1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2016 Joyent, Inc. 25 * Copyright 2016 Toomas Soome <tsoome@me.com> 26 * Copyright (c) 2016 by Delphix. All rights reserved. 27 * Copyright 2017 RackTop Systems. 28 * Copyright 2018 Nexenta Systems, Inc. 29 */ 30 31 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 /* 35 * University Copyright- Copyright (c) 1982, 1986, 1988 36 * The Regents of the University of California 37 * All Rights Reserved 38 * 39 * University Acknowledgment- Portions of this document are derived from 40 * software developed by the University of California, Berkeley, and its 41 * contributors. 42 */ 43 44 /* 45 * This file contains those functions from fs/vfs.c that can be 46 * used with relatively little change. Functions that differ 47 * significantly from that are in other files. 48 */ 49 50 #include <sys/types.h> 51 #include <sys/t_lock.h> 52 #include <sys/param.h> 53 #include <sys/errno.h> 54 #include <sys/user.h> 55 #include <sys/fstyp.h> 56 #include <sys/kmem.h> 57 #include <sys/systm.h> 58 #include <sys/proc.h> 59 #include <sys/mount.h> 60 #include <sys/vfs.h> 61 #include <sys/vfs_opreg.h> 62 #include <sys/fem.h> 63 #include <sys/mntent.h> 64 #include <sys/stat.h> 65 #include <sys/statvfs.h> 66 #include <sys/statfs.h> 67 #include <sys/cred.h> 68 #include <sys/vnode.h> 69 #include <sys/rwstlock.h> 70 #include <sys/dnlc.h> 71 #include <sys/file.h> 72 #include <sys/time.h> 73 #include <sys/atomic.h> 74 #include <sys/cmn_err.h> 75 #include <sys/buf.h> 76 #include <sys/debug.h> 77 #include <sys/vnode.h> 78 #include <sys/ddi.h> 79 #include <sys/pathname.h> 80 #include <sys/poll.h> 81 #include <sys/sunddi.h> 82 #include <sys/sysmacros.h> 83 #include <sys/zone.h> 84 #include <sys/policy.h> 85 #include <sys/attr.h> 86 #include <fs/fs_subr.h> 87 88 #include <libfksmbfs.h> 89 90 static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int); 91 static void vfs_setmntopt_nolock(mntopts_t *, const char *, 92 const char *, int, int); 93 static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **); 94 // static void vfs_freemnttab(struct vfs *); 95 static void vfs_freeopt(mntopt_t *); 96 static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *); 97 static void vfs_swapopttbl(mntopts_t *, mntopts_t *); 98 static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int); 99 // static void vfs_createopttbl_extend(mntopts_t *, const char *, 100 // const mntopts_t *); 101 // static char **vfs_copycancelopt_extend(char **const, int); 102 static void vfs_freecancelopt(char **); 103 104 /* 105 * VFS global data. 106 */ 107 vnode_t *rootdir; /* pointer to root inode vnode. */ 108 struct vfs *rootvfs = NULL; /* pointer to root vfs; head of VFS list. */ 109 static krwlock_t vfslist; 110 struct vfs *zone_vfslist; /* list of FS's mounted in zone */ 111 112 /* from os/vfs_conf.c */ 113 const int nfstype = 5; 114 struct vfssw vfssw[10] = { 115 { "BADVFS" }, /* 0:invalid */ 116 { "" }, /* reserved for loadable fs */ 117 { "" }, 118 { "" }, 119 { "" }, 120 }; 121 122 /* 123 * Table for generic options recognized in the VFS layer and acted 124 * on at this level before parsing file system specific options. 125 * The nosuid option is stronger than any of the devices and setuid 126 * options, so those are canceled when nosuid is seen. 127 * 128 * All options which are added here need to be added to the 129 * list of standard options in usr/src/cmd/fs.d/fslib.c as well. 130 */ 131 /* 132 * VFS Mount options table 133 */ 134 static char *ro_cancel[] = { MNTOPT_RW, NULL }; 135 static char *rw_cancel[] = { MNTOPT_RO, NULL }; 136 static char *suid_cancel[] = { MNTOPT_NOSUID, NULL }; 137 static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES, 138 MNTOPT_NOSETUID, MNTOPT_SETUID, NULL }; 139 static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL }; 140 static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL }; 141 static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL }; 142 static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL }; 143 static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL }; 144 static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL }; 145 static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL }; 146 static char *noexec_cancel[] = { MNTOPT_EXEC, NULL }; 147 148 static const mntopt_t mntopts[] = { 149 /* 150 * option name cancel options default arg flags 151 */ 152 { MNTOPT_REMOUNT, NULL, NULL, 153 MO_NODISPLAY, (void *)0 }, 154 { MNTOPT_RO, ro_cancel, NULL, 0, 155 (void *)0 }, 156 { MNTOPT_RW, rw_cancel, NULL, 0, 157 (void *)0 }, 158 { MNTOPT_SUID, suid_cancel, NULL, 0, 159 (void *)0 }, 160 { MNTOPT_NOSUID, nosuid_cancel, NULL, 0, 161 (void *)0 }, 162 { MNTOPT_DEVICES, devices_cancel, NULL, 0, 163 (void *)0 }, 164 { MNTOPT_NODEVICES, nodevices_cancel, NULL, 0, 165 (void *)0 }, 166 { MNTOPT_SETUID, setuid_cancel, NULL, 0, 167 (void *)0 }, 168 { MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0, 169 (void *)0 }, 170 { MNTOPT_NBMAND, nbmand_cancel, NULL, 0, 171 (void *)0 }, 172 { MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0, 173 (void *)0 }, 174 { MNTOPT_EXEC, exec_cancel, NULL, 0, 175 (void *)0 }, 176 { MNTOPT_NOEXEC, noexec_cancel, NULL, 0, 177 (void *)0 }, 178 }; 179 180 const mntopts_t vfs_mntopts = { 181 sizeof (mntopts) / sizeof (mntopt_t), 182 (mntopt_t *)&mntopts[0] 183 }; 184 185 /* 186 * File system operation dispatch functions. 187 */ 188 189 int 190 fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 191 { 192 return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr); 193 } 194 195 int 196 fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr) 197 { 198 return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr); 199 } 200 201 int 202 fsop_root(vfs_t *vfsp, vnode_t **vpp) 203 { 204 return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp)); 205 } 206 207 int 208 fsop_statfs(vfs_t *vfsp, statvfs64_t *sp) 209 { 210 return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp); 211 } 212 213 int 214 fsop_sync(vfs_t *vfsp, short flag, cred_t *cr) 215 { 216 return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr); 217 } 218 219 int 220 fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 221 { 222 return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp); 223 } 224 225 int 226 fsop_mountroot(vfs_t *vfsp, enum whymountroot reason) 227 { 228 return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason); 229 } 230 231 void 232 fsop_freefs(vfs_t *vfsp) 233 { 234 (*(vfsp)->vfs_op->vfs_freevfs)(vfsp); 235 } 236 237 int 238 fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate) 239 { 240 return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate)); 241 } 242 243 int 244 fsop_sync_by_kind(int fstype, short flag, cred_t *cr) 245 { 246 ASSERT((fstype >= 0) && (fstype < nfstype)); 247 248 if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype])) 249 return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr); 250 else 251 return (ENOTSUP); 252 } 253 254 /* 255 * File system initialization. vfs_setfsops() must be called from a file 256 * system's init routine. 257 */ 258 259 static int 260 fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual, 261 int *unused_ops) 262 { 263 static const fs_operation_trans_def_t vfs_ops_table[] = { 264 VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount), 265 fs_nosys, fs_nosys, 266 267 VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount), 268 fs_nosys, fs_nosys, 269 270 VFSNAME_ROOT, offsetof(vfsops_t, vfs_root), 271 fs_nosys, fs_nosys, 272 273 VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs), 274 fs_nosys, fs_nosys, 275 276 VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync), 277 (fs_generic_func_p) fs_sync, 278 (fs_generic_func_p) fs_sync, /* No errors allowed */ 279 280 VFSNAME_VGET, offsetof(vfsops_t, vfs_vget), 281 fs_nosys, fs_nosys, 282 283 VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot), 284 fs_nosys, fs_nosys, 285 286 VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs), 287 (fs_generic_func_p)(uintptr_t)fs_freevfs, 288 (fs_generic_func_p)(uintptr_t) 289 fs_freevfs, /* Shouldn't fail */ 290 291 VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate), 292 (fs_generic_func_p)fs_nosys, 293 (fs_generic_func_p)fs_nosys, 294 295 NULL, 0, NULL, NULL 296 }; 297 298 return (fs_build_vector(actual, unused_ops, vfs_ops_table, template)); 299 } 300 301 /* zfs_boot_init() */ 302 303 int 304 vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual) 305 { 306 int error; 307 int unused_ops; 308 309 /* 310 * Verify that fstype refers to a valid fs. Note that 311 * 0 is valid since it's used to set "stray" ops. 312 */ 313 if ((fstype < 0) || (fstype >= nfstype)) 314 return (EINVAL); 315 316 if (!ALLOCATED_VFSSW(&vfssw[fstype])) 317 return (EINVAL); 318 319 /* Set up the operations vector. */ 320 321 error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops); 322 323 if (error != 0) 324 return (error); 325 326 vfssw[fstype].vsw_flag |= VSW_INSTALLED; 327 328 if (actual != NULL) 329 *actual = &vfssw[fstype].vsw_vfsops; 330 331 #if DEBUG 332 if (unused_ops != 0) 333 cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied " 334 "but not used", vfssw[fstype].vsw_name, unused_ops); 335 #endif 336 337 return (0); 338 } 339 340 int 341 vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual) 342 { 343 int error; 344 int unused_ops; 345 346 *actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP); 347 348 error = fs_copyfsops(template, *actual, &unused_ops); 349 if (error != 0) { 350 kmem_free(*actual, sizeof (vfsops_t)); 351 *actual = NULL; 352 return (error); 353 } 354 355 return (0); 356 } 357 358 /* 359 * Free a vfsops structure created as a result of vfs_makefsops(). 360 * NOTE: For a vfsops structure initialized by vfs_setfsops(), use 361 * vfs_freevfsops_by_type(). 362 */ 363 void 364 vfs_freevfsops(vfsops_t *vfsops) 365 { 366 kmem_free(vfsops, sizeof (vfsops_t)); 367 } 368 369 /* 370 * Since the vfsops structure is part of the vfssw table and wasn't 371 * really allocated, we're not really freeing anything. We keep 372 * the name for consistency with vfs_freevfsops(). We do, however, 373 * need to take care of a little bookkeeping. 374 * NOTE: For a vfsops structure created by vfs_setfsops(), use 375 * vfs_freevfsops_by_type(). 376 */ 377 int 378 vfs_freevfsops_by_type(int fstype) 379 { 380 381 /* Verify that fstype refers to a loaded fs (and not fsid 0). */ 382 if ((fstype <= 0) || (fstype >= nfstype)) 383 return (EINVAL); 384 385 WLOCK_VFSSW(); 386 if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) { 387 WUNLOCK_VFSSW(); 388 return (EINVAL); 389 } 390 391 vfssw[fstype].vsw_flag &= ~VSW_INSTALLED; 392 WUNLOCK_VFSSW(); 393 394 return (0); 395 } 396 397 /* Support routines used to reference vfs_op */ 398 399 /* Set the operations vector for a vfs */ 400 void 401 vfs_setops(vfs_t *vfsp, vfsops_t *vfsops) 402 { 403 404 ASSERT(vfsp != NULL); 405 ASSERT(vfsops != NULL); 406 407 vfsp->vfs_op = vfsops; 408 } 409 410 /* Retrieve the operations vector for a vfs */ 411 vfsops_t * 412 vfs_getops(vfs_t *vfsp) 413 { 414 415 ASSERT(vfsp != NULL); 416 417 return (vfsp->vfs_op); 418 } 419 420 /* 421 * Returns non-zero (1) if the vfsops matches that of the vfs. 422 * Returns zero (0) if not. 423 */ 424 int 425 vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops) 426 { 427 return (vfs_getops(vfsp) == vfsops); 428 } 429 430 /* 431 * Returns non-zero (1) if the file system has installed a non-default, 432 * non-error vfs_sync routine. Returns zero (0) otherwise. 433 */ 434 int 435 vfs_can_sync(vfs_t *vfsp) 436 { 437 /* vfs_sync() routine is not the default/error function */ 438 return (vfs_getops(vfsp)->vfs_sync != fs_sync); 439 } 440 441 /* 442 * Initialize a vfs structure. 443 */ 444 void 445 vfs_init(vfs_t *vfsp, vfsops_t *op, void *data) 446 { 447 /* Always do full init, like vfs_alloc() */ 448 bzero(vfsp, sizeof (vfs_t)); 449 vfsp->vfs_count = 0; 450 vfsp->vfs_next = vfsp; 451 vfsp->vfs_prev = vfsp; 452 vfsp->vfs_zone_next = vfsp; 453 vfsp->vfs_zone_prev = vfsp; 454 vfsp->vfs_lofi_id = 0; 455 sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL); 456 vfsimpl_setup(vfsp); 457 vfsp->vfs_data = (data); 458 vfs_setops((vfsp), (op)); 459 } 460 461 /* 462 * Allocate and initialize the vfs implementation private data 463 * structure, vfs_impl_t. 464 */ 465 void 466 vfsimpl_setup(vfs_t *vfsp) 467 { 468 int i; 469 470 if (vfsp->vfs_implp != NULL) { 471 return; 472 } 473 474 vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP); 475 /* Note that these are #define'd in vfs.h */ 476 vfsp->vfs_vskap = NULL; 477 vfsp->vfs_fstypevsp = NULL; 478 479 /* Set size of counted array, then zero the array */ 480 vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1; 481 for (i = 1; i < VFS_FEATURE_MAXSZ; i++) { 482 vfsp->vfs_featureset[i] = 0; 483 } 484 } 485 486 /* 487 * Release the vfs_impl_t structure, if it exists. Some unbundled 488 * filesystems may not use the newer version of vfs and thus 489 * would not contain this implementation private data structure. 490 */ 491 void 492 vfsimpl_teardown(vfs_t *vfsp) 493 { 494 vfs_impl_t *vip = vfsp->vfs_implp; 495 496 if (vip == NULL) 497 return; 498 499 kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t)); 500 vfsp->vfs_implp = NULL; 501 } 502 503 /* 504 * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs, 505 * fstatvfs, and sysfs moved to common/syscall. 506 */ 507 508 // vfs_sync, sync 509 510 /* 511 * External routines. 512 */ 513 514 krwlock_t vfssw_lock; /* lock accesses to vfssw */ 515 516 /* 517 * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(), 518 * but otherwise should be accessed only via vfs_list_lock() and 519 * vfs_list_unlock(). Also used to protect the timestamp for mods to the list. 520 */ 521 static krwlock_t vfslist; 522 523 // vfs_mountdevices(void) 524 // vfs_mountdev1(void) 525 // vfs_mountfs() 526 // vfs_mountroot() 527 // lofi_add, lofi_remove 528 529 530 /* 531 * Mount the FS for the test jig. Based on domount() 532 */ 533 int 534 fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp) 535 { 536 vnode_t *vp; 537 struct cred *credp; 538 struct vfssw *vswp; 539 vfsops_t *vfsops; 540 struct vfs *vfsp = NULL; 541 mntopts_t mnt_mntopts; 542 int error = 0; 543 int copyout_error = 0; 544 char *opts = uap->optptr; 545 char *inargs = opts; 546 int optlen = uap->optlen; 547 548 credp = CRED(); 549 550 /* 551 * Test jig specific: mount on rootdir 552 */ 553 if (rootvfs != NULL) 554 return (EBUSY); 555 vp = rootdir; 556 557 /* 558 * The v_flag value for the mount point vp is permanently set 559 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine 560 * for mount point locking. 561 */ 562 mutex_enter(&vp->v_lock); 563 vp->v_flag |= VVFSLOCK; 564 mutex_exit(&vp->v_lock); 565 566 mnt_mntopts.mo_count = 0; 567 568 /* 569 * Find the ops vector to use to invoke the file system-specific mount 570 * method. If the fsname argument is non-NULL, use it directly. 571 */ 572 if ((vswp = vfs_getvfssw(fsname)) == NULL) { 573 return (EINVAL); 574 } 575 if (!VFS_INSTALLED(vswp)) 576 return (EINVAL); 577 578 // secpolicy_fs_allowed_mount(fsname) 579 580 vfsops = &vswp->vsw_vfsops; 581 582 vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts); 583 584 /* 585 * Fetch mount options and parse them for generic vfs options 586 */ 587 if (uap->flags & MS_OPTIONSTR) { 588 /* 589 * Limit the buffer size 590 */ 591 if (optlen < 0 || optlen > MAX_MNTOPT_STR) { 592 error = EINVAL; 593 goto errout; 594 } 595 if ((uap->flags & MS_SYSSPACE) == 0) { 596 inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP); 597 inargs[0] = '\0'; 598 if (optlen) { 599 error = copyinstr(opts, inargs, (size_t)optlen, 600 NULL); 601 if (error) { 602 goto errout; 603 } 604 } 605 } 606 vfs_parsemntopts(&mnt_mntopts, inargs, 0); 607 } 608 /* 609 * Flag bits override the options string. 610 */ 611 if (uap->flags & MS_REMOUNT) 612 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0); 613 if (uap->flags & MS_RDONLY) 614 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0); 615 if (uap->flags & MS_NOSUID) 616 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0); 617 618 /* 619 * Check if this is a remount; must be set in the option string and 620 * the file system must support a remount option. 621 */ 622 if (vfs_optionisset_nolock(&mnt_mntopts, 623 MNTOPT_REMOUNT, NULL)) { 624 /* disallow here */ 625 error = ENOTSUP; 626 goto errout; 627 } 628 629 /* 630 * uap->flags and vfs_optionisset() should agree. 631 */ 632 if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) { 633 uap->flags |= MS_RDONLY; 634 } 635 if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) { 636 uap->flags |= MS_NOSUID; 637 } 638 // nbmand ... 639 640 /* 641 * If we are splicing the fs into the namespace, 642 * perform mount point checks... 643 * (always splice=0 here) 644 */ 645 646 if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) { 647 uap->dataptr = NULL; 648 uap->datalen = 0; 649 } 650 651 /* 652 * If this is a remount, ... (never here) 653 */ 654 vfsp = vfs_alloc(KM_SLEEP); 655 VFS_INIT(vfsp, vfsops, NULL); 656 657 VFS_HOLD(vfsp); 658 659 // lofi_add(fsname, vfsp, &mnt_mntopts, uap) 660 661 /* 662 * PRIV_SYS_MOUNT doesn't mean you can become root. 663 */ 664 uap->flags |= MS_NOSUID; 665 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0); 666 667 /* 668 * The vfs_reflock... 669 */ 670 671 /* 672 * Lock the vfs... 673 */ 674 if ((error = vfs_lock(vfsp)) != 0) { 675 vfs_free(vfsp); 676 vfsp = NULL; 677 goto errout; 678 } 679 680 /* 681 * Add device to mount in progress table... 682 */ 683 /* 684 * Invalidate cached entry for the mount point. 685 */ 686 687 /* 688 * If have an option string but the filesystem doesn't supply a 689 * prototype options table, create a table... 690 */ 691 692 /* 693 * Serialize with zone state transitions... 694 */ 695 696 // mount_in_progress(zone); 697 698 /* 699 * Instantiate (or reinstantiate) the file system... 700 */ 701 vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts); 702 703 vfs_setresource(vfsp, uap->spec, 0); 704 vfs_setmntpoint(vfsp, uap->dir, 0); 705 706 /* 707 * going to mount on this vnode, so notify. 708 */ 709 // vnevent_mountedover(vp, NULL); 710 error = VFS_MOUNT(vfsp, vp, uap, credp); 711 712 if (uap->flags & MS_RDONLY) 713 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 714 if (uap->flags & MS_NOSUID) 715 vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); 716 if (uap->flags & MS_GLOBAL) 717 vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0); 718 719 if (error) { 720 // lofi_remove(vfsp); 721 722 // (remount == 0) 723 vfs_unlock(vfsp); 724 // vfs_freemnttab(vfsp); 725 vfs_free(vfsp); 726 vfsp = NULL; 727 } else { 728 /* 729 * Set the mount time to now 730 */ 731 // vfsp->vfs_mtime = ddi_get_time(); 732 // if (remount) ... 733 // else if (splice) vfs_add(vp, vfsp, flags) 734 // else VFS_HOLD(vfsp); 735 736 /* 737 * Test jig specific: 738 * Do sort of like vfs_add for vp=rootdir 739 * Already have hold on vp. 740 */ 741 vfsp->vfs_vnodecovered = vp; 742 vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES); 743 VFS_HOLD(vfsp); 744 rootvfs = vfsp; 745 746 /* 747 * Set flags for global options encountered 748 */ 749 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) 750 vfsp->vfs_flag |= VFS_RDONLY; 751 else 752 vfsp->vfs_flag &= ~VFS_RDONLY; 753 if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { 754 vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES); 755 } else { 756 if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) 757 vfsp->vfs_flag |= VFS_NODEVICES; 758 else 759 vfsp->vfs_flag &= ~VFS_NODEVICES; 760 if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) 761 vfsp->vfs_flag |= VFS_NOSETUID; 762 else 763 vfsp->vfs_flag &= ~VFS_NOSETUID; 764 } 765 if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) 766 vfsp->vfs_flag |= VFS_NBMAND; 767 else 768 vfsp->vfs_flag &= ~VFS_NBMAND; 769 770 if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) 771 vfsp->vfs_flag |= VFS_XATTR; 772 else 773 vfsp->vfs_flag &= ~VFS_XATTR; 774 775 if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL)) 776 vfsp->vfs_flag |= VFS_NOEXEC; 777 else 778 vfsp->vfs_flag &= ~VFS_NOEXEC; 779 780 /* 781 * Now construct the output option string of options 782 * we recognized. 783 */ 784 if (uap->flags & MS_OPTIONSTR) { 785 vfs_list_read_lock(); 786 copyout_error = vfs_buildoptionstr( 787 &vfsp->vfs_mntopts, inargs, optlen); 788 vfs_list_unlock(); 789 if (copyout_error == 0 && 790 (uap->flags & MS_SYSSPACE) == 0) { 791 copyout_error = copyout(inargs, opts, optlen); 792 } 793 } 794 795 /* 796 * If this isn't a remount, set up the vopstats... 797 */ 798 if (vswp->vsw_flag & VSW_XID) 799 vfsp->vfs_flag |= VFS_XID; 800 801 vfs_unlock(vfsp); 802 803 /* 804 * Test jig specicific: 805 * Replace rootdir with the mounted root. 806 */ 807 error = VFS_ROOT(vfsp, &rootdir); 808 if (error != 0) { 809 panic("fake_domount, get root %d\n", error); 810 } 811 } 812 // mount_completed(zone); 813 // zone_rele(zone); 814 815 // if (splice) 816 // vn_vfsunlock(vp); 817 818 if ((error == 0) && (copyout_error == 0)) { 819 /* get_vskstat_anchor() */ 820 /* Return vfsp to caller. */ 821 *vfspp = vfsp; 822 } 823 errout: 824 vfs_freeopttbl(&mnt_mntopts); 825 /* resource, mountpt not allocated */ 826 /* no addmip, delmip */ 827 ASSERT(vswp != NULL); 828 vfs_unrefvfssw(vswp); 829 if (inargs != opts) 830 kmem_free(inargs, MAX_MNTOPT_STR); 831 if (copyout_error) { 832 if (vfsp != NULL) { 833 // lofi_remove(vfsp); 834 VFS_RELE(vfsp); 835 } 836 error = copyout_error; 837 } 838 return (error); 839 } 840 841 842 static void 843 vfs_setpath( 844 struct vfs *vfsp, /* vfs being updated */ 845 refstr_t **refp, /* Ref-count string to contain the new path */ 846 const char *newpath, /* Path to add to refp (above) */ 847 uint32_t flag) /* flag */ 848 { 849 // size_t len; 850 refstr_t *ref; 851 // char *sp; 852 int have_list_lock = 0; 853 854 ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp)); 855 856 /* 857 * New path must be less than MAXPATHLEN because mntfs 858 * will only display up to MAXPATHLEN bytes. This is currently 859 * safe, because domount() uses pn_get(), and other callers 860 * similarly cap the size to fewer than MAXPATHLEN bytes. 861 */ 862 863 ASSERT(strlen(newpath) < MAXPATHLEN); 864 865 /* mntfs requires consistency while vfs list lock is held */ 866 867 if (VFS_ON_LIST(vfsp)) { 868 have_list_lock = 1; 869 vfs_list_lock(); 870 } 871 872 if (*refp != NULL) 873 refstr_rele(*refp); 874 875 /* 876 * If we are in a non-global zone... (do something else) 877 */ 878 ref = refstr_alloc(newpath); 879 *refp = ref; 880 881 if (have_list_lock) { 882 vfs_mnttab_modtimeupd(); 883 vfs_list_unlock(); 884 } 885 } 886 887 /* 888 * Record a mounted resource name in a vfs structure. 889 * If vfsp is already mounted, caller must hold the vfs lock. 890 */ 891 void 892 vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag) 893 { 894 if (resource == NULL || resource[0] == '\0') 895 resource = VFS_NORESOURCE; 896 vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag); 897 } 898 899 /* 900 * Record a mount point name in a vfs structure. 901 * If vfsp is already mounted, caller must hold the vfs lock. 902 */ 903 void 904 vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag) 905 { 906 if (mntpt == NULL || mntpt[0] == '\0') 907 mntpt = VFS_NOMNTPT; 908 vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag); 909 } 910 911 /* Returns the vfs_resource. Caller must call refstr_rele() when finished. */ 912 913 refstr_t * 914 vfs_getresource(const struct vfs *vfsp) 915 { 916 refstr_t *resource; 917 918 vfs_list_read_lock(); 919 resource = vfsp->vfs_resource; 920 refstr_hold(resource); 921 vfs_list_unlock(); 922 923 return (resource); 924 } 925 926 /* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */ 927 928 refstr_t * 929 vfs_getmntpoint(const struct vfs *vfsp) 930 { 931 refstr_t *mntpt; 932 933 vfs_list_read_lock(); 934 mntpt = vfsp->vfs_mntpt; 935 refstr_hold(mntpt); 936 vfs_list_unlock(); 937 938 return (mntpt); 939 } 940 941 // vfs_createopttbl_extend 942 // vfs_createopttbl 943 944 /* 945 * Swap two mount options tables 946 */ 947 static void 948 vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2) 949 { 950 uint_t tmpcnt; 951 mntopt_t *tmplist; 952 953 tmpcnt = optbl2->mo_count; 954 tmplist = optbl2->mo_list; 955 optbl2->mo_count = optbl1->mo_count; 956 optbl2->mo_list = optbl1->mo_list; 957 optbl1->mo_count = tmpcnt; 958 optbl1->mo_list = tmplist; 959 } 960 961 static void 962 vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2) 963 { 964 vfs_list_lock(); 965 vfs_swapopttbl_nolock(optbl1, optbl2); 966 vfs_mnttab_modtimeupd(); 967 vfs_list_unlock(); 968 } 969 970 static char ** 971 vfs_copycancelopt_extend(char **const moc, int extend) 972 { 973 int i = 0; 974 int j; 975 char **result; 976 977 if (moc != NULL) { 978 for (; moc[i] != NULL; i++) 979 /* count number of options to cancel */; 980 } 981 982 if (i + extend == 0) 983 return (NULL); 984 985 result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP); 986 987 for (j = 0; j < i; j++) { 988 result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP); 989 (void) strcpy(result[j], moc[j]); 990 } 991 for (; j <= i + extend; j++) 992 result[j] = NULL; 993 994 return (result); 995 } 996 997 static void 998 vfs_copyopt(const mntopt_t *s, mntopt_t *d) 999 { 1000 char *sp, *dp; 1001 1002 d->mo_flags = s->mo_flags; 1003 d->mo_data = s->mo_data; 1004 sp = s->mo_name; 1005 if (sp != NULL) { 1006 dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP); 1007 (void) strcpy(dp, sp); 1008 d->mo_name = dp; 1009 } else { 1010 d->mo_name = NULL; /* should never happen */ 1011 } 1012 1013 d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0); 1014 1015 sp = s->mo_arg; 1016 if (sp != NULL) { 1017 dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP); 1018 (void) strcpy(dp, sp); 1019 d->mo_arg = dp; 1020 } else { 1021 d->mo_arg = NULL; 1022 } 1023 } 1024 1025 // vfs_copyopttbl_extend 1026 // vfs_copyopttbl 1027 1028 /* 1029 * Copy a mount options table, possibly allocating some spare 1030 * slots at the end. It is permissible to copy_extend the NULL table. 1031 */ 1032 static void 1033 vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra) 1034 { 1035 uint_t i, count; 1036 mntopt_t *motbl; 1037 1038 /* 1039 * Clear out any existing stuff in the options table being initialized 1040 */ 1041 vfs_freeopttbl(dmo); 1042 count = (smo == NULL) ? 0 : smo->mo_count; 1043 if ((count + extra) == 0) /* nothing to do */ 1044 return; 1045 dmo->mo_count = count + extra; 1046 motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP); 1047 dmo->mo_list = motbl; 1048 for (i = 0; i < count; i++) { 1049 vfs_copyopt(&smo->mo_list[i], &motbl[i]); 1050 } 1051 for (i = count; i < count + extra; i++) { 1052 motbl[i].mo_flags = MO_EMPTY; 1053 } 1054 } 1055 1056 /* 1057 * Copy a mount options table. 1058 * 1059 * This function is *not* for general use by filesystems. 1060 * 1061 * Note: caller is responsible for locking the vfs list, if needed, 1062 * to protect smo and dmo. 1063 */ 1064 void 1065 vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo) 1066 { 1067 vfs_copyopttbl_extend(smo, dmo, 0); 1068 } 1069 1070 static char ** 1071 vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2) 1072 { 1073 int c1 = 0; 1074 int c2 = 0; 1075 char **result; 1076 char **sp1, **sp2, **dp; 1077 1078 /* 1079 * First we count both lists of cancel options. 1080 * If either is NULL or has no elements, we return a copy of 1081 * the other. 1082 */ 1083 if (mop1->mo_cancel != NULL) { 1084 for (; mop1->mo_cancel[c1] != NULL; c1++) 1085 /* count cancel options in mop1 */; 1086 } 1087 1088 if (c1 == 0) 1089 return (vfs_copycancelopt_extend(mop2->mo_cancel, 0)); 1090 1091 if (mop2->mo_cancel != NULL) { 1092 for (; mop2->mo_cancel[c2] != NULL; c2++) 1093 /* count cancel options in mop2 */; 1094 } 1095 1096 result = vfs_copycancelopt_extend(mop1->mo_cancel, c2); 1097 1098 if (c2 == 0) 1099 return (result); 1100 1101 /* 1102 * When we get here, we've got two sets of cancel options; 1103 * we need to merge the two sets. We know that the result 1104 * array has "c1+c2+1" entries and in the end we might shrink 1105 * it. 1106 * Result now has a copy of the c1 entries from mop1; we'll 1107 * now lookup all the entries of mop2 in mop1 and copy it if 1108 * it is unique. 1109 * This operation is O(n^2) but it's only called once per 1110 * filesystem per duplicate option. This is a situation 1111 * which doesn't arise with the filesystems in ON and 1112 * n is generally 1. 1113 */ 1114 1115 dp = &result[c1]; 1116 for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) { 1117 for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) { 1118 if (strcmp(*sp1, *sp2) == 0) 1119 break; 1120 } 1121 if (*sp1 == NULL) { 1122 /* 1123 * Option *sp2 not found in mop1, so copy it. 1124 * The calls to vfs_copycancelopt_extend() 1125 * guarantee that there's enough room. 1126 */ 1127 *dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP); 1128 (void) strcpy(*dp++, *sp2); 1129 } 1130 } 1131 if (dp != &result[c1+c2]) { 1132 size_t bytes = (dp - result + 1) * sizeof (char *); 1133 char **nres = kmem_alloc(bytes, KM_SLEEP); 1134 1135 bcopy(result, nres, bytes); 1136 kmem_free(result, (c1 + c2 + 1) * sizeof (char *)); 1137 result = nres; 1138 } 1139 return (result); 1140 } 1141 1142 /* 1143 * Merge two mount option tables (outer and inner) into one. This is very 1144 * similar to "merging" global variables and automatic variables in C. 1145 * 1146 * This isn't (and doesn't have to be) fast. 1147 * 1148 * This function is *not* for general use by filesystems. 1149 * 1150 * Note: caller is responsible for locking the vfs list, if needed, 1151 * to protect omo, imo & dmo. 1152 */ 1153 void 1154 vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo) 1155 { 1156 uint_t i, count; 1157 mntopt_t *mop, *motbl; 1158 uint_t freeidx; 1159 1160 /* 1161 * First determine how much space we need to allocate. 1162 */ 1163 count = omo->mo_count; 1164 for (i = 0; i < imo->mo_count; i++) { 1165 if (imo->mo_list[i].mo_flags & MO_EMPTY) 1166 continue; 1167 if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL) 1168 count++; 1169 } 1170 ASSERT(count >= omo->mo_count && 1171 count <= omo->mo_count + imo->mo_count); 1172 motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP); 1173 for (i = 0; i < omo->mo_count; i++) 1174 vfs_copyopt(&omo->mo_list[i], &motbl[i]); 1175 freeidx = omo->mo_count; 1176 for (i = 0; i < imo->mo_count; i++) { 1177 if (imo->mo_list[i].mo_flags & MO_EMPTY) 1178 continue; 1179 if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) { 1180 char **newcanp; 1181 uint_t index = mop - omo->mo_list; 1182 1183 newcanp = vfs_mergecancelopts(mop, &motbl[index]); 1184 1185 vfs_freeopt(&motbl[index]); 1186 vfs_copyopt(&imo->mo_list[i], &motbl[index]); 1187 1188 vfs_freecancelopt(motbl[index].mo_cancel); 1189 motbl[index].mo_cancel = newcanp; 1190 } else { 1191 /* 1192 * If it's a new option, just copy it over to the first 1193 * free location. 1194 */ 1195 vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]); 1196 } 1197 } 1198 dmo->mo_count = count; 1199 dmo->mo_list = motbl; 1200 } 1201 1202 /* 1203 * Functions to set and clear mount options in a mount options table. 1204 */ 1205 1206 /* 1207 * Clear a mount option, if it exists. 1208 * 1209 * The update_mnttab arg indicates whether mops is part of a vfs that is on 1210 * the vfs list. 1211 */ 1212 static void 1213 vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab) 1214 { 1215 struct mntopt *mop; 1216 uint_t i, count; 1217 1218 ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist)); 1219 1220 count = mops->mo_count; 1221 for (i = 0; i < count; i++) { 1222 mop = &mops->mo_list[i]; 1223 1224 if (mop->mo_flags & MO_EMPTY) 1225 continue; 1226 if (strcmp(opt, mop->mo_name)) 1227 continue; 1228 mop->mo_flags &= ~MO_SET; 1229 if (mop->mo_arg != NULL) { 1230 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); 1231 } 1232 mop->mo_arg = NULL; 1233 if (update_mnttab) 1234 vfs_mnttab_modtimeupd(); 1235 break; 1236 } 1237 } 1238 1239 void 1240 vfs_clearmntopt(struct vfs *vfsp, const char *opt) 1241 { 1242 int gotlock = 0; 1243 1244 if (VFS_ON_LIST(vfsp)) { 1245 gotlock = 1; 1246 vfs_list_lock(); 1247 } 1248 vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock); 1249 if (gotlock) 1250 vfs_list_unlock(); 1251 } 1252 1253 1254 /* 1255 * Set a mount option on... 1256 */ 1257 static void 1258 vfs_setmntopt_nolock(mntopts_t *mops, const char *opt, 1259 const char *arg, int flags, int update_mnttab) 1260 { 1261 mntopt_t *mop; 1262 uint_t i, count; 1263 char *sp; 1264 1265 ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist)); 1266 1267 if (flags & VFS_CREATEOPT) { 1268 if (vfs_hasopt(mops, opt) != NULL) { 1269 flags &= ~VFS_CREATEOPT; 1270 } 1271 } 1272 count = mops->mo_count; 1273 for (i = 0; i < count; i++) { 1274 mop = &mops->mo_list[i]; 1275 1276 if (mop->mo_flags & MO_EMPTY) { 1277 if ((flags & VFS_CREATEOPT) == 0) 1278 continue; 1279 sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP); 1280 (void) strcpy(sp, opt); 1281 mop->mo_name = sp; 1282 if (arg != NULL) 1283 mop->mo_flags = MO_HASVALUE; 1284 else 1285 mop->mo_flags = 0; 1286 } else if (strcmp(opt, mop->mo_name)) { 1287 continue; 1288 } 1289 if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT)) 1290 break; 1291 if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) { 1292 sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP); 1293 (void) strcpy(sp, arg); 1294 } else { 1295 sp = NULL; 1296 } 1297 if (mop->mo_arg != NULL) 1298 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); 1299 mop->mo_arg = sp; 1300 if (flags & VFS_DISPLAY) 1301 mop->mo_flags &= ~MO_NODISPLAY; 1302 if (flags & VFS_NODISPLAY) 1303 mop->mo_flags |= MO_NODISPLAY; 1304 mop->mo_flags |= MO_SET; 1305 if (mop->mo_cancel != NULL) { 1306 char **cp; 1307 1308 for (cp = mop->mo_cancel; *cp != NULL; cp++) 1309 vfs_clearmntopt_nolock(mops, *cp, 0); 1310 } 1311 if (update_mnttab) 1312 vfs_mnttab_modtimeupd(); 1313 break; 1314 } 1315 } 1316 1317 void 1318 vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags) 1319 { 1320 int gotlock = 0; 1321 1322 if (VFS_ON_LIST(vfsp)) { 1323 gotlock = 1; 1324 vfs_list_lock(); 1325 } 1326 vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock); 1327 if (gotlock) 1328 vfs_list_unlock(); 1329 } 1330 1331 // vfs_addtag 1332 // vfs_settag 1333 // vfs_clrtag 1334 1335 /* 1336 * Function to parse an option string and fill in a mount options table. 1337 * Unknown options are silently ignored. The input option string is modified 1338 * by replacing separators with nulls. If the create flag is set, options 1339 * not found in the table are just added on the fly. The table must have 1340 * an option slot marked MO_EMPTY to add an option on the fly. 1341 * 1342 * This function is *not* for general use by filesystems. 1343 * 1344 * Note: caller is responsible for locking the vfs list, if needed, 1345 * to protect mops.. 1346 */ 1347 void 1348 vfs_parsemntopts(mntopts_t *mops, char *osp, int create) 1349 { 1350 char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL; 1351 int setflg = VFS_NOFORCEOPT; 1352 1353 if (osp == NULL) 1354 return; 1355 while (*s != '\0') { 1356 p = strchr(s, ','); /* find next option */ 1357 if (p == NULL) { 1358 cp = NULL; 1359 p = s + strlen(s); 1360 } else { 1361 cp = p; /* save location of comma */ 1362 *p++ = '\0'; /* mark end and point to next option */ 1363 } 1364 nextop = p; 1365 p = strchr(s, '='); /* look for value */ 1366 if (p == NULL) { 1367 valp = NULL; /* no value supplied */ 1368 ep = NULL; 1369 } else { 1370 ep = p; /* save location of equals */ 1371 *p++ = '\0'; /* end option and point to value */ 1372 valp = p; 1373 } 1374 /* 1375 * set option into options table 1376 */ 1377 if (create) 1378 setflg |= VFS_CREATEOPT; 1379 vfs_setmntopt_nolock(mops, s, valp, setflg, 0); 1380 if (cp != NULL) 1381 *cp = ','; /* restore the comma */ 1382 if (valp != NULL) 1383 *ep = '='; /* restore the equals */ 1384 s = nextop; 1385 } 1386 } 1387 1388 /* 1389 * Function to inquire if an option exists in a mount options table. 1390 * Returns a pointer to the option if it exists, else NULL. 1391 */ 1392 struct mntopt * 1393 vfs_hasopt(const mntopts_t *mops, const char *opt) 1394 { 1395 struct mntopt *mop; 1396 uint_t i, count; 1397 1398 count = mops->mo_count; 1399 for (i = 0; i < count; i++) { 1400 mop = &mops->mo_list[i]; 1401 1402 if (mop->mo_flags & MO_EMPTY) 1403 continue; 1404 if (strcmp(opt, mop->mo_name) == 0) 1405 return (mop); 1406 } 1407 return (NULL); 1408 } 1409 1410 /* 1411 * Function to inquire if an option is set in a mount options table. 1412 * Returns non-zero if set and fills in the arg pointer with a pointer to 1413 * the argument string or NULL if there is no argument string. 1414 */ 1415 static int 1416 vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp) 1417 { 1418 struct mntopt *mop; 1419 uint_t i, count; 1420 1421 count = mops->mo_count; 1422 for (i = 0; i < count; i++) { 1423 mop = &mops->mo_list[i]; 1424 1425 if (mop->mo_flags & MO_EMPTY) 1426 continue; 1427 if (strcmp(opt, mop->mo_name)) 1428 continue; 1429 if ((mop->mo_flags & MO_SET) == 0) 1430 return (0); 1431 if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0) 1432 *argp = mop->mo_arg; 1433 return (1); 1434 } 1435 return (0); 1436 } 1437 1438 1439 int 1440 vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp) 1441 { 1442 int ret; 1443 1444 vfs_list_read_lock(); 1445 ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp); 1446 vfs_list_unlock(); 1447 return (ret); 1448 } 1449 1450 1451 /* 1452 * Construct a comma separated string of the options set in the given 1453 * mount table, return the string in the given buffer. Return non-zero if 1454 * the buffer would overflow. 1455 * 1456 * This function is *not* for general use by filesystems. 1457 * 1458 * Note: caller is responsible for locking the vfs list, if needed, 1459 * to protect mp. 1460 */ 1461 int 1462 vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len) 1463 { 1464 char *cp; 1465 uint_t i; 1466 1467 buf[0] = '\0'; 1468 cp = buf; 1469 for (i = 0; i < mp->mo_count; i++) { 1470 struct mntopt *mop; 1471 1472 mop = &mp->mo_list[i]; 1473 if (mop->mo_flags & MO_SET) { 1474 int optlen, comma = 0; 1475 1476 if (buf[0] != '\0') 1477 comma = 1; 1478 optlen = strlen(mop->mo_name); 1479 if (strlen(buf) + comma + optlen + 1 > len) 1480 goto err; 1481 if (comma) 1482 *cp++ = ','; 1483 (void) strcpy(cp, mop->mo_name); 1484 cp += optlen; 1485 /* 1486 * Append option value if there is one 1487 */ 1488 if (mop->mo_arg != NULL) { 1489 int arglen; 1490 1491 arglen = strlen(mop->mo_arg); 1492 if (strlen(buf) + arglen + 2 > len) 1493 goto err; 1494 *cp++ = '='; 1495 (void) strcpy(cp, mop->mo_arg); 1496 cp += arglen; 1497 } 1498 } 1499 } 1500 return (0); 1501 err: 1502 return (EOVERFLOW); 1503 } 1504 1505 static void 1506 vfs_freecancelopt(char **moc) 1507 { 1508 if (moc != NULL) { 1509 int ccnt = 0; 1510 char **cp; 1511 1512 for (cp = moc; *cp != NULL; cp++) { 1513 kmem_free(*cp, strlen(*cp) + 1); 1514 ccnt++; 1515 } 1516 kmem_free(moc, (ccnt + 1) * sizeof (char *)); 1517 } 1518 } 1519 1520 static void 1521 vfs_freeopt(mntopt_t *mop) 1522 { 1523 if (mop->mo_name != NULL) 1524 kmem_free(mop->mo_name, strlen(mop->mo_name) + 1); 1525 1526 vfs_freecancelopt(mop->mo_cancel); 1527 1528 if (mop->mo_arg != NULL) 1529 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); 1530 } 1531 1532 /* 1533 * Free a mount options table 1534 * 1535 * This function is *not* for general use by filesystems. 1536 * 1537 * Note: caller is responsible for locking the vfs list, if needed, 1538 * to protect mp. 1539 */ 1540 void 1541 vfs_freeopttbl(mntopts_t *mp) 1542 { 1543 uint_t i, count; 1544 1545 count = mp->mo_count; 1546 for (i = 0; i < count; i++) { 1547 vfs_freeopt(&mp->mo_list[i]); 1548 } 1549 if (count) { 1550 kmem_free(mp->mo_list, sizeof (mntopt_t) * count); 1551 mp->mo_count = 0; 1552 mp->mo_list = NULL; 1553 } 1554 } 1555 1556 // vfs_mntdummyread 1557 // vfs_mntdummywrite 1558 // vfs_mntdummygetattr 1559 // vfs_mnttabvp_setup 1560 // vfs_mnttab_rwop 1561 // vfs_mnttab_writeop 1562 // vfs_mnttab_readop 1563 // vfs_freemnttab 1564 // vfs_mnttab_modtime 1565 // vfs_mnttab_poll 1566 // vfs_mono_time 1567 1568 /* 1569 * Update the mnttab modification time... 1570 */ 1571 void 1572 vfs_mnttab_modtimeupd() 1573 { 1574 } 1575 1576 /* 1577 * Unlike the real dounmount, we don't have 1578 * vn_vfswlock_held(coveredvp) 1579 */ 1580 int 1581 fake_dounmount(struct vfs *vfsp, int flag) 1582 { 1583 cred_t *cr = CRED(); 1584 vnode_t *coveredvp; 1585 int error; 1586 1587 /* 1588 * Get covered vnode. This will be NULL if the vfs is not linked 1589 * into the file system name space (i.e., domount() with MNT_NOSPICE). 1590 */ 1591 coveredvp = vfsp->vfs_vnodecovered; 1592 1593 /* For forcible umount, skip VFS_SYNC() since it may hang */ 1594 if ((flag & MS_FORCE) == 0) 1595 (void) VFS_SYNC(vfsp, 0, cr); 1596 1597 /* 1598 * Test-jig specific: 1599 * Need to release rootdir before unmount or VFS_UNMOUNT 1600 * may fail due to that node being active. 1601 */ 1602 if (rootdir != NULL) { 1603 ASSERT(rootdir != coveredvp); 1604 VN_RELE(rootdir); 1605 rootdir = NULL; 1606 } 1607 1608 /* 1609 * Lock the vfs to maintain fs status quo during unmount. This 1610 * has to be done after the sync because ufs_update tries to acquire 1611 * the vfs_reflock. 1612 */ 1613 vfs_lock_wait(vfsp); 1614 1615 if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) { 1616 int err2; 1617 vfs_unlock(vfsp); 1618 /* Get rootdir back */ 1619 err2 = VFS_ROOT(vfsp, &rootdir); 1620 if (err2 != 0) { 1621 panic("fake_dounmount, get root %d\n", err2); 1622 } 1623 } else { 1624 /* 1625 * Real dounmount does vfs_remove. 1626 * 1627 * Test-jig specific: 1628 * Restore the covered rootdir, 1629 * release the rootvfs hold and clear. 1630 */ 1631 if (coveredvp != NULL) { 1632 // vfs_list_remove(vfsp); 1633 vfsp->vfs_vnodecovered = NULL; 1634 rootdir = coveredvp; 1635 } 1636 if (rootvfs == vfsp) { 1637 VFS_RELE(vfsp); 1638 rootvfs = NULL; 1639 } 1640 1641 /* 1642 * Release the (final) reference to vfs 1643 */ 1644 vfs_unlock(vfsp); 1645 VFS_RELE(vfsp); 1646 } 1647 return (error); 1648 } 1649 1650 // vfs_unmountall(void) 1651 // vfs_addmip 1652 // vfs_delmip 1653 // vfs_add 1654 // vfs_remove 1655 1656 static krwlock_t vpvfsentry_ve_lock; 1657 1658 /* 1659 * Lock a filesystem to prevent access to it while mounting, 1660 * unmounting and syncing. Return EBUSY immediately if lock 1661 * can't be acquired. 1662 */ 1663 int 1664 vfs_lock(vfs_t *vfsp) 1665 { 1666 1667 if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER)) 1668 return (0); 1669 1670 return (EBUSY); 1671 } 1672 1673 int 1674 vfs_rlock(vfs_t *vfsp) 1675 { 1676 1677 if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER)) 1678 return (0); 1679 1680 return (EBUSY); 1681 } 1682 1683 void 1684 vfs_lock_wait(vfs_t *vfsp) 1685 { 1686 1687 rw_enter(&vpvfsentry_ve_lock, RW_WRITER); 1688 } 1689 1690 void 1691 vfs_rlock_wait(vfs_t *vfsp) 1692 { 1693 rw_enter(&vpvfsentry_ve_lock, RW_READER); 1694 } 1695 1696 /* 1697 * Unlock a locked filesystem. 1698 */ 1699 void 1700 vfs_unlock(vfs_t *vfsp) 1701 { 1702 1703 rw_exit(&vpvfsentry_ve_lock); 1704 } 1705 1706 /* 1707 * Utility routine that allows a filesystem to construct its 1708 * fsid in "the usual way" - by munging some underlying dev_t and 1709 * the filesystem type number into the 64-bit fsid. ... 1710 */ 1711 void 1712 vfs_make_fsid(fsid_t *fsi, dev_t dev, int val) 1713 { 1714 if (!cmpldev((dev32_t *)&fsi->val[0], dev)) 1715 panic("device number too big for fsid!"); 1716 fsi->val[1] = val; 1717 } 1718 1719 int 1720 vfs_lock_held(vfs_t *vfsp) 1721 { 1722 int held; 1723 1724 held = rw_write_held(&vpvfsentry_ve_lock); 1725 1726 return (held); 1727 } 1728 1729 // vfs_lock_owner 1730 1731 /* 1732 * vfs list locking. 1733 */ 1734 1735 void 1736 vfs_list_lock() 1737 { 1738 rw_enter(&vfslist, RW_WRITER); 1739 } 1740 1741 void 1742 vfs_list_read_lock() 1743 { 1744 rw_enter(&vfslist, RW_READER); 1745 } 1746 1747 void 1748 vfs_list_unlock() 1749 { 1750 rw_exit(&vfslist); 1751 } 1752 1753 /* 1754 * Low level worker routines for adding entries to and removing entries from 1755 * the vfs list. 1756 */ 1757 1758 // vfs_hash_add 1759 // vfs_hash_remove 1760 // vfs_list_add 1761 // vfs_list_remove 1762 // getvfs 1763 // vfs_devmounting 1764 1765 /* 1766 * Search the vfs list for a specified device. Returns 1, if entry is found 1767 * or 0 if no suitable entry is found. 1768 */ 1769 1770 int 1771 vfs_devismounted(dev_t dev) 1772 { 1773 return (0); 1774 } 1775 1776 // vfs_dev2vfsp 1777 // vfs_mntpoint2vfsp 1778 1779 /* 1780 * Search the vfs list for a specified vfsops. 1781 * if vfs entry is found then return 1, else 0. 1782 */ 1783 int 1784 vfs_opsinuse(vfsops_t *ops) 1785 { 1786 return (0); 1787 } 1788 1789 /* 1790 * Allocate an entry in vfssw for a file system type 1791 */ 1792 struct vfssw * 1793 allocate_vfssw(const char *type) 1794 { 1795 struct vfssw *vswp; 1796 1797 if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) { 1798 /* 1799 * The vfssw table uses the empty string to identify an 1800 * available entry; we cannot add any type which has 1801 * a leading NUL. The string length is limited to 1802 * the size of the st_fstype array in struct stat. 1803 */ 1804 return (NULL); 1805 } 1806 1807 ASSERT(VFSSW_WRITE_LOCKED()); 1808 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) 1809 if (!ALLOCATED_VFSSW(vswp)) { 1810 vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP); 1811 (void) strcpy(vswp->vsw_name, type); 1812 ASSERT(vswp->vsw_count == 0); 1813 vswp->vsw_count = 1; 1814 mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL); 1815 return (vswp); 1816 } 1817 return (NULL); 1818 } 1819 1820 // vfs_to_modname 1821 // vfs_getvfssw 1822 1823 /* 1824 * Find a vfssw entry given a file system type name. 1825 */ 1826 struct vfssw * 1827 vfs_getvfssw(const char *type) 1828 { 1829 struct vfssw *vswp; 1830 1831 if (type == NULL || *type == '\0') 1832 return (NULL); 1833 1834 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { 1835 if (strcmp(type, vswp->vsw_name) == 0) { 1836 return (vswp); 1837 } 1838 } 1839 1840 return (NULL); 1841 1842 } 1843 1844 /* 1845 * Find a vfssw entry given a file system type name. 1846 */ 1847 struct vfssw * 1848 vfs_getvfsswbyname(const char *type) 1849 { 1850 struct vfssw *vswp; 1851 1852 ASSERT(VFSSW_LOCKED()); 1853 if (type == NULL || *type == '\0') 1854 return (NULL); 1855 1856 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { 1857 if (strcmp(type, vswp->vsw_name) == 0) { 1858 vfs_refvfssw(vswp); 1859 return (vswp); 1860 } 1861 } 1862 1863 return (NULL); 1864 } 1865 1866 // vfs_getvfsswbyvfsops 1867 1868 /* 1869 * Reference a vfssw entry. 1870 */ 1871 void 1872 vfs_refvfssw(struct vfssw *vswp) 1873 { 1874 1875 mutex_enter(&vswp->vsw_lock); 1876 vswp->vsw_count++; 1877 mutex_exit(&vswp->vsw_lock); 1878 } 1879 1880 /* 1881 * Unreference a vfssw entry. 1882 */ 1883 void 1884 vfs_unrefvfssw(struct vfssw *vswp) 1885 { 1886 1887 mutex_enter(&vswp->vsw_lock); 1888 vswp->vsw_count--; 1889 mutex_exit(&vswp->vsw_lock); 1890 } 1891 1892 // vfs_syncall 1893 1894 /* 1895 * Map VFS flags to statvfs flags. These shouldn't really be separate 1896 * flags at all. 1897 */ 1898 uint_t 1899 vf_to_stf(uint_t vf) 1900 { 1901 uint_t stf = 0; 1902 1903 if (vf & VFS_RDONLY) 1904 stf |= ST_RDONLY; 1905 if (vf & VFS_NOSETUID) 1906 stf |= ST_NOSUID; 1907 if (vf & VFS_NOTRUNC) 1908 stf |= ST_NOTRUNC; 1909 1910 return (stf); 1911 } 1912 1913 // vfsstray_sync 1914 // vfsstray 1915 // vfs_EIO 1916 // vfs_EIO_sync 1917 // EIO_vfs 1918 // EIO_vfsops 1919 1920 #pragma init(vfsinit) 1921 1922 /* 1923 * Called from startup() to initialize all loaded vfs's 1924 */ 1925 void 1926 vfsinit(void) 1927 { 1928 vn_create_cache(); 1929 1930 /* Temporary, until we mount root */ 1931 rootdir = vn_alloc(KM_SLEEP); 1932 rootdir->v_type = VDIR; 1933 } 1934 1935 vfs_t * 1936 vfs_alloc(int kmflag) 1937 { 1938 vfs_t *vfsp; 1939 1940 vfsp = kmem_alloc(sizeof (struct vfs), kmflag); 1941 1942 /* 1943 * Do the simplest initialization here. 1944 * Everything else gets done in vfs_init() 1945 */ 1946 bzero(vfsp, sizeof (vfs_t)); 1947 return (vfsp); 1948 } 1949 1950 void 1951 vfs_free(vfs_t *vfsp) 1952 { 1953 /* 1954 * One would be tempted to assert that "vfsp->vfs_count == 0". 1955 * Don't. See fs/vfs.c 1956 */ 1957 1958 /* If FEM was in use, make sure everything gets cleaned up */ 1959 1960 if (vfsp->vfs_implp) 1961 vfsimpl_teardown(vfsp); 1962 sema_destroy(&vfsp->vfs_reflock); 1963 kmem_free(vfsp, sizeof (struct vfs)); 1964 } 1965 1966 /* 1967 * Increments the vfs reference count by one atomically. 1968 */ 1969 void 1970 vfs_hold(vfs_t *vfsp) 1971 { 1972 atomic_inc_32(&vfsp->vfs_count); 1973 ASSERT(vfsp->vfs_count != 0); 1974 } 1975 1976 /* 1977 * Decrements the vfs reference count by one atomically. When 1978 * vfs reference count becomes zero, it calls the file system 1979 * specific vfs_freevfs() to free up the resources. 1980 */ 1981 void 1982 vfs_rele(vfs_t *vfsp) 1983 { 1984 ASSERT(vfsp->vfs_count != 0); 1985 if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) { 1986 VFS_FREEVFS(vfsp); 1987 // lofi_remove(vfsp); 1988 // zone_rele_ref... 1989 // vfs_freemnttab(vfsp); 1990 vfs_free(vfsp); 1991 } 1992 } 1993 1994 /* 1995 * Generic operations vector support. 1996 */ 1997 1998 int 1999 fs_build_vector(void *vector, int *unused_ops, 2000 const fs_operation_trans_def_t *translation, 2001 const fs_operation_def_t *operations) 2002 { 2003 int i, num_trans, num_ops, used; 2004 2005 /* 2006 * Count the number of translations and the number of supplied 2007 * operations. 2008 */ 2009 2010 { 2011 const fs_operation_trans_def_t *p; 2012 2013 for (num_trans = 0, p = translation; 2014 p->name != NULL; 2015 num_trans++, p++) 2016 ; 2017 } 2018 2019 { 2020 const fs_operation_def_t *p; 2021 2022 for (num_ops = 0, p = operations; 2023 p->name != NULL; 2024 num_ops++, p++) 2025 ; 2026 } 2027 2028 /* Walk through each operation known to our caller. There will be */ 2029 /* one entry in the supplied "translation table" for each. */ 2030 2031 used = 0; 2032 2033 for (i = 0; i < num_trans; i++) { 2034 int j, found; 2035 char *curname; 2036 fs_generic_func_p result; 2037 fs_generic_func_p *location; 2038 2039 curname = translation[i].name; 2040 2041 /* Look for a matching operation in the list supplied by the */ 2042 /* file system. */ 2043 2044 found = 0; 2045 2046 for (j = 0; j < num_ops; j++) { 2047 if (strcmp(operations[j].name, curname) == 0) { 2048 used++; 2049 found = 1; 2050 break; 2051 } 2052 } 2053 2054 /* 2055 * If the file system is using a "placeholder" for default 2056 * or error functions, grab the appropriate function out of 2057 * the translation table. If the file system didn't supply 2058 * this operation at all, use the default function. 2059 */ 2060 2061 if (found) { 2062 result = operations[j].func.fs_generic; 2063 if (result == fs_default) { 2064 result = translation[i].defaultFunc; 2065 } else if (result == fs_error) { 2066 result = translation[i].errorFunc; 2067 } else if (result == NULL) { 2068 /* Null values are PROHIBITED */ 2069 return (EINVAL); 2070 } 2071 } else { 2072 result = translation[i].defaultFunc; 2073 } 2074 2075 /* Now store the function into the operations vector. */ 2076 2077 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2078 location = (fs_generic_func_p *) 2079 (((char *)vector) + translation[i].offset); 2080 2081 *location = result; 2082 } 2083 2084 *unused_ops = num_ops - used; 2085 2086 return (0); 2087 } 2088 2089 /* Placeholder functions, should never be called. */ 2090 2091 int 2092 fs_error(void) 2093 { 2094 cmn_err(CE_PANIC, "fs_error called"); 2095 return (0); 2096 } 2097 2098 int 2099 fs_default(void) 2100 { 2101 cmn_err(CE_PANIC, "fs_default called"); 2102 return (0); 2103 } 2104 2105 // rootconf 2106 // getfsname 2107 // getrootfs 2108 2109 /* 2110 * VFS feature routines 2111 */ 2112 2113 #define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF) 2114 #define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL) 2115 2116 /* Register a feature in the vfs */ 2117 void 2118 vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature) 2119 { 2120 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ 2121 if (vfsp->vfs_implp == NULL) 2122 return; 2123 2124 vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature); 2125 } 2126 2127 void 2128 vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature) 2129 { 2130 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ 2131 if (vfsp->vfs_implp == NULL) 2132 return; 2133 vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature); 2134 } 2135 2136 /* 2137 * Query a vfs for a feature. 2138 * Returns 1 if feature is present, 0 if not 2139 */ 2140 int 2141 vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature) 2142 { 2143 int ret = 0; 2144 2145 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ 2146 if (vfsp->vfs_implp == NULL) 2147 return (ret); 2148 2149 if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature)) 2150 ret = 1; 2151 2152 return (ret); 2153 } 2154 2155 // vfs_propagate_features 2156 // vfs_get_lofi 2157