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