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
90static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
91static void vfs_setmntopt_nolock(mntopts_t *, const char *,
92    const char *, int, int);
93static int  vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
94// static void vfs_freemnttab(struct vfs *);
95static void vfs_freeopt(mntopt_t *);
96static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
97static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
98static 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);
102static void vfs_freecancelopt(char **);
103
104/*
105 * VFS global data.
106 */
107vnode_t *rootdir;		/* pointer to root inode vnode. */
108struct vfs *rootvfs = NULL;	/* pointer to root vfs; head of VFS list. */
109static krwlock_t vfslist;
110struct vfs	*zone_vfslist;	/* list of FS's mounted in zone */
111
112/* from os/vfs_conf.c */
113const int nfstype = 5;
114struct 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 */
134static char *ro_cancel[] = { MNTOPT_RW, NULL };
135static char *rw_cancel[] = { MNTOPT_RO, NULL };
136static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
137static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
138    MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
139static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
140static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
141static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
142static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
143static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
144static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
145static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
146static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
147
148static 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
180const 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
189int
190fsop_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
195int
196fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
197{
198	return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
199}
200
201int
202fsop_root(vfs_t *vfsp, vnode_t **vpp)
203{
204	return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
205}
206
207int
208fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
209{
210	return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
211}
212
213int
214fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
215{
216	return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
217}
218
219int
220fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
221{
222	return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
223}
224
225int
226fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
227{
228	return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
229}
230
231void
232fsop_freefs(vfs_t *vfsp)
233{
234	(*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
235}
236
237int
238fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
239{
240	return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
241}
242
243int
244fsop_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
259static int
260fs_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
302int
303vfs_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
339int
340vfs_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 */
362void
363vfs_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 */
376int
377vfs_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 */
399void
400vfs_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 */
410vfsops_t *
411vfs_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 */
423int
424vfs_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 */
433int
434vfs_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 */
443void
444vfs_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 */
464void
465vfsimpl_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 */
490void
491vfsimpl_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
513krwlock_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 */
520static 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 */
532int
533fake_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	}
822errout:
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
841static void
842vfs_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 */
890void
891vfs_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 */
902void
903vfs_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
912refstr_t *
913vfs_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
927refstr_t *
928vfs_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 */
946static void
947vfs_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
960static void
961vfs_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
969static char **
970vfs_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
996static void
997vfs_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 */
1031static void
1032vfs_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 */
1063void
1064vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
1065{
1066	vfs_copyopttbl_extend(smo, dmo, 0);
1067}
1068
1069static char **
1070vfs_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 */
1152void
1153vfs_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 */
1211static void
1212vfs_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
1238void
1239vfs_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 */
1256static void
1257vfs_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
1316void
1317vfs_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 */
1346void
1347vfs_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 */
1391struct mntopt *
1392vfs_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 */
1414static int
1415vfs_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
1438int
1439vfs_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 */
1460int
1461vfs_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);
1500err:
1501	return (EOVERFLOW);
1502}
1503
1504static void
1505vfs_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
1519static void
1520vfs_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 */
1539void
1540vfs_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 */
1570void
1571vfs_mnttab_modtimeupd()
1572{
1573}
1574
1575/*
1576 * Unlike the real dounmount, we don't have
1577 * vn_vfswlock_held(coveredvp)
1578 */
1579int
1580fake_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
1655static 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 */
1662int
1663vfs_lock(vfs_t *vfsp)
1664{
1665
1666	if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
1667		return (0);
1668
1669	return (EBUSY);
1670}
1671
1672int
1673vfs_rlock(vfs_t *vfsp)
1674{
1675
1676	if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
1677		return (0);
1678
1679	return (EBUSY);
1680}
1681
1682void
1683vfs_lock_wait(vfs_t *vfsp)
1684{
1685
1686	rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
1687}
1688
1689void
1690vfs_rlock_wait(vfs_t *vfsp)
1691{
1692	rw_enter(&vpvfsentry_ve_lock, RW_READER);
1693}
1694
1695/*
1696 * Unlock a locked filesystem.
1697 */
1698void
1699vfs_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 */
1710void
1711vfs_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
1718int
1719vfs_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
1734void
1735vfs_list_lock()
1736{
1737	rw_enter(&vfslist, RW_WRITER);
1738}
1739
1740void
1741vfs_list_read_lock()
1742{
1743	rw_enter(&vfslist, RW_READER);
1744}
1745
1746void
1747vfs_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
1769int
1770vfs_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 */
1782int
1783vfs_opsinuse(vfsops_t *ops)
1784{
1785	return (0);
1786}
1787
1788/*
1789 * Allocate an entry in vfssw for a file system type
1790 */
1791struct vfssw *
1792allocate_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 */
1825struct vfssw *
1826vfs_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 */
1846struct vfssw *
1847vfs_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 */
1870void
1871vfs_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 */
1882void
1883vfs_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 */
1897uint_t
1898vf_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 */
1924void
1925vfsinit(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
1934vfs_t *
1935vfs_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
1949void
1950vfs_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 */
1968void
1969vfs_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 */
1980void
1981vfs_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
1997int
1998fs_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
2090int
2091fs_error(void)
2092{
2093	cmn_err(CE_PANIC, "fs_error called");
2094	return (0);
2095}
2096
2097int
2098fs_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 */
2116void
2117vfs_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
2126void
2127vfs_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 */
2139int
2140vfs_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