1 /* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/systm.h> 43 #include <sys/cred.h> 44 #include <sys/vfs.h> 45 #include <sys/vnode.h> 46 #include <fs/fs_subr.h> 47 #include <sys/sysmacros.h> 48 #include <sys/kmem.h> 49 #include <sys/mkdev.h> 50 #include <sys/mount.h> 51 #include <sys/statvfs.h> 52 #include <sys/errno.h> 53 #include <sys/debug.h> 54 #include <sys/cmn_err.h> 55 #include <sys/modctl.h> 56 #include <sys/policy.h> 57 #include <sys/atomic.h> 58 #include <sys/zone.h> 59 #include <sys/vfs_opreg.h> 60 #include <sys/mntent.h> 61 #include <sys/priv.h> 62 #include <sys/tsol/label.h> 63 #include <sys/tsol/tndb.h> 64 #include <inet/ip.h> 65 66 #include <netsmb/smb_osdep.h> 67 #include <netsmb/smb.h> 68 #include <netsmb/smb_conn.h> 69 #include <netsmb/smb_subr.h> 70 #include <netsmb/smb_dev.h> 71 72 #include <smbfs/smbfs.h> 73 #include <smbfs/smbfs_node.h> 74 #include <smbfs/smbfs_subr.h> 75 76 /* 77 * Local functions definitions. 78 */ 79 int smbfsinit(int fstyp, char *name); 80 void smbfsfini(); 81 static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); 82 83 static vfsdef_t vfw = { 84 VFSDEF_VERSION, 85 "smbfs", /* type name string */ 86 smbfsinit, /* init routine */ 87 VSW_NOTZONESAFE, /* flags */ 88 NULL /* mount options table prototype */ 89 }; 90 91 static struct modlfs modlfs = { 92 &mod_fsops, 93 "SMBFS filesystem v" SMBFS_VER_STR, 94 &vfw 95 }; 96 97 static struct modlinkage modlinkage = { 98 MODREV_1, (void *)&modlfs, NULL 99 }; 100 101 /* 102 * Mutex to protect the following variables: 103 * smbfs_major 104 * smbfs_minor 105 */ 106 extern kmutex_t smbfs_minor_lock; 107 extern int smbfs_major; 108 extern int smbfs_minor; 109 110 /* 111 * Prevent unloads while we have mounts 112 */ 113 uint32_t smbfs_mountcount; 114 115 /* 116 * smbfs vfs operations. 117 */ 118 static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 119 static int smbfs_unmount(vfs_t *, int, cred_t *); 120 static int smbfs_root(vfs_t *, vnode_t **); 121 static int smbfs_statvfs(vfs_t *, statvfs64_t *); 122 static int smbfs_sync(vfs_t *, short, cred_t *); 123 static void smbfs_freevfs(vfs_t *); 124 125 /* 126 * Module loading 127 */ 128 129 /* 130 * This routine is invoked automatically when the kernel module 131 * containing this routine is loaded. This allows module specific 132 * initialization to be done when the module is loaded. 133 */ 134 int 135 _init(void) 136 { 137 int status; 138 139 /* 140 * Check compiled-in version of "nsmb" 141 * that we're linked with. (paranoid) 142 */ 143 if (nsmb_version != NSMB_VERSION) { 144 cmn_err(CE_WARN, "_init: nsmb version mismatch"); 145 return (ENOTTY); 146 } 147 148 smbfs_mountcount = 0; 149 150 if ((status = smbfs_clntinit()) != 0) { 151 cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); 152 return (status); 153 } 154 155 status = mod_install((struct modlinkage *)&modlinkage); 156 return (status); 157 } 158 159 /* 160 * Free kernel module resources that were allocated in _init 161 * and remove the linkage information into the kernel 162 */ 163 int 164 _fini(void) 165 { 166 int error; 167 168 /* 169 * If a forcedly unmounted instance is still hanging around, 170 * we cannot allow the module to be unloaded because that would 171 * cause panics once the VFS framework decides it's time to call 172 * into VFS_FREEVFS(). 173 */ 174 if (smbfs_mountcount) 175 return (EBUSY); 176 177 error = mod_remove(&modlinkage); 178 if (error) 179 return (error); 180 181 /* 182 * Free the allocated smbnodes, etc. 183 */ 184 smbfs_clntfini(); 185 186 /* 187 * Free the ops vectors 188 */ 189 smbfsfini(); 190 return (0); 191 } 192 193 /* 194 * Return information about the module 195 */ 196 int 197 _info(struct modinfo *modinfop) 198 { 199 return (mod_info((struct modlinkage *)&modlinkage, modinfop)); 200 } 201 202 /* 203 * Initialize the vfs structure 204 */ 205 206 int smbfsfstyp; 207 vfsops_t *smbfs_vfsops = NULL; 208 209 static const fs_operation_def_t smbfs_vfsops_template[] = { 210 { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, 211 { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, 212 { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, 213 { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, 214 { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, 215 { VFSNAME_VGET, { .error = fs_nosys } }, 216 { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, 217 { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, 218 { NULL, NULL } 219 }; 220 221 int 222 smbfsinit(int fstyp, char *name) 223 { 224 int error; 225 226 error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); 227 if (error != 0) { 228 zcmn_err(GLOBAL_ZONEID, CE_WARN, 229 "smbfsinit: bad vfs ops template"); 230 return (error); 231 } 232 233 error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); 234 if (error != 0) { 235 (void) vfs_freevfsops_by_type(fstyp); 236 zcmn_err(GLOBAL_ZONEID, CE_WARN, 237 "smbfsinit: bad vnode ops template"); 238 return (error); 239 } 240 241 smbfsfstyp = fstyp; 242 243 return (0); 244 } 245 246 void 247 smbfsfini() 248 { 249 if (smbfs_vfsops) { 250 (void) vfs_freevfsops_by_type(smbfsfstyp); 251 smbfs_vfsops = NULL; 252 } 253 if (smbfs_vnodeops) { 254 vn_freevnodeops(smbfs_vnodeops); 255 smbfs_vnodeops = NULL; 256 } 257 } 258 259 void 260 smbfs_free_smi(smbmntinfo_t *smi) 261 { 262 if (smi) { 263 smbfs_zonelist_remove(smi); 264 kmem_free(smi, sizeof (smbmntinfo_t)); 265 } 266 } 267 268 /* 269 * smbfs mount vfsop 270 * Set up mount info record and attach it to vfs struct. 271 */ 272 static int 273 smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 274 { 275 char *data = uap->dataptr; 276 int error; 277 vnode_t *rtvp = NULL; /* root of this fs */ 278 smbmntinfo_t *smi = NULL; 279 dev_t smbfs_dev; 280 int version; 281 int devfd; 282 zone_t *zone = curproc->p_zone; 283 zone_t *mntzone = NULL; 284 smb_share_t *ssp = NULL; 285 smb_cred_t scred; 286 287 STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ 288 289 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 290 return (error); 291 292 if (mvp->v_type != VDIR) 293 return (ENOTDIR); 294 295 /* 296 * get arguments 297 * 298 * uap->datalen might be different from sizeof (args) 299 * in a compatible situation. 300 */ 301 STRUCT_INIT(args, get_udatamodel()); 302 bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); 303 if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 304 SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) 305 return (EFAULT); 306 307 /* 308 * Check mount program version 309 */ 310 version = STRUCT_FGET(args, version); 311 if (version != SMBFS_VERSION) { 312 cmn_err(CE_WARN, "mount version mismatch:" 313 " kernel=%d, mount=%d\n", 314 SMBFS_VERSION, version); 315 return (EINVAL); 316 } 317 318 if (uap->flags & MS_REMOUNT) { 319 cmn_err(CE_WARN, "MS_REMOUNT not implemented"); 320 return (ENOTSUP); 321 } 322 323 /* 324 * Check for busy 325 */ 326 mutex_enter(&mvp->v_lock); 327 if (!(uap->flags & MS_OVERLAY) && 328 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 329 mutex_exit(&mvp->v_lock); 330 return (EBUSY); 331 } 332 mutex_exit(&mvp->v_lock); 333 334 /* 335 * Get the "share" from the netsmb driver (ssp). 336 * It is returned with a "ref" (hold) for us. 337 * Release this hold: at errout below, or in 338 * smbfs_freevfs(). 339 */ 340 devfd = STRUCT_FGET(args, devfd); 341 error = smb_dev2share(devfd, &ssp); 342 if (error) { 343 cmn_err(CE_WARN, "invalid device handle %d (%d)\n", 344 devfd, error); 345 return (error); 346 } 347 348 /* 349 * We don't have data structures to support multiple mounts of 350 * the same share object by the same owner, so don't allow it. 351 */ 352 if (ssp->ss_mount != NULL) { 353 smb_share_rele(ssp); 354 return (EBUSY); 355 } 356 357 smb_credinit(&scred, curproc, cr); 358 359 /* 360 * Use "goto errout" from here on. 361 * See: ssp, smi, rtvp, mntzone 362 */ 363 364 /* 365 * Determine the zone we're being mounted into. 366 */ 367 zone_hold(mntzone = zone); /* start with this assumption */ 368 if (getzoneid() == GLOBAL_ZONEID) { 369 zone_rele(mntzone); 370 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 371 ASSERT(mntzone != NULL); 372 if (mntzone != zone) { 373 error = EBUSY; 374 goto errout; 375 } 376 } 377 378 /* 379 * Stop the mount from going any further if the zone is going away. 380 */ 381 if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 382 error = EBUSY; 383 goto errout; 384 } 385 386 /* 387 * On a Trusted Extensions client, we may have to force read-only 388 * for read-down mounts. 389 */ 390 if (is_system_labeled()) { 391 void *addr; 392 int ipvers = 0; 393 struct smb_vc *vcp; 394 395 vcp = SSTOVC(ssp); 396 addr = smb_vc_getipaddr(vcp, &ipvers); 397 error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); 398 399 if (error > 0) 400 goto errout; 401 402 if (error == -1) { 403 /* change mount to read-only to prevent write-down */ 404 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 405 } 406 } 407 408 /* 409 * Get root vnode. 410 */ 411 proceed: 412 413 /* 414 * Create a mount record and link it to the vfs struct. 415 * Compare with NFS: nfsrootvp() 416 */ 417 smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP); 418 419 smi->smi_share = ssp; 420 ssp->ss_mount = smi; 421 smi->smi_zone = mntzone; 422 423 /* 424 * XXX If not root, get uid/gid from the covered vnode. 425 */ 426 smi->smi_args.dir_mode = STRUCT_FGET(args, dir_mode); 427 smi->smi_args.file_mode = STRUCT_FGET(args, file_mode); 428 smi->smi_args.uid = STRUCT_FGET(args, uid); 429 smi->smi_args.gid = STRUCT_FGET(args, gid); 430 431 error = smbfs_smb_qfsattr(ssp, &smi->smi_fsattr, &scred); 432 if (error) { 433 SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); 434 } 435 436 #ifdef NOT_YET 437 /* Once acls are implemented, remove the ifdefs */ 438 else if (smbfs_aclsflunksniff(smi, &scred)) { 439 mutex_enter(&smi->smi_lock); 440 smi->smi_fsattr &= ~FILE_PERSISTENT_ACLS; 441 mutex_exit(&smi->smi_lock); 442 } 443 #endif /* NOT_YET */ 444 445 /* 446 * Assign a unique device id to the mount 447 */ 448 mutex_enter(&smbfs_minor_lock); 449 do { 450 smbfs_minor = (smbfs_minor + 1) & MAXMIN32; 451 smbfs_dev = makedevice(smbfs_major, smbfs_minor); 452 } while (vfs_devismounted(smbfs_dev)); 453 mutex_exit(&smbfs_minor_lock); 454 455 vfsp->vfs_dev = smbfs_dev; 456 vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); 457 vfsp->vfs_data = (caddr_t)smi; 458 vfsp->vfs_fstype = smbfsfstyp; 459 vfsp->vfs_bsize = MAXBSIZE; 460 vfsp->vfs_bcount = 0; 461 462 smi->smi_flags = SMI_INT | SMI_LLOCK; 463 smi->smi_vfsp = vfsp; 464 smbfs_zonelist_add(smi); 465 466 /* 467 * Create the root vnode, which we need in unmount 468 * for the call to smb_check_table(), etc. 469 */ 470 rtvp = smbfs_make_node(vfsp, "\\", 1, NULL, 0, NULL); 471 if (!rtvp) { 472 cmn_err(CE_WARN, "smbfs_mount: make_node failed\n"); 473 return (ENOENT); 474 } 475 rtvp->v_type = VDIR; 476 rtvp->v_flag |= VROOT; 477 478 /* 479 * Could get attributes here, but that can wait 480 * until someone does a getattr call. 481 * 482 * NFS does other stuff here too: 483 * async worker threads 484 * init kstats 485 * 486 * End of code from NFS nfsrootvp() 487 */ 488 489 smb_credrele(&scred); 490 491 smi->smi_root = VTOSMB(rtvp); 492 493 atomic_inc_32(&smbfs_mountcount); 494 495 return (0); 496 497 errout: 498 499 ASSERT(rtvp == NULL); 500 501 vfsp->vfs_data = NULL; 502 if (smi) 503 smbfs_free_smi(smi); 504 505 if (mntzone != NULL) 506 zone_rele(mntzone); 507 508 if (ssp) 509 smb_share_rele(ssp); 510 511 smb_credrele(&scred); 512 513 /* args, if we allocated */ 514 515 return (error); 516 } 517 518 /* 519 * vfs operations 520 */ 521 static int 522 smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 523 { 524 smbmntinfo_t *smi; 525 smbnode_t *rtnp; 526 527 smi = VFTOSMI(vfsp); 528 529 if (secpolicy_fs_unmount(cr, vfsp) != 0) 530 return (EPERM); 531 532 if ((flag & MS_FORCE) == 0) { 533 #ifdef APPLE 534 smbfs_rflush(vfsp, cr); 535 #endif 536 537 /* 538 * If there are any active vnodes on this file system, 539 * (other than the root vnode) then the file system is 540 * busy and can't be umounted. 541 */ 542 if (smb_check_table(vfsp, smi->smi_root)) 543 return (EBUSY); 544 545 /* 546 * We normally hold a ref to the root vnode, so 547 * check for references beyond the one we expect: 548 * smbmntinfo_t -> smi_root 549 * Note that NFS does not hold the root vnode. 550 */ 551 if (smi->smi_root && 552 smi->smi_root->r_vnode->v_count > 1) 553 return (EBUSY); 554 } 555 556 /* 557 * common code for both forced and non-forced 558 * 559 * Setting VFS_UNMOUNTED prevents new operations. 560 * Operations already underway may continue, 561 * but not for long. 562 */ 563 vfsp->vfs_flag |= VFS_UNMOUNTED; 564 565 /* 566 * Shutdown any outstanding I/O requests on this share, 567 * and force a tree disconnect. The share object will 568 * continue to hang around until smb_share_rele(). 569 * This should also cause most active nodes to be 570 * released as their operations fail with EIO. 571 */ 572 smb_share_kill(smi->smi_share); 573 574 /* 575 * If we hold the root VP (and we normally do) 576 * then it's safe to release it now. 577 */ 578 if (smi->smi_root) { 579 rtnp = smi->smi_root; 580 smi->smi_root = NULL; 581 VN_RELE(rtnp->r_vnode); /* release root vnode */ 582 } 583 584 /* 585 * Remove all nodes from the node hash tables. 586 * This (indirectly) calls: smb_addfree, smbinactive, 587 * which will try to flush dirty pages, etc. so 588 * don't destroy the underlying share just yet. 589 * 590 * Also, with a forced unmount, some nodes may 591 * remain active, and those will get cleaned up 592 * after their last vn_rele. 593 */ 594 smbfs_destroy_table(vfsp); 595 596 /* 597 * Delete our kstats... 598 * 599 * Doing it here, rather than waiting until 600 * smbfs_freevfs so these are not visible 601 * after the unmount. 602 */ 603 if (smi->smi_io_kstats) { 604 kstat_delete(smi->smi_io_kstats); 605 smi->smi_io_kstats = NULL; 606 } 607 if (smi->smi_ro_kstats) { 608 kstat_delete(smi->smi_ro_kstats); 609 smi->smi_ro_kstats = NULL; 610 } 611 612 /* 613 * Note: the smb_share_rele() 614 * happens in smbfs_freevfs() 615 */ 616 617 return (0); 618 } 619 620 621 /* 622 * find root of smbfs 623 */ 624 static int 625 smbfs_root(vfs_t *vfsp, vnode_t **vpp) 626 { 627 smbmntinfo_t *smi; 628 vnode_t *vp; 629 630 smi = VFTOSMI(vfsp); 631 632 if (curproc->p_zone != smi->smi_zone) 633 return (EPERM); 634 635 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 636 return (EIO); 637 638 /* 639 * The root vp is created in mount and held 640 * until unmount, so this is paranoia. 641 */ 642 if (smi->smi_root == NULL) 643 return (EIO); 644 645 /* Just take a reference and return it. */ 646 vp = SMBTOV(smi->smi_root); 647 VN_HOLD(vp); 648 *vpp = vp; 649 650 return (0); 651 } 652 653 /* 654 * Get file system statistics. 655 */ 656 static int 657 smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) 658 { 659 int error; 660 smbmntinfo_t *smi = VFTOSMI(vfsp); 661 smb_share_t *ssp = smi->smi_share; 662 statvfs64_t stvfs; 663 hrtime_t now; 664 smb_cred_t scred; 665 666 if (curproc->p_zone != smi->smi_zone) 667 return (EPERM); 668 669 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 670 return (EIO); 671 672 mutex_enter(&smi->smi_lock); 673 674 /* 675 * Use cached result if still valid. 676 */ 677 recheck: 678 now = gethrtime(); 679 if (now < smi->smi_statfstime) { 680 goto cache_hit; 681 } 682 683 /* 684 * FS attributes are stale, so someone 685 * needs to do an OTW call to get them. 686 * Serialize here so only one thread 687 * does the OTW call. 688 */ 689 if (smi->smi_status & SM_STATUS_STATFS_BUSY) { 690 smi->smi_status |= SM_STATUS_STATFS_WANT; 691 if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { 692 mutex_exit(&smi->smi_lock); 693 return (EINTR); 694 } 695 /* Hope status is valid now. */ 696 goto recheck; 697 } 698 smi->smi_status |= SM_STATUS_STATFS_BUSY; 699 mutex_exit(&smi->smi_lock); 700 701 /* 702 * Do the OTW call. Note: lock NOT held. 703 */ 704 smb_credinit(&scred, curproc, NULL); 705 bzero(&stvfs, sizeof (stvfs)); 706 error = smbfs_smb_statfs(ssp, &stvfs, &scred); 707 smb_credrele(&scred); 708 709 mutex_enter(&smi->smi_lock); 710 if (smi->smi_status & SM_STATUS_STATFS_WANT) 711 cv_broadcast(&smi->smi_statvfs_cv); 712 smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); 713 714 if (error) { 715 SMBVDEBUG("statfs error=%d\n", error); 716 mutex_exit(&smi->smi_lock); 717 return (error); 718 } 719 720 /* 721 * Set a few things the OTW call didn't get. 722 */ 723 stvfs.f_frsize = stvfs.f_bsize; 724 stvfs.f_favail = stvfs.f_ffree; 725 stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 726 strncpy(stvfs.f_basetype, vfw.name, FSTYPSZ); 727 stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); 728 stvfs.f_namemax = (uint32_t)MAXNAMELEN - 1; 729 730 /* 731 * Save the result, update lifetime 732 */ 733 now = gethrtime(); 734 smi->smi_statfstime = now + 735 (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); 736 smi->smi_statvfsbuf = stvfs; /* struct assign! */ 737 738 /* 739 * Copy the statvfs data to caller's buf. 740 * Note: struct assignment 741 */ 742 cache_hit: 743 *sbp = smi->smi_statvfsbuf; 744 mutex_exit(&smi->smi_lock); 745 return (error); 746 } 747 748 static kmutex_t smbfs_syncbusy; 749 750 /* 751 * Flush dirty smbfs files for file system vfsp. 752 * If vfsp == NULL, all smbfs files are flushed. 753 */ 754 /*ARGSUSED*/ 755 static int 756 smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 757 { 758 /* 759 * Cross-zone calls are OK here, since this translates to a 760 * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 761 */ 762 #ifdef APPLE 763 if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { 764 smbfs_rflush(vfsp, cr); 765 mutex_exit(&smbfs_syncbusy); 766 } 767 #endif /* APPLE */ 768 return (0); 769 } 770 771 /* 772 * Initialization routine for VFS routines. Should only be called once 773 */ 774 int 775 smbfs_vfsinit(void) 776 { 777 mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); 778 return (0); 779 } 780 781 /* 782 * Shutdown routine for VFS routines. Should only be called once 783 */ 784 void 785 smbfs_vfsfini(void) 786 { 787 mutex_destroy(&smbfs_syncbusy); 788 } 789 790 void 791 smbfs_freevfs(vfs_t *vfsp) 792 { 793 smbmntinfo_t *smi; 794 smb_share_t *ssp; 795 796 /* free up the resources */ 797 smi = VFTOSMI(vfsp); 798 799 /* 800 * By this time we should have already deleted the 801 * smi kstats in the unmount code. If they are still around 802 * something is wrong 803 */ 804 ASSERT(smi->smi_io_kstats == NULL); 805 806 /* 807 * Drop our reference to the share. 808 * This usually leads to VC close. 809 */ 810 ssp = smi->smi_share; 811 smi->smi_share = NULL; 812 ssp->ss_mount = NULL; 813 814 smb_share_rele(ssp); 815 816 zone_rele(smi->smi_zone); 817 818 smbfs_free_smi(smi); 819 820 /* 821 * Allow _fini() to succeed now, if so desired. 822 */ 823 atomic_dec_32(&smbfs_mountcount); 824 } 825 826 /* 827 * smbfs_mount_label_policy: 828 * Determine whether the mount is allowed according to MAC check, 829 * by comparing (where appropriate) label of the remote server 830 * against the label of the zone being mounted into. 831 * 832 * Returns: 833 * 0 : access allowed 834 * -1 : read-only access allowed (i.e., read-down) 835 * >0 : error code, such as EACCES 836 * 837 * NB: 838 * NFS supports Cipso labels by parsing the vfs_resource 839 * to see what the Solaris server global zone has shared. 840 * We can't support that for CIFS since resource names 841 * contain share names, not paths. 842 */ 843 static int 844 smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) 845 { 846 bslabel_t *server_sl, *mntlabel; 847 zone_t *mntzone = NULL; 848 ts_label_t *zlabel; 849 tsol_tpc_t *tp; 850 ts_label_t *tsl = NULL; 851 int retv; 852 853 /* 854 * Get the zone's label. Each zone on a labeled system has a label. 855 */ 856 mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 857 zlabel = mntzone->zone_slabel; 858 ASSERT(zlabel != NULL); 859 label_hold(zlabel); 860 861 retv = EACCES; /* assume the worst */ 862 863 /* 864 * Next, get the assigned label of the remote server. 865 */ 866 tp = find_tpc(ipaddr, addr_type, B_FALSE); 867 if (tp == NULL) 868 goto out; /* error getting host entry */ 869 870 if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) 871 goto rel_tpc; /* invalid domain */ 872 if ((tp->tpc_tp.host_type != UNLABELED)) 873 goto rel_tpc; /* invalid hosttype */ 874 875 server_sl = &tp->tpc_tp.tp_def_label; 876 mntlabel = label2bslabel(zlabel); 877 878 /* 879 * Now compare labels to complete the MAC check. If the labels 880 * are equal or if the requestor is in the global zone and has 881 * NET_MAC_AWARE, then allow read-write access. (Except for 882 * mounts into the global zone itself; restrict these to 883 * read-only.) 884 * 885 * If the requestor is in some other zone, but his label 886 * dominates the server, then allow read-down. 887 * 888 * Otherwise, access is denied. 889 */ 890 if (blequal(mntlabel, server_sl) || 891 (crgetzoneid(cr) == GLOBAL_ZONEID && 892 getpflags(NET_MAC_AWARE, cr) != 0)) { 893 if ((mntzone == global_zone) || 894 !blequal(mntlabel, server_sl)) 895 retv = -1; /* read-only */ 896 else 897 retv = 0; /* access OK */ 898 } else if (bldominates(mntlabel, server_sl)) { 899 retv = -1; /* read-only */ 900 } else { 901 retv = EACCES; 902 } 903 904 if (tsl != NULL) 905 label_rele(tsl); 906 907 rel_tpc: 908 /*LINTED*/ 909 TPC_RELE(tp); 910 out: 911 if (mntzone) 912 zone_rele(mntzone); 913 label_rele(zlabel); 914 return (retv); 915 } 916