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