1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2012 by Delphix. All rights reserved. 27 */ 28 29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 /* 33 * University Copyright- Copyright (c) 1982, 1986, 1988 34 * The Regents of the University of California 35 * All Rights Reserved 36 * 37 * University Acknowledgment- Portions of this document are derived from 38 * software developed by the University of California, Berkeley, and its 39 * contributors. 40 */ 41 42 43 #include <sys/types.h> 44 #include <sys/t_lock.h> 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/buf.h> 48 #include <sys/conf.h> 49 #include <sys/cred.h> 50 #include <sys/kmem.h> 51 #include <sys/sysmacros.h> 52 #include <sys/vfs.h> 53 #include <sys/vfs_opreg.h> 54 #include <sys/vnode.h> 55 #include <sys/fs/snode.h> 56 #include <sys/fs/fifonode.h> 57 #include <sys/debug.h> 58 #include <sys/errno.h> 59 #include <sys/time.h> 60 #include <sys/file.h> 61 #include <sys/open.h> 62 #include <sys/user.h> 63 #include <sys/termios.h> 64 #include <sys/stream.h> 65 #include <sys/strsubr.h> 66 #include <sys/autoconf.h> 67 #include <sys/esunddi.h> 68 #include <sys/flock.h> 69 #include <sys/modctl.h> 70 71 struct vfs spec_vfs; 72 static dev_t specdev; 73 struct kmem_cache *snode_cache; 74 int spec_debug = 0; 75 76 static struct snode *sfind(dev_t, vtype_t, struct vnode *); 77 static struct vnode *get_cvp(dev_t, vtype_t, struct snode *, int *); 78 static void sinsert(struct snode *); 79 80 struct vnode * 81 specvp_devfs( 82 struct vnode *realvp, 83 dev_t dev, 84 vtype_t vtyp, 85 struct cred *cr, 86 dev_info_t *dip) 87 { 88 struct vnode *vp; 89 90 ASSERT(realvp && dip); 91 vp = specvp(realvp, dev, vtyp, cr); 92 ASSERT(vp); 93 94 /* associate a dip hold with the common snode's s_dip pointer */ 95 spec_assoc_vp_with_devi(vp, dip); 96 return (vp); 97 } 98 99 /* 100 * Return a shadow special vnode for the given dev. 101 * If no snode exists for this dev create one and put it 102 * in a table hashed by <dev, realvp>. If the snode for 103 * this dev is already in the table return it (ref count is 104 * incremented by sfind). The snode will be flushed from the 105 * table when spec_inactive calls sdelete. 106 * 107 * The fsid is inherited from the real vnode so that clones 108 * can be found. 109 * 110 */ 111 struct vnode * 112 specvp( 113 struct vnode *vp, 114 dev_t dev, 115 vtype_t type, 116 struct cred *cr) 117 { 118 struct snode *sp; 119 struct snode *nsp; 120 struct snode *csp; 121 struct vnode *svp; 122 struct vattr va; 123 int rc; 124 int used_csp = 0; /* Did we use pre-allocated csp */ 125 126 if (vp == NULL) 127 return (NULL); 128 if (vp->v_type == VFIFO) 129 return (fifovp(vp, cr)); 130 131 ASSERT(vp->v_type == type); 132 ASSERT(vp->v_rdev == dev); 133 134 /* 135 * Pre-allocate snodes before holding any locks in case we block 136 */ 137 nsp = kmem_cache_alloc(snode_cache, KM_SLEEP); 138 csp = kmem_cache_alloc(snode_cache, KM_SLEEP); 139 140 /* 141 * Get the time attributes outside of the stable lock since 142 * this operation may block. Unfortunately, it may not have 143 * been required if the snode is in the cache. 144 */ 145 va.va_mask = AT_FSID | AT_TIMES; 146 rc = VOP_GETATTR(vp, &va, 0, cr, NULL); /* XXX may block! */ 147 148 mutex_enter(&stable_lock); 149 if ((sp = sfind(dev, type, vp)) == NULL) { 150 struct vnode *cvp; 151 152 sp = nsp; /* Use pre-allocated snode */ 153 svp = STOV(sp); 154 155 sp->s_realvp = vp; 156 VN_HOLD(vp); 157 sp->s_commonvp = NULL; 158 sp->s_dev = dev; 159 sp->s_dip = NULL; 160 sp->s_nextr = NULL; 161 sp->s_list = NULL; 162 sp->s_plcy = NULL; 163 sp->s_size = 0; 164 sp->s_flag = 0; 165 if (rc == 0) { 166 /* 167 * Set times in snode to those in the vnode. 168 */ 169 sp->s_fsid = va.va_fsid; 170 sp->s_atime = va.va_atime.tv_sec; 171 sp->s_mtime = va.va_mtime.tv_sec; 172 sp->s_ctime = va.va_ctime.tv_sec; 173 } else { 174 sp->s_fsid = specdev; 175 sp->s_atime = 0; 176 sp->s_mtime = 0; 177 sp->s_ctime = 0; 178 } 179 sp->s_count = 0; 180 sp->s_mapcnt = 0; 181 182 vn_reinit(svp); 183 svp->v_flag = (vp->v_flag & VROOT); 184 svp->v_vfsp = vp->v_vfsp; 185 VFS_HOLD(svp->v_vfsp); 186 svp->v_type = type; 187 svp->v_rdev = dev; 188 (void) vn_copypath(vp, svp); 189 if (type == VBLK || type == VCHR) { 190 cvp = get_cvp(dev, type, csp, &used_csp); 191 svp->v_stream = cvp->v_stream; 192 193 sp->s_commonvp = cvp; 194 } 195 vn_exists(svp); 196 sinsert(sp); 197 mutex_exit(&stable_lock); 198 if (used_csp == 0) { 199 /* Didn't use pre-allocated snode so free it */ 200 kmem_cache_free(snode_cache, csp); 201 } 202 } else { 203 mutex_exit(&stable_lock); 204 /* free unused snode memory */ 205 kmem_cache_free(snode_cache, nsp); 206 kmem_cache_free(snode_cache, csp); 207 } 208 return (STOV(sp)); 209 } 210 211 /* 212 * Return a special vnode for the given dev; no vnode is supplied 213 * for it to shadow. Always create a new snode and put it in the 214 * table hashed by <dev, NULL>. The snode will be flushed from the 215 * table when spec_inactive() calls sdelete(). The association of 216 * this node with a attached instance of hardware is not made until 217 * spec_open time. 218 * 219 * N.B. Assumes caller takes on responsibility of making sure no one 220 * else is creating a snode for (dev, type) at this time. 221 */ 222 struct vnode * 223 makespecvp(dev_t dev, vtype_t type) 224 { 225 struct snode *sp; 226 struct vnode *svp, *cvp; 227 time_t now; 228 229 sp = kmem_cache_alloc(snode_cache, KM_SLEEP); 230 svp = STOV(sp); 231 cvp = commonvp(dev, type); 232 now = gethrestime_sec(); 233 234 sp->s_realvp = NULL; 235 sp->s_commonvp = cvp; 236 sp->s_dev = dev; 237 sp->s_dip = NULL; 238 sp->s_nextr = NULL; 239 sp->s_list = NULL; 240 sp->s_plcy = NULL; 241 sp->s_size = 0; 242 sp->s_flag = 0; 243 sp->s_fsid = specdev; 244 sp->s_atime = now; 245 sp->s_mtime = now; 246 sp->s_ctime = now; 247 sp->s_count = 0; 248 sp->s_mapcnt = 0; 249 250 vn_reinit(svp); 251 svp->v_vfsp = &spec_vfs; 252 svp->v_stream = cvp->v_stream; 253 svp->v_type = type; 254 svp->v_rdev = dev; 255 256 vn_exists(svp); 257 mutex_enter(&stable_lock); 258 sinsert(sp); 259 mutex_exit(&stable_lock); 260 261 return (svp); 262 } 263 264 265 /* 266 * This function is called from spec_assoc_vp_with_devi(). That function 267 * associates a "new" dip with a common snode, releasing (any) old dip 268 * in the process. This function (spec_assoc_fence()) looks at the "new dip" 269 * and determines whether the snode should be fenced of or not. As the table 270 * below indicates, the value of old-dip is a don't care for all cases. 271 * 272 * old-dip new-dip common-snode 273 * ========================================= 274 * Don't care NULL unfence 275 * Don't care retired fence 276 * Don't care not-retired unfence 277 * 278 * Since old-dip value is a "don't care", it is not passed into this function. 279 */ 280 static void 281 spec_assoc_fence(dev_info_t *ndip, vnode_t *vp) 282 { 283 int fence; 284 struct snode *csp; 285 286 ASSERT(vp); 287 ASSERT(vn_matchops(vp, spec_getvnodeops())); 288 289 fence = 0; 290 if (ndip != NULL) { 291 mutex_enter(&DEVI(ndip)->devi_lock); 292 if (DEVI(ndip)->devi_flags & DEVI_RETIRED) 293 fence = 1; 294 mutex_exit(&DEVI(ndip)->devi_lock); 295 } 296 297 csp = VTOCS(vp); 298 ASSERT(csp); 299 300 /* SFENCED flag only set on common snode */ 301 mutex_enter(&csp->s_lock); 302 if (fence) 303 csp->s_flag |= SFENCED; 304 else 305 csp->s_flag &= ~SFENCED; 306 mutex_exit(&csp->s_lock); 307 308 FENDBG((CE_NOTE, "%sfenced common snode (%p) for new dip=%p", 309 fence ? "" : "un", (void *)csp, (void *)ndip)); 310 } 311 312 /* 313 * Associate the common snode with a devinfo node. This is called from: 314 * 315 * 1) specvp_devfs to associate a specfs node with the dip attached 316 * by devfs. 317 * 318 * 2) spec_open after path reconstruction and attach. 319 * 320 * 3) From dacf processing to associate a makespecvp node with 321 * the dip that dacf postattach processing is being performed on. 322 * This association is made prior to open to avoid recursion issues. 323 * 324 * 4) From ddi_assoc_queue_with_devi to change vnode association as part of 325 * DL_ATTACH/DL_DETACH processing (SDIPSET already set). The call 326 * from ddi_assoc_queue_with_devi may specify a NULL dip. 327 * 328 * We put an extra hold on the devinfo node passed in as we establish it as 329 * the new s_dip pointer. Any hold associated with the prior s_dip pointer 330 * is released. The new hold will stay active until another call to 331 * spec_assoc_vp_with_devi or until the common snode is destroyed by 332 * spec_inactive after the last VN_RELE of the common node. This devinfo hold 333 * transfers across a clone open except in the clone_dev case, where the clone 334 * driver is no longer required after open. 335 * 336 * When SDIPSET is set and s_dip is NULL, the vnode has an association with 337 * the driver even though there is currently no association with a specific 338 * hardware instance. 339 */ 340 void 341 spec_assoc_vp_with_devi(struct vnode *vp, dev_info_t *dip) 342 { 343 struct snode *csp; 344 dev_info_t *olddip; 345 346 ASSERT(vp); 347 348 /* 349 * Don't establish a NULL association for a vnode associated with the 350 * clone driver. The qassociate(, -1) call from a streams driver's 351 * open implementation to indicate support for qassociate has the 352 * side-effect of this type of spec_assoc_vp_with_devi call. This 353 * call should not change the the association of the pre-clone 354 * vnode associated with the clone driver, the post-clone newdev 355 * association will be established later by spec_clone(). 356 */ 357 if ((dip == NULL) && (getmajor(vp->v_rdev) == clone_major)) 358 return; 359 360 /* hold the new */ 361 if (dip) 362 e_ddi_hold_devi(dip); 363 364 csp = VTOS(VTOS(vp)->s_commonvp); 365 mutex_enter(&csp->s_lock); 366 olddip = csp->s_dip; 367 csp->s_dip = dip; 368 csp->s_flag |= SDIPSET; 369 370 /* If association changes then invalidate cached size */ 371 if (olddip != dip) 372 csp->s_flag &= ~SSIZEVALID; 373 mutex_exit(&csp->s_lock); 374 375 spec_assoc_fence(dip, vp); 376 377 /* release the old */ 378 if (olddip) 379 ddi_release_devi(olddip); 380 } 381 382 /* 383 * Return the held dip associated with the specified snode. 384 */ 385 dev_info_t * 386 spec_hold_devi_by_vp(struct vnode *vp) 387 { 388 struct snode *csp; 389 dev_info_t *dip; 390 391 ASSERT(vn_matchops(vp, spec_getvnodeops())); 392 393 csp = VTOS(VTOS(vp)->s_commonvp); 394 dip = csp->s_dip; 395 if (dip) 396 e_ddi_hold_devi(dip); 397 return (dip); 398 } 399 400 /* 401 * Find a special vnode that refers to the given device 402 * of the given type. Never return a "common" vnode. 403 * Return NULL if a special vnode does not exist. 404 * HOLD the vnode before returning it. 405 */ 406 struct vnode * 407 specfind(dev_t dev, vtype_t type) 408 { 409 struct snode *st; 410 struct vnode *nvp; 411 412 mutex_enter(&stable_lock); 413 st = stable[STABLEHASH(dev)]; 414 while (st != NULL) { 415 if (st->s_dev == dev) { 416 nvp = STOV(st); 417 if (nvp->v_type == type && st->s_commonvp != nvp) { 418 VN_HOLD(nvp); 419 mutex_exit(&stable_lock); 420 return (nvp); 421 } 422 } 423 st = st->s_next; 424 } 425 mutex_exit(&stable_lock); 426 return (NULL); 427 } 428 429 /* 430 * Loop through the snode cache looking for snodes referencing dip. 431 * 432 * This function determines if a devinfo node is "BUSY" from the perspective 433 * of having an active vnode associated with the device, which represents a 434 * dependency on the device's services. This function is needed because a 435 * devinfo node can have a non-zero devi_ref and still NOT be "BUSY" when, 436 * for instance, the framework is manipulating the node (has an open 437 * ndi_hold_devi). 438 * 439 * Returns: 440 * DEVI_REFERENCED - if dip is referenced 441 * DEVI_NOT_REFERENCED - if dip is not referenced 442 */ 443 int 444 devi_stillreferenced(dev_info_t *dip) 445 { 446 struct snode *sp; 447 int i; 448 449 /* if no hold then there can't be an snode with s_dip == dip */ 450 if (e_ddi_devi_holdcnt(dip) == 0) 451 return (DEVI_NOT_REFERENCED); 452 453 mutex_enter(&stable_lock); 454 for (i = 0; i < STABLESIZE; i++) { 455 for (sp = stable[i]; sp != NULL; sp = sp->s_next) { 456 if (sp->s_dip == dip) { 457 mutex_exit(&stable_lock); 458 return (DEVI_REFERENCED); 459 } 460 } 461 } 462 mutex_exit(&stable_lock); 463 return (DEVI_NOT_REFERENCED); 464 } 465 466 /* 467 * Given an snode, returns the open count and the dip 468 * associated with that snode 469 * Assumes the caller holds the appropriate locks 470 * to prevent snode and/or dip from going away. 471 * Returns: 472 * -1 No associated dip 473 * >= 0 Number of opens. 474 */ 475 int 476 spec_devi_open_count(struct snode *sp, dev_info_t **dipp) 477 { 478 dev_info_t *dip; 479 uint_t count; 480 struct vnode *vp; 481 482 ASSERT(sp); 483 ASSERT(dipp); 484 485 vp = STOV(sp); 486 487 *dipp = NULL; 488 489 /* 490 * We are only interested in common snodes. Only common snodes 491 * get their s_count fields bumped up on opens. 492 */ 493 if (sp->s_commonvp != vp || (dip = sp->s_dip) == NULL) 494 return (-1); 495 496 mutex_enter(&sp->s_lock); 497 count = sp->s_count + sp->s_mapcnt; 498 if (sp->s_flag & SLOCKED) 499 count++; 500 mutex_exit(&sp->s_lock); 501 502 *dipp = dip; 503 504 return (count); 505 } 506 507 /* 508 * Given a device vnode, return the common 509 * vnode associated with it. 510 */ 511 struct vnode * 512 common_specvp(struct vnode *vp) 513 { 514 struct snode *sp; 515 516 if ((vp->v_type != VBLK) && (vp->v_type != VCHR) || 517 !vn_matchops(vp, spec_getvnodeops())) 518 return (vp); 519 sp = VTOS(vp); 520 return (sp->s_commonvp); 521 } 522 523 /* 524 * Returns a special vnode for the given dev. The vnode is the 525 * one which is "common" to all the snodes which represent the 526 * same device. 527 * Similar to commonvp() but doesn't acquire the stable_lock, and 528 * may use a pre-allocated snode provided by caller. 529 */ 530 static struct vnode * 531 get_cvp( 532 dev_t dev, 533 vtype_t type, 534 struct snode *nsp, /* pre-allocated snode */ 535 int *used_nsp) /* flag indicating if we use nsp */ 536 { 537 struct snode *sp; 538 struct vnode *svp; 539 540 ASSERT(MUTEX_HELD(&stable_lock)); 541 if ((sp = sfind(dev, type, NULL)) == NULL) { 542 sp = nsp; /* Use pre-allocated snode */ 543 *used_nsp = 1; /* return value */ 544 svp = STOV(sp); 545 546 sp->s_realvp = NULL; 547 sp->s_commonvp = svp; /* points to itself */ 548 sp->s_dev = dev; 549 sp->s_dip = NULL; 550 sp->s_nextr = NULL; 551 sp->s_list = NULL; 552 sp->s_plcy = NULL; 553 sp->s_size = UNKNOWN_SIZE; 554 sp->s_flag = 0; 555 sp->s_fsid = specdev; 556 sp->s_atime = 0; 557 sp->s_mtime = 0; 558 sp->s_ctime = 0; 559 sp->s_count = 0; 560 sp->s_mapcnt = 0; 561 562 vn_reinit(svp); 563 svp->v_vfsp = &spec_vfs; 564 svp->v_type = type; 565 svp->v_rdev = dev; 566 vn_exists(svp); 567 sinsert(sp); 568 } else 569 *used_nsp = 0; 570 return (STOV(sp)); 571 } 572 573 /* 574 * Returns a special vnode for the given dev. The vnode is the 575 * one which is "common" to all the snodes which represent the 576 * same device. For use ONLY by SPECFS. 577 */ 578 struct vnode * 579 commonvp(dev_t dev, vtype_t type) 580 { 581 struct snode *sp, *nsp; 582 struct vnode *svp; 583 584 /* Pre-allocate snode in case we might block */ 585 nsp = kmem_cache_alloc(snode_cache, KM_SLEEP); 586 587 mutex_enter(&stable_lock); 588 if ((sp = sfind(dev, type, NULL)) == NULL) { 589 sp = nsp; /* Use pre-alloced snode */ 590 svp = STOV(sp); 591 592 sp->s_realvp = NULL; 593 sp->s_commonvp = svp; /* points to itself */ 594 sp->s_dev = dev; 595 sp->s_dip = NULL; 596 sp->s_nextr = NULL; 597 sp->s_list = NULL; 598 sp->s_plcy = NULL; 599 sp->s_size = UNKNOWN_SIZE; 600 sp->s_flag = 0; 601 sp->s_fsid = specdev; 602 sp->s_atime = 0; 603 sp->s_mtime = 0; 604 sp->s_ctime = 0; 605 sp->s_count = 0; 606 sp->s_mapcnt = 0; 607 608 vn_reinit(svp); 609 svp->v_vfsp = &spec_vfs; 610 svp->v_type = type; 611 svp->v_rdev = dev; 612 vn_exists(svp); 613 sinsert(sp); 614 mutex_exit(&stable_lock); 615 } else { 616 mutex_exit(&stable_lock); 617 /* Didn't need the pre-allocated snode */ 618 kmem_cache_free(snode_cache, nsp); 619 } 620 return (STOV(sp)); 621 } 622 623 /* 624 * Snode lookup stuff. 625 * These routines maintain a table of snodes hashed by dev so 626 * that the snode for an dev can be found if it already exists. 627 */ 628 struct snode *stable[STABLESIZE]; 629 int stablesz = STABLESIZE; 630 kmutex_t stable_lock; 631 632 /* 633 * Put a snode in the table. 634 */ 635 static void 636 sinsert(struct snode *sp) 637 { 638 ASSERT(MUTEX_HELD(&stable_lock)); 639 sp->s_next = stable[STABLEHASH(sp->s_dev)]; 640 stable[STABLEHASH(sp->s_dev)] = sp; 641 } 642 643 /* 644 * Remove an snode from the hash table. 645 * The realvp is not released here because spec_inactive() still 646 * needs it to do a spec_fsync(). 647 */ 648 void 649 sdelete(struct snode *sp) 650 { 651 struct snode *st; 652 struct snode *stprev = NULL; 653 654 ASSERT(MUTEX_HELD(&stable_lock)); 655 st = stable[STABLEHASH(sp->s_dev)]; 656 while (st != NULL) { 657 if (st == sp) { 658 if (stprev == NULL) 659 stable[STABLEHASH(sp->s_dev)] = st->s_next; 660 else 661 stprev->s_next = st->s_next; 662 break; 663 } 664 stprev = st; 665 st = st->s_next; 666 } 667 } 668 669 /* 670 * Lookup an snode by <dev, type, vp>. 671 * ONLY looks for snodes with non-NULL s_realvp members and 672 * common snodes (with s_commonvp pointing to its vnode). 673 * 674 * If vp is NULL, only return commonvp. Otherwise return 675 * shadow vp with both shadow and common vp's VN_HELD. 676 */ 677 static struct snode * 678 sfind( 679 dev_t dev, 680 vtype_t type, 681 struct vnode *vp) 682 { 683 struct snode *st; 684 struct vnode *svp; 685 686 ASSERT(MUTEX_HELD(&stable_lock)); 687 st = stable[STABLEHASH(dev)]; 688 while (st != NULL) { 689 svp = STOV(st); 690 if (st->s_dev == dev && svp->v_type == type && 691 VN_CMP(st->s_realvp, vp) && 692 (vp != NULL || st->s_commonvp == svp) && 693 (vp == NULL || st->s_realvp->v_vfsp == vp->v_vfsp)) { 694 VN_HOLD(svp); 695 return (st); 696 } 697 st = st->s_next; 698 } 699 return (NULL); 700 } 701 702 /* 703 * Mark the accessed, updated, or changed times in an snode 704 * with the current time. 705 */ 706 void 707 smark(struct snode *sp, int flag) 708 { 709 time_t now = gethrestime_sec(); 710 711 /* check for change to avoid unnecessary locking */ 712 ASSERT((flag & ~(SACC|SUPD|SCHG)) == 0); 713 if (((flag & sp->s_flag) != flag) || 714 ((flag & SACC) && (sp->s_atime != now)) || 715 ((flag & SUPD) && (sp->s_mtime != now)) || 716 ((flag & SCHG) && (sp->s_ctime != now))) { 717 /* lock and update */ 718 mutex_enter(&sp->s_lock); 719 sp->s_flag |= flag; 720 if (flag & SACC) 721 sp->s_atime = now; 722 if (flag & SUPD) 723 sp->s_mtime = now; 724 if (flag & SCHG) 725 sp->s_ctime = now; 726 mutex_exit(&sp->s_lock); 727 } 728 } 729 730 /* 731 * Return the maximum file offset permitted for this device. 732 * -1 means unrestricted. SLOFFSET is associated with D_64BIT. 733 * 734 * On a 32-bit kernel this will limit: 735 * o D_64BIT devices to SPEC_MAXOFFSET_T. 736 * o non-D_64BIT character drivers to a 32-bit offset (MAXOFF_T). 737 */ 738 offset_t 739 spec_maxoffset(struct vnode *vp) 740 { 741 struct snode *sp = VTOS(vp); 742 struct snode *csp = VTOS(sp->s_commonvp); 743 744 if (vp->v_stream) 745 return ((offset_t)-1); 746 else if (csp->s_flag & SANYOFFSET) /* D_U64BIT */ 747 return ((offset_t)-1); 748 #ifdef _ILP32 749 if (csp->s_flag & SLOFFSET) /* D_64BIT */ 750 return (SPEC_MAXOFFSET_T); 751 #endif /* _ILP32 */ 752 return (MAXOFF_T); 753 } 754 755 /*ARGSUSED*/ 756 static int 757 snode_constructor(void *buf, void *cdrarg, int kmflags) 758 { 759 struct snode *sp = buf; 760 struct vnode *vp; 761 762 vp = sp->s_vnode = vn_alloc(kmflags); 763 if (vp == NULL) { 764 return (-1); 765 } 766 vn_setops(vp, spec_getvnodeops()); 767 vp->v_data = sp; 768 769 mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL); 770 cv_init(&sp->s_cv, NULL, CV_DEFAULT, NULL); 771 return (0); 772 } 773 774 /*ARGSUSED1*/ 775 static void 776 snode_destructor(void *buf, void *cdrarg) 777 { 778 struct snode *sp = buf; 779 struct vnode *vp = STOV(sp); 780 781 mutex_destroy(&sp->s_lock); 782 cv_destroy(&sp->s_cv); 783 784 vn_free(vp); 785 } 786 787 788 int 789 specinit(int fstype, char *name) 790 { 791 static const fs_operation_def_t spec_vfsops_template[] = { 792 VFSNAME_SYNC, { .vfs_sync = spec_sync }, 793 NULL, NULL 794 }; 795 extern struct vnodeops *spec_vnodeops; 796 extern const fs_operation_def_t spec_vnodeops_template[]; 797 struct vfsops *spec_vfsops; 798 int error; 799 dev_t dev; 800 801 /* 802 * Associate vfs and vnode operations. 803 */ 804 error = vfs_setfsops(fstype, spec_vfsops_template, &spec_vfsops); 805 if (error != 0) { 806 cmn_err(CE_WARN, "specinit: bad vfs ops template"); 807 return (error); 808 } 809 810 error = vn_make_ops(name, spec_vnodeops_template, &spec_vnodeops); 811 if (error != 0) { 812 (void) vfs_freevfsops_by_type(fstype); 813 cmn_err(CE_WARN, "specinit: bad vnode ops template"); 814 return (error); 815 } 816 817 mutex_init(&stable_lock, NULL, MUTEX_DEFAULT, NULL); 818 mutex_init(&spec_syncbusy, NULL, MUTEX_DEFAULT, NULL); 819 820 /* 821 * Create snode cache 822 */ 823 snode_cache = kmem_cache_create("snode_cache", sizeof (struct snode), 824 0, snode_constructor, snode_destructor, NULL, NULL, NULL, 0); 825 826 /* 827 * Associate vfs operations with spec_vfs 828 */ 829 VFS_INIT(&spec_vfs, spec_vfsops, (caddr_t)NULL); 830 if ((dev = getudev()) == -1) 831 dev = 0; 832 specdev = makedevice(dev, 0); 833 return (0); 834 } 835 836 int 837 device_close(struct vnode *vp, int flag, struct cred *cr) 838 { 839 struct snode *sp = VTOS(vp); 840 enum vtype type = vp->v_type; 841 struct vnode *cvp; 842 dev_t dev; 843 int error; 844 845 dev = sp->s_dev; 846 cvp = sp->s_commonvp; 847 848 switch (type) { 849 850 case VCHR: 851 if (vp->v_stream) { 852 if (cvp->v_stream != NULL) 853 error = strclose(cvp, flag, cr); 854 vp->v_stream = NULL; 855 } else 856 error = dev_close(dev, flag, OTYP_CHR, cr); 857 break; 858 859 case VBLK: 860 /* 861 * On last close a block device we must 862 * invalidate any in-core blocks so that we 863 * can, for example, change floppy disks. 864 */ 865 (void) spec_putpage(cvp, (offset_t)0, 866 (size_t)0, B_INVAL|B_FORCE, cr, NULL); 867 bflush(dev); 868 binval(dev); 869 error = dev_close(dev, flag, OTYP_BLK, cr); 870 break; 871 default: 872 panic("device_close: not a device"); 873 /*NOTREACHED*/ 874 } 875 876 return (error); 877 } 878 879 struct vnode * 880 makectty(vnode_t *ovp) 881 { 882 vnode_t *vp; 883 884 if (vp = makespecvp(ovp->v_rdev, VCHR)) { 885 struct snode *sp; 886 struct snode *csp; 887 struct vnode *cvp; 888 889 sp = VTOS(vp); 890 cvp = sp->s_commonvp; 891 csp = VTOS(cvp); 892 mutex_enter(&csp->s_lock); 893 csp->s_count++; 894 mutex_exit(&csp->s_lock); 895 } 896 897 return (vp); 898 } 899 900 void 901 spec_snode_walk(int (*callback)(struct snode *sp, void *arg), void *arg) 902 { 903 struct snode *sp; 904 int i; 905 906 ASSERT(callback); 907 908 mutex_enter(&stable_lock); 909 for (i = 0; i < STABLESIZE; i++) { 910 for (sp = stable[i]; sp; sp = sp->s_next) { 911 if (callback(sp, arg) != DDI_WALK_CONTINUE) 912 goto out; 913 } 914 } 915 out: 916 mutex_exit(&stable_lock); 917 } 918 919 int 920 spec_is_clone(vnode_t *vp) 921 { 922 struct snode *sp; 923 924 if (vn_matchops(vp, spec_getvnodeops())) { 925 sp = VTOS(vp); 926 return ((sp->s_flag & SCLONE) ? 1 : 0); 927 } 928 929 return (0); 930 } 931 932 int 933 spec_is_selfclone(vnode_t *vp) 934 { 935 struct snode *sp; 936 937 if (vn_matchops(vp, spec_getvnodeops())) { 938 sp = VTOS(vp); 939 return ((sp->s_flag & SSELFCLONE) ? 1 : 0); 940 } 941 942 return (0); 943 } 944 945 /* 946 * We may be invoked with a NULL vp in which case we fence off 947 * all snodes associated with dip 948 */ 949 int 950 spec_fence_snode(dev_info_t *dip, struct vnode *vp) 951 { 952 struct snode *sp; 953 struct snode *csp; 954 int retired; 955 int i; 956 char *path; 957 int emitted; 958 959 ASSERT(dip); 960 961 retired = 0; 962 mutex_enter(&DEVI(dip)->devi_lock); 963 if (DEVI(dip)->devi_flags & DEVI_RETIRED) 964 retired = 1; 965 mutex_exit(&DEVI(dip)->devi_lock); 966 967 if (!retired) 968 return (0); 969 970 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 971 (void) ddi_pathname(dip, path); 972 973 974 if (vp != NULL) { 975 ASSERT(vn_matchops(vp, spec_getvnodeops())); 976 csp = VTOCS(vp); 977 ASSERT(csp); 978 mutex_enter(&csp->s_lock); 979 csp->s_flag |= SFENCED; 980 mutex_exit(&csp->s_lock); 981 FENDBG((CE_NOTE, "fenced off snode(%p) for dip: %s", 982 (void *)csp, path)); 983 kmem_free(path, MAXPATHLEN); 984 return (0); 985 } 986 987 emitted = 0; 988 mutex_enter(&stable_lock); 989 for (i = 0; i < STABLESIZE; i++) { 990 for (sp = stable[i]; sp != NULL; sp = sp->s_next) { 991 ASSERT(sp->s_commonvp); 992 csp = VTOS(sp->s_commonvp); 993 if (csp->s_dip == dip) { 994 /* fence off the common snode */ 995 mutex_enter(&csp->s_lock); 996 csp->s_flag |= SFENCED; 997 mutex_exit(&csp->s_lock); 998 if (!emitted) { 999 FENDBG((CE_NOTE, "fenced 1 of N")); 1000 emitted++; 1001 } 1002 } 1003 } 1004 } 1005 mutex_exit(&stable_lock); 1006 1007 FENDBG((CE_NOTE, "fenced off all snodes for dip: %s", path)); 1008 kmem_free(path, MAXPATHLEN); 1009 1010 return (0); 1011 } 1012 1013 1014 int 1015 spec_unfence_snode(dev_info_t *dip) 1016 { 1017 struct snode *sp; 1018 struct snode *csp; 1019 int i; 1020 char *path; 1021 int emitted; 1022 1023 ASSERT(dip); 1024 1025 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1026 (void) ddi_pathname(dip, path); 1027 1028 emitted = 0; 1029 mutex_enter(&stable_lock); 1030 for (i = 0; i < STABLESIZE; i++) { 1031 for (sp = stable[i]; sp != NULL; sp = sp->s_next) { 1032 ASSERT(sp->s_commonvp); 1033 csp = VTOS(sp->s_commonvp); 1034 ASSERT(csp); 1035 if (csp->s_dip == dip) { 1036 /* unfence the common snode */ 1037 mutex_enter(&csp->s_lock); 1038 csp->s_flag &= ~SFENCED; 1039 mutex_exit(&csp->s_lock); 1040 if (!emitted) { 1041 FENDBG((CE_NOTE, "unfenced 1 of N")); 1042 emitted++; 1043 } 1044 } 1045 } 1046 } 1047 mutex_exit(&stable_lock); 1048 1049 FENDBG((CE_NOTE, "unfenced all snodes for dip: %s", path)); 1050 kmem_free(path, MAXPATHLEN); 1051 1052 return (0); 1053 } 1054 1055 void 1056 spec_size_invalidate(dev_t dev, vtype_t type) 1057 { 1058 1059 struct snode *csp; 1060 1061 mutex_enter(&stable_lock); 1062 if ((csp = sfind(dev, type, NULL)) != NULL) { 1063 mutex_enter(&csp->s_lock); 1064 csp->s_flag &= ~SSIZEVALID; 1065 VN_RELE_ASYNC(STOV(csp), system_taskq); 1066 mutex_exit(&csp->s_lock); 1067 } 1068 mutex_exit(&stable_lock); 1069 } 1070