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