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