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