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 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * 25 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 26 * All rights reserved. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/thread.h> 32 #include <sys/t_lock.h> 33 #include <sys/time.h> 34 #include <sys/vnode.h> 35 #include <sys/vfs.h> 36 #include <sys/errno.h> 37 #include <sys/buf.h> 38 #include <sys/stat.h> 39 #include <sys/cred.h> 40 #include <sys/kmem.h> 41 #include <sys/debug.h> 42 #include <sys/vmsystm.h> 43 #include <sys/flock.h> 44 #include <sys/share.h> 45 #include <sys/cmn_err.h> 46 #include <sys/tiuser.h> 47 #include <sys/sysmacros.h> 48 #include <sys/callb.h> 49 #include <sys/acl.h> 50 #include <sys/kstat.h> 51 #include <sys/signal.h> 52 #include <sys/list.h> 53 #include <sys/zone.h> 54 55 #include <netsmb/smb.h> 56 #include <netsmb/smb_conn.h> 57 #include <netsmb/smb_subr.h> 58 59 #include <smbfs/smbfs.h> 60 #include <smbfs/smbfs_node.h> 61 #include <smbfs/smbfs_subr.h> 62 63 #include <vm/hat.h> 64 #include <vm/as.h> 65 #include <vm/page.h> 66 #include <vm/pvn.h> 67 #include <vm/seg.h> 68 #include <vm/seg_map.h> 69 #include <vm/seg_vn.h> 70 71 #define ATTRCACHE_VALID(vp) (gethrtime() < VTOSMB(vp)->r_attrtime) 72 73 static int smbfs_getattr_cache(vnode_t *, smbfattr_t *); 74 static void smbfattr_to_vattr(vnode_t *, smbfattr_t *, vattr_t *); 75 static void smbfattr_to_xvattr(smbfattr_t *, vattr_t *); 76 static int smbfs_getattr_otw(vnode_t *, struct smbfattr *, cred_t *); 77 78 79 /* 80 * The following code provide zone support in order to perform an action 81 * for each smbfs mount in a zone. This is also where we would add 82 * per-zone globals and kernel threads for the smbfs module (since 83 * they must be terminated by the shutdown callback). 84 */ 85 86 struct smi_globals { 87 kmutex_t smg_lock; /* lock protecting smg_list */ 88 list_t smg_list; /* list of SMBFS mounts in zone */ 89 boolean_t smg_destructor_called; 90 }; 91 typedef struct smi_globals smi_globals_t; 92 93 static zone_key_t smi_list_key; 94 95 /* 96 * Attributes caching: 97 * 98 * Attributes are cached in the smbnode in struct vattr form. 99 * There is a time associated with the cached attributes (r_attrtime) 100 * which tells whether the attributes are valid. The time is initialized 101 * to the difference between current time and the modify time of the vnode 102 * when new attributes are cached. This allows the attributes for 103 * files that have changed recently to be timed out sooner than for files 104 * that have not changed for a long time. There are minimum and maximum 105 * timeout values that can be set per mount point. 106 */ 107 108 /* 109 * Helper for _validate_caches 110 */ 111 int 112 smbfs_waitfor_purge_complete(vnode_t *vp) 113 { 114 smbnode_t *np; 115 k_sigset_t smask; 116 117 np = VTOSMB(vp); 118 if (np->r_serial != NULL && np->r_serial != curthread) { 119 mutex_enter(&np->r_statelock); 120 sigintr(&smask, VTOSMI(vp)->smi_flags & SMI_INT); 121 while (np->r_serial != NULL) { 122 if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) { 123 sigunintr(&smask); 124 mutex_exit(&np->r_statelock); 125 return (EINTR); 126 } 127 } 128 sigunintr(&smask); 129 mutex_exit(&np->r_statelock); 130 } 131 return (0); 132 } 133 134 /* 135 * Validate caches by checking cached attributes. If the cached 136 * attributes have timed out, then get new attributes from the server. 137 * As a side affect, this will do cache invalidation if the attributes 138 * have changed. 139 * 140 * If the attributes have not timed out and if there is a cache 141 * invalidation being done by some other thread, then wait until that 142 * thread has completed the cache invalidation. 143 */ 144 int 145 smbfs_validate_caches( 146 struct vnode *vp, 147 cred_t *cr) 148 { 149 struct smbfattr fa; 150 int error; 151 152 if (ATTRCACHE_VALID(vp)) { 153 error = smbfs_waitfor_purge_complete(vp); 154 if (error) 155 return (error); 156 return (0); 157 } 158 159 return (smbfs_getattr_otw(vp, &fa, cr)); 160 } 161 162 /* 163 * Purge all of the various data caches. 164 * 165 * Here NFS also had a flags arg to control what gets flushed. 166 * We only have the page cache, so no flags arg. 167 */ 168 /* ARGSUSED */ 169 void 170 smbfs_purge_caches(struct vnode *vp, cred_t *cr) 171 { 172 173 /* 174 * Here NFS has: Purge the DNLC for this vp, 175 * Clear any readdir state bits, 176 * the readlink response cache, ... 177 */ 178 179 /* 180 * Flush the page cache. 181 */ 182 if (vn_has_cached_data(vp)) { 183 (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL); 184 } 185 186 /* 187 * Here NFS has: Flush the readdir response cache. 188 * No readdir cache in smbfs. 189 */ 190 } 191 192 /* 193 * Here NFS has: 194 * nfs_purge_rddir_cache() 195 * nfs3_cache_post_op_attr() 196 * nfs3_cache_post_op_vattr() 197 * nfs3_cache_wcc_data() 198 */ 199 200 /* 201 * Check the attribute cache to see if the new attributes match 202 * those cached. If they do, the various `data' caches are 203 * considered to be good. Otherwise, purge the cached data. 204 */ 205 static void 206 smbfs_cache_check( 207 struct vnode *vp, 208 struct smbfattr *fap, 209 cred_t *cr) 210 { 211 smbnode_t *np; 212 int purge_data = 0; 213 int purge_acl = 0; 214 215 np = VTOSMB(vp); 216 mutex_enter(&np->r_statelock); 217 218 /* 219 * Compare with NFS macro: CACHE_VALID 220 * If the mtime or size has changed, 221 * purge cached data. 222 */ 223 if (np->r_attr.fa_mtime.tv_sec != fap->fa_mtime.tv_sec || 224 np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec) 225 purge_data = 1; 226 if (np->r_attr.fa_size != fap->fa_size) 227 purge_data = 1; 228 229 if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec || 230 np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec) 231 purge_acl = 1; 232 233 if (purge_acl) { 234 np->r_sectime = gethrtime(); 235 } 236 237 mutex_exit(&np->r_statelock); 238 239 if (purge_data) 240 smbfs_purge_caches(vp, cr); 241 } 242 243 /* 244 * Set attributes cache for given vnode using SMB fattr 245 * and update the attribute cache timeout. 246 * 247 * Based on NFS: nfs_attrcache, nfs_attrcache_va 248 */ 249 void 250 smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap) 251 { 252 smbnode_t *np; 253 smbmntinfo_t *smi; 254 hrtime_t delta, now; 255 u_offset_t newsize; 256 vtype_t vtype, oldvt; 257 mode_t mode; 258 259 np = VTOSMB(vp); 260 smi = VTOSMI(vp); 261 262 /* 263 * We allow v_type to change, so set that here 264 * (and the mode, which depends on the type). 265 */ 266 if (fap->fa_attr & SMB_FA_DIR) { 267 vtype = VDIR; 268 mode = smi->smi_dmode; 269 } else { 270 vtype = VREG; 271 mode = smi->smi_fmode; 272 } 273 274 mutex_enter(&np->r_statelock); 275 now = gethrtime(); 276 277 /* 278 * Delta is the number of nanoseconds that we will 279 * cache the attributes of the file. It is based on 280 * the number of nanoseconds since the last time that 281 * we detected a change. The assumption is that files 282 * that changed recently are likely to change again. 283 * There is a minimum and a maximum for regular files 284 * and for directories which is enforced though. 285 * 286 * Using the time since last change was detected 287 * eliminates direct comparison or calculation 288 * using mixed client and server times. SMBFS 289 * does not make any assumptions regarding the 290 * client and server clocks being synchronized. 291 */ 292 if (fap->fa_mtime.tv_sec != np->r_attr.fa_mtime.tv_sec || 293 fap->fa_mtime.tv_nsec != np->r_attr.fa_mtime.tv_nsec || 294 fap->fa_size != np->r_attr.fa_size) 295 np->r_mtime = now; 296 297 if ((smi->smi_flags & SMI_NOAC) || (vp->v_flag & VNOCACHE)) 298 delta = 0; 299 else { 300 delta = now - np->r_mtime; 301 if (vtype == VDIR) { 302 if (delta < smi->smi_acdirmin) 303 delta = smi->smi_acdirmin; 304 else if (delta > smi->smi_acdirmax) 305 delta = smi->smi_acdirmax; 306 } else { 307 if (delta < smi->smi_acregmin) 308 delta = smi->smi_acregmin; 309 else if (delta > smi->smi_acregmax) 310 delta = smi->smi_acregmax; 311 } 312 } 313 314 np->r_attrtime = now + delta; 315 np->r_attr = *fap; 316 np->n_mode = mode; 317 oldvt = vp->v_type; 318 vp->v_type = vtype; 319 320 /* 321 * Shall we update r_size? (local notion of size) 322 * 323 * The real criteria for updating r_size should be: 324 * if the file has grown on the server, or if 325 * the client has not modified the file. 326 * 327 * Also deal with the fact that SMB presents 328 * directories as having size=0. Doing that 329 * here and leaving fa_size as returned OtW 330 * avoids fixing the size lots of places. 331 */ 332 newsize = fap->fa_size; 333 if (vtype == VDIR && newsize < DEV_BSIZE) 334 newsize = DEV_BSIZE; 335 336 if (np->r_size != newsize && 337 (!vn_has_cached_data(vp) || 338 (!(np->r_flags & RDIRTY) && np->r_count == 0))) { 339 /* OK to set the size. */ 340 np->r_size = newsize; 341 } 342 343 /* 344 * Here NFS has: 345 * nfs_setswaplike(vp, va); 346 * np->r_flags &= ~RWRITEATTR; 347 * (not needed here) 348 */ 349 350 np->n_flag &= ~NATTRCHANGED; 351 mutex_exit(&np->r_statelock); 352 353 if (oldvt != vtype) { 354 SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype); 355 } 356 } 357 358 /* 359 * Fill in attribute from the cache. 360 * 361 * If valid, copy to *fap and return zero, 362 * otherwise return an error. 363 * 364 * From NFS: nfs_getattr_cache() 365 */ 366 int 367 smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap) 368 { 369 smbnode_t *np; 370 int error; 371 372 np = VTOSMB(vp); 373 374 mutex_enter(&np->r_statelock); 375 if (gethrtime() >= np->r_attrtime) { 376 /* cache expired */ 377 error = ENOENT; 378 } else { 379 /* cache is valid */ 380 *fap = np->r_attr; 381 error = 0; 382 } 383 mutex_exit(&np->r_statelock); 384 385 return (error); 386 } 387 388 /* 389 * Get attributes over-the-wire and update attributes cache 390 * if no error occurred in the over-the-wire operation. 391 * Return 0 if successful, otherwise error. 392 * From NFS: nfs_getattr_otw 393 */ 394 static int 395 smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr) 396 { 397 struct smbnode *np; 398 struct smb_cred scred; 399 int error; 400 401 np = VTOSMB(vp); 402 403 /* 404 * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL) 405 * With SMB, getting the ACL is a significantly more 406 * expensive operation, so we do that only when asked 407 * for the uid/gid. See smbfsgetattr(). 408 */ 409 410 /* Shared lock for (possible) n_fid use. */ 411 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 412 return (EINTR); 413 smb_credinit(&scred, cr); 414 415 bzero(fap, sizeof (*fap)); 416 error = smbfs_smb_getfattr(np, fap, &scred); 417 418 smb_credrele(&scred); 419 smbfs_rw_exit(&np->r_lkserlock); 420 421 if (error) { 422 /* Here NFS has: PURGE_STALE_FH(error, vp, cr) */ 423 smbfs_attrcache_remove(np); 424 if (error == ENOENT || error == ENOTDIR) { 425 /* 426 * Getattr failed because the object was 427 * removed or renamed by another client. 428 * Remove any cached attributes under it. 429 */ 430 smbfs_attrcache_prune(np); 431 } 432 return (error); 433 } 434 435 /* 436 * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr); 437 * which did: fattr_to_vattr, nfs_attr_cache. 438 * We cache the fattr form, so just do the 439 * cache check and store the attributes. 440 */ 441 smbfs_cache_check(vp, fap, cr); 442 smbfs_attrcache_fa(vp, fap); 443 444 return (0); 445 } 446 447 /* 448 * Return either cached or remote attributes. If we get remote attrs, 449 * use them to check and invalidate caches, then cache the new attributes. 450 * 451 * From NFS: nfsgetattr() 452 */ 453 int 454 smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) 455 { 456 struct smbfattr fa; 457 smbmntinfo_t *smi; 458 uint_t mask; 459 int error; 460 461 smi = VTOSMI(vp); 462 463 ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone); 464 465 /* 466 * If asked for UID or GID, update n_uid, n_gid. 467 */ 468 mask = AT_ALL; 469 if (vap->va_mask & (AT_UID | AT_GID)) { 470 if (smi->smi_flags & SMI_ACL) 471 (void) smbfs_acl_getids(vp, cr); 472 /* else leave as set in make_smbnode */ 473 } else { 474 mask &= ~(AT_UID | AT_GID); 475 } 476 477 /* 478 * If we've got cached attributes, just use them; 479 * otherwise go to the server to get attributes, 480 * which will update the cache in the process. 481 */ 482 error = smbfs_getattr_cache(vp, &fa); 483 if (error) 484 error = smbfs_getattr_otw(vp, &fa, cr); 485 if (error) 486 return (error); 487 vap->va_mask |= mask; 488 489 /* 490 * Re. client's view of the file size, see: 491 * smbfs_attrcache_fa, smbfs_getattr_otw 492 */ 493 smbfattr_to_vattr(vp, &fa, vap); 494 if (vap->va_mask & AT_XVATTR) 495 smbfattr_to_xvattr(&fa, vap); 496 497 return (0); 498 } 499 500 501 /* 502 * Convert SMB over the wire attributes to vnode form. 503 * Returns 0 for success, error if failed (overflow, etc). 504 * From NFS: nattr_to_vattr() 505 */ 506 void 507 smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap) 508 { 509 struct smbnode *np = VTOSMB(vp); 510 511 /* 512 * Take type, mode, uid, gid from the smbfs node, 513 * which has have been updated by _getattr_otw. 514 */ 515 vap->va_type = vp->v_type; 516 vap->va_mode = np->n_mode; 517 518 vap->va_uid = np->n_uid; 519 vap->va_gid = np->n_gid; 520 521 vap->va_fsid = vp->v_vfsp->vfs_dev; 522 vap->va_nodeid = np->n_ino; 523 vap->va_nlink = 1; 524 525 /* 526 * Difference from NFS here: We cache attributes as 527 * reported by the server, so r_attr.fa_size is the 528 * server's idea of the file size. This is called 529 * for getattr, so we want to return the client's 530 * idea of the file size. NFS deals with that in 531 * nfsgetattr(), the equivalent of our caller. 532 */ 533 vap->va_size = np->r_size; 534 535 /* 536 * Times. Note, already converted from NT to 537 * Unix form (in the unmarshalling code). 538 */ 539 vap->va_atime = fa->fa_atime; 540 vap->va_mtime = fa->fa_mtime; 541 vap->va_ctime = fa->fa_ctime; 542 543 /* 544 * rdev, blksize, seq are made up. 545 * va_nblocks is 512 byte blocks. 546 */ 547 vap->va_rdev = vp->v_rdev; 548 vap->va_blksize = MAXBSIZE; 549 vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz); 550 vap->va_seq = 0; 551 } 552 553 /* 554 * smbfattr_to_xvattr: like smbfattr_to_vattr but for 555 * Extensible system attributes (PSARC 2007/315) 556 */ 557 static void 558 smbfattr_to_xvattr(struct smbfattr *fa, struct vattr *vap) 559 { 560 xvattr_t *xvap = (xvattr_t *)vap; /* *vap may be xvattr_t */ 561 xoptattr_t *xoap = NULL; 562 563 if ((xoap = xva_getxoptattr(xvap)) == NULL) 564 return; 565 566 if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 567 xoap->xoa_createtime = fa->fa_createtime; 568 XVA_SET_RTN(xvap, XAT_CREATETIME); 569 } 570 571 if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) { 572 xoap->xoa_archive = 573 ((fa->fa_attr & SMB_FA_ARCHIVE) != 0); 574 XVA_SET_RTN(xvap, XAT_ARCHIVE); 575 } 576 577 if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) { 578 xoap->xoa_system = 579 ((fa->fa_attr & SMB_FA_SYSTEM) != 0); 580 XVA_SET_RTN(xvap, XAT_SYSTEM); 581 } 582 583 if (XVA_ISSET_REQ(xvap, XAT_READONLY)) { 584 xoap->xoa_readonly = 585 ((fa->fa_attr & SMB_FA_RDONLY) != 0); 586 XVA_SET_RTN(xvap, XAT_READONLY); 587 } 588 589 if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) { 590 xoap->xoa_hidden = 591 ((fa->fa_attr & SMB_FA_HIDDEN) != 0); 592 XVA_SET_RTN(xvap, XAT_HIDDEN); 593 } 594 } 595 596 /* 597 * Here NFS has: 598 * nfs_async_... stuff 599 * which we're not using (no async I/O), and: 600 * writerp(), 601 * nfs_putpages() 602 * nfs_invalidate_pages() 603 * which we have in smbfs_vnops.c, and 604 * nfs_printfhandle() 605 * nfs_write_error() 606 * not needed here. 607 */ 608 609 /* 610 * Helper function for smbfs_sync 611 * 612 * Walk the per-zone list of smbfs mounts, calling smbfs_rflush 613 * on each one. This is a little tricky because we need to exit 614 * the list mutex before each _rflush call and then try to resume 615 * where we were in the list after re-entering the mutex. 616 */ 617 void 618 smbfs_flushall(cred_t *cr) 619 { 620 smi_globals_t *smg; 621 smbmntinfo_t *tmp_smi, *cur_smi, *next_smi; 622 623 smg = zone_getspecific(smi_list_key, crgetzone(cr)); 624 ASSERT(smg != NULL); 625 626 mutex_enter(&smg->smg_lock); 627 cur_smi = list_head(&smg->smg_list); 628 if (cur_smi == NULL) { 629 mutex_exit(&smg->smg_lock); 630 return; 631 } 632 VFS_HOLD(cur_smi->smi_vfsp); 633 mutex_exit(&smg->smg_lock); 634 635 flush: 636 smbfs_rflush(cur_smi->smi_vfsp, cr); 637 638 mutex_enter(&smg->smg_lock); 639 /* 640 * Resume after cur_smi if that's still on the list, 641 * otherwise restart at the head. 642 */ 643 for (tmp_smi = list_head(&smg->smg_list); 644 tmp_smi != NULL; 645 tmp_smi = list_next(&smg->smg_list, tmp_smi)) 646 if (tmp_smi == cur_smi) 647 break; 648 if (tmp_smi != NULL) 649 next_smi = list_next(&smg->smg_list, tmp_smi); 650 else 651 next_smi = list_head(&smg->smg_list); 652 653 if (next_smi != NULL) 654 VFS_HOLD(next_smi->smi_vfsp); 655 VFS_RELE(cur_smi->smi_vfsp); 656 657 mutex_exit(&smg->smg_lock); 658 659 if (next_smi != NULL) { 660 cur_smi = next_smi; 661 goto flush; 662 } 663 } 664 665 /* 666 * SMB Client initialization and cleanup. 667 * Much of it is per-zone now. 668 */ 669 670 671 /* ARGSUSED */ 672 static void * 673 smbfs_zone_init(zoneid_t zoneid) 674 { 675 smi_globals_t *smg; 676 677 smg = kmem_alloc(sizeof (*smg), KM_SLEEP); 678 mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL); 679 list_create(&smg->smg_list, sizeof (smbmntinfo_t), 680 offsetof(smbmntinfo_t, smi_zone_node)); 681 smg->smg_destructor_called = B_FALSE; 682 return (smg); 683 } 684 685 /* 686 * Callback routine to tell all SMBFS mounts in the zone to stop creating new 687 * threads. Existing threads should exit. 688 */ 689 /* ARGSUSED */ 690 static void 691 smbfs_zone_shutdown(zoneid_t zoneid, void *data) 692 { 693 smi_globals_t *smg = data; 694 smbmntinfo_t *smi; 695 696 ASSERT(smg != NULL); 697 again: 698 mutex_enter(&smg->smg_lock); 699 for (smi = list_head(&smg->smg_list); smi != NULL; 700 smi = list_next(&smg->smg_list, smi)) { 701 702 /* 703 * If we've done the shutdown work for this FS, skip. 704 * Once we go off the end of the list, we're done. 705 */ 706 if (smi->smi_flags & SMI_DEAD) 707 continue; 708 709 /* 710 * We will do work, so not done. Get a hold on the FS. 711 */ 712 VFS_HOLD(smi->smi_vfsp); 713 714 mutex_enter(&smi->smi_lock); 715 smi->smi_flags |= SMI_DEAD; 716 mutex_exit(&smi->smi_lock); 717 718 /* 719 * Drop lock and release FS, which may change list, then repeat. 720 * We're done when every mi has been done or the list is empty. 721 */ 722 mutex_exit(&smg->smg_lock); 723 VFS_RELE(smi->smi_vfsp); 724 goto again; 725 } 726 mutex_exit(&smg->smg_lock); 727 } 728 729 static void 730 smbfs_zone_free_globals(smi_globals_t *smg) 731 { 732 list_destroy(&smg->smg_list); /* makes sure the list is empty */ 733 mutex_destroy(&smg->smg_lock); 734 kmem_free(smg, sizeof (*smg)); 735 736 } 737 738 /* ARGSUSED */ 739 static void 740 smbfs_zone_destroy(zoneid_t zoneid, void *data) 741 { 742 smi_globals_t *smg = data; 743 744 ASSERT(smg != NULL); 745 mutex_enter(&smg->smg_lock); 746 if (list_head(&smg->smg_list) != NULL) { 747 /* Still waiting for VFS_FREEVFS() */ 748 smg->smg_destructor_called = B_TRUE; 749 mutex_exit(&smg->smg_lock); 750 return; 751 } 752 smbfs_zone_free_globals(smg); 753 } 754 755 /* 756 * Add an SMBFS mount to the per-zone list of SMBFS mounts. 757 */ 758 void 759 smbfs_zonelist_add(smbmntinfo_t *smi) 760 { 761 smi_globals_t *smg; 762 763 smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone); 764 mutex_enter(&smg->smg_lock); 765 list_insert_head(&smg->smg_list, smi); 766 mutex_exit(&smg->smg_lock); 767 } 768 769 /* 770 * Remove an SMBFS mount from the per-zone list of SMBFS mounts. 771 */ 772 void 773 smbfs_zonelist_remove(smbmntinfo_t *smi) 774 { 775 smi_globals_t *smg; 776 777 smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone); 778 mutex_enter(&smg->smg_lock); 779 list_remove(&smg->smg_list, smi); 780 /* 781 * We can be called asynchronously by VFS_FREEVFS() after the zone 782 * shutdown/destroy callbacks have executed; if so, clean up the zone's 783 * smi_globals. 784 */ 785 if (list_head(&smg->smg_list) == NULL && 786 smg->smg_destructor_called == B_TRUE) { 787 smbfs_zone_free_globals(smg); 788 return; 789 } 790 mutex_exit(&smg->smg_lock); 791 } 792 793 #ifdef lint 794 #define NEED_SMBFS_CALLBACKS 1 795 #endif 796 797 #ifdef NEED_SMBFS_CALLBACKS 798 /* 799 * Call-back hooks for netsmb, in case we want them. 800 * Apple's VFS wants them. We may not need them. 801 */ 802 /*ARGSUSED*/ 803 static void smbfs_dead(smb_share_t *ssp) 804 { 805 /* 806 * Walk the mount list, finding all mounts 807 * using this share... 808 */ 809 } 810 811 /*ARGSUSED*/ 812 static void smbfs_cb_nop(smb_share_t *ss) 813 { 814 /* no-op */ 815 } 816 817 smb_fscb_t smbfs_cb = { 818 .fscb_disconn = smbfs_dead, 819 .fscb_connect = smbfs_cb_nop, 820 .fscb_down = smbfs_cb_nop, 821 .fscb_up = smbfs_cb_nop }; 822 823 #endif /* NEED_SMBFS_CALLBACKS */ 824 825 /* 826 * SMBFS Client initialization routine. This routine should only be called 827 * once. It performs the following tasks: 828 * - Initalize all global locks 829 * - Call sub-initialization routines (localize access to variables) 830 */ 831 int 832 smbfs_clntinit(void) 833 { 834 835 zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown, 836 smbfs_zone_destroy); 837 #ifdef NEED_SMBFS_CALLBACKS 838 (void) smb_fscb_set(&smbfs_cb); 839 #endif /* NEED_SMBFS_CALLBACKS */ 840 return (0); 841 } 842 843 /* 844 * This routine is called when the modunload is called. This will cleanup 845 * the previously allocated/initialized nodes. 846 */ 847 void 848 smbfs_clntfini(void) 849 { 850 #ifdef NEED_SMBFS_CALLBACKS 851 (void) smb_fscb_set(NULL); 852 #endif /* NEED_SMBFS_CALLBACKS */ 853 (void) zone_key_delete(smi_list_key); 854 }