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