1a237e38eSth /*
2a237e38eSth  * CDDL HEADER START
3a237e38eSth  *
4a237e38eSth  * The contents of this file are subject to the terms of the
5a237e38eSth  * Common Development and Distribution License (the "License").
6a237e38eSth  * You may not use this file except in compliance with the License.
7a237e38eSth  *
8a237e38eSth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a237e38eSth  * or http://www.opensolaris.org/os/licensing.
10a237e38eSth  * See the License for the specific language governing permissions
11a237e38eSth  * and limitations under the License.
12a237e38eSth  *
13a237e38eSth  * When distributing Covered Code, include this CDDL HEADER in each
14a237e38eSth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a237e38eSth  * If applicable, add the following below this CDDL HEADER, with the
16a237e38eSth  * fields enclosed by brackets "[]" replaced with your own identifying
17a237e38eSth  * information: Portions Copyright [yyyy] [name of copyright owner]
18a237e38eSth  *
19a237e38eSth  * CDDL HEADER END
20a237e38eSth  */
21a237e38eSth 
22a237e38eSth /*
230fbb751dSJohn Levon  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24a237e38eSth  */
25a237e38eSth 
26*0dfe541eSEvan Layton /*
27*0dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
28*0dfe541eSEvan Layton  */
29*0dfe541eSEvan Layton 
30a237e38eSth #include <sys/atomic.h>
31a237e38eSth #include <sys/cmn_err.h>
32a237e38eSth #include <sys/errno.h>
33a237e38eSth #include <sys/mount.h>
34a237e38eSth #include <sharefs/sharefs.h>
35a237e38eSth #include <sys/vfs_opreg.h>
36a237e38eSth #include <sys/policy.h>
37a237e38eSth #include <sys/sunddi.h>
38a237e38eSth #include <sys/sysmacros.h>
39a237e38eSth #include <sys/systm.h>
40a237e38eSth 
41a237e38eSth #include <sys/mntent.h>
42a237e38eSth #include <sys/vfs.h>
43a237e38eSth 
44a237e38eSth /*
45a237e38eSth  * Kernel sharetab filesystem.
46a237e38eSth  *
47a237e38eSth  * This is a pseudo filesystem which exports information about shares currently
48a237e38eSth  * in kernel memory. The only element of the pseudo filesystem is a file.
49a237e38eSth  *
50a237e38eSth  * This file contains functions that interact with the VFS layer.
51a237e38eSth  *
52a237e38eSth  *	sharetab	sharefs_datanode_t	sharefs.c
53a237e38eSth  *
54a237e38eSth  */
55a237e38eSth 
56a237e38eSth vnodeops_t			*sharefs_ops_data;
57a237e38eSth 
58a237e38eSth static const fs_operation_def_t	sharefs_vfstops[];
59a237e38eSth static gfs_opsvec_t		 sharefs_opsvec[];
60a237e38eSth 
61a237e38eSth static int sharefs_init(int, char *);
62a237e38eSth 
63a237e38eSth /*
64a237e38eSth  * The sharefs system call.
65a237e38eSth  */
66a237e38eSth static struct sysent sharefs_sysent = {
67a237e38eSth 	3,
68a237e38eSth 	SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
69a237e38eSth 	sharefs
70a237e38eSth };
71a237e38eSth 
72a237e38eSth static struct modlsys modlsys = {
73a237e38eSth 	&mod_syscallops,
74a237e38eSth 	"sharefs syscall",
75a237e38eSth 	&sharefs_sysent
76a237e38eSth };
77a237e38eSth 
78a237e38eSth #ifdef	_SYSCALL32_IMPL
79a237e38eSth static struct modlsys modlsys32 = {
80a237e38eSth 	&mod_syscallops32,
81a237e38eSth 	"sharefs syscall (32-bit)",
82a237e38eSth 	&sharefs_sysent
83a237e38eSth };
84a237e38eSth #endif /* _SYSCALL32_IMPL */
85a237e38eSth 
86a237e38eSth /*
87a237e38eSth  * Module linkage
88a237e38eSth  */
89a237e38eSth static mntopts_t sharefs_mntopts = {
90a237e38eSth 	0,
91a237e38eSth 	NULL
92a237e38eSth };
93a237e38eSth 
94a237e38eSth static vfsdef_t vfw = {
95a237e38eSth 	VFSDEF_VERSION,
96a237e38eSth 	"sharefs",
97a237e38eSth 	sharefs_init,
980fbb751dSJohn Levon 	VSW_HASPROTO | VSW_ZMOUNT,
99a237e38eSth 	&sharefs_mntopts,
100a237e38eSth };
101a237e38eSth 
102a237e38eSth extern struct mod_ops	mod_fsops;
103a237e38eSth 
104a237e38eSth static struct modlfs modlfs = {
105a237e38eSth 	&mod_fsops,
106a237e38eSth 	"sharetab filesystem",
107a237e38eSth 	&vfw
108a237e38eSth };
109a237e38eSth 
110a237e38eSth static struct modlinkage modlinkage = {
111a237e38eSth 	MODREV_1,
112a237e38eSth 	&modlfs,
113a237e38eSth 	&modlsys,
114a237e38eSth #ifdef	_SYSCALL32_IMPL
115a237e38eSth 	&modlsys32,
116a237e38eSth #endif
117a237e38eSth 	NULL
118a237e38eSth };
119a237e38eSth 
120a237e38eSth int
_init(void)121a237e38eSth _init(void)
122a237e38eSth {
123a237e38eSth 	return (mod_install(&modlinkage));
124a237e38eSth }
125a237e38eSth 
126a237e38eSth int
_info(struct modinfo * modinfop)127a237e38eSth _info(struct modinfo *modinfop)
128a237e38eSth {
129a237e38eSth 	return (mod_info(&modlinkage, modinfop));
130a237e38eSth }
131a237e38eSth 
132a237e38eSth int
_fini(void)133a237e38eSth _fini(void)
134a237e38eSth {
135a237e38eSth 	/*
136a237e38eSth 	 * The sharetab filesystem cannot be unloaded.
137a237e38eSth 	 */
138a237e38eSth 	return (EBUSY);
139a237e38eSth }
140a237e38eSth 
141a237e38eSth /*
142a237e38eSth  * Filesystem initialization.
143a237e38eSth  */
144a237e38eSth 
145a237e38eSth static int sharefs_fstype;
146a237e38eSth static major_t sharefs_major;
147a237e38eSth static minor_t sharefs_minor;
148a237e38eSth 
149a237e38eSth static gfs_opsvec_t sharefs_opsvec[] = {
150a237e38eSth 	{ "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data },
151a237e38eSth 	{ NULL }
152a237e38eSth };
153a237e38eSth 
154a237e38eSth /* ARGSUSED */
155a237e38eSth static int
sharefs_init(int fstype,char * name)156a237e38eSth sharefs_init(int fstype, char *name)
157a237e38eSth {
158a237e38eSth 	vfsops_t	*vfsops;
159a237e38eSth 	int		error;
160a237e38eSth 
161a237e38eSth 	sharefs_fstype = fstype;
162a237e38eSth 	if (error = vfs_setfsops(fstype, sharefs_vfstops, &vfsops)) {
163a237e38eSth 		cmn_err(CE_WARN, "sharefs_init: bad vfs ops template");
164a237e38eSth 		return (error);
165a237e38eSth 	}
166a237e38eSth 
167a237e38eSth 	if (error = gfs_make_opsvec(sharefs_opsvec)) {
168a237e38eSth 		(void) vfs_freevfsops(vfsops);
169a237e38eSth 		return (error);
170a237e38eSth 	}
171a237e38eSth 
172a237e38eSth 	if ((sharefs_major = getudev()) == (major_t)-1) {
173a237e38eSth 		cmn_err(CE_WARN,
174a3175730Sth 		    "sharefs_init: can't get unique device number");
175a237e38eSth 		sharefs_major = 0;
176a237e38eSth 	}
177a237e38eSth 
178a237e38eSth 	sharefs_sharetab_init();
179a237e38eSth 
180a237e38eSth 	return (0);
181a237e38eSth }
182a237e38eSth 
183a237e38eSth /*
184a237e38eSth  * VFS entry points
185a237e38eSth  */
186a237e38eSth static int
sharefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)187a237e38eSth sharefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
188a237e38eSth {
189a237e38eSth 	sharefs_vfs_t	*data;
190a237e38eSth 	dev_t		dev;
191a237e38eSth 
192a237e38eSth 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
193a237e38eSth 		return (EPERM);
194a237e38eSth 
195a237e38eSth 	if ((uap->flags & MS_OVERLAY) == 0 &&
196a237e38eSth 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
197a237e38eSth 		return (EBUSY);
198a237e38eSth 
199a237e38eSth 	data = kmem_alloc(sizeof (sharefs_vfs_t), KM_SLEEP);
200a237e38eSth 
201a237e38eSth 	/*
202a237e38eSth 	 * Initialize vfs fields
203a237e38eSth 	 */
204a237e38eSth 	vfsp->vfs_bsize = DEV_BSIZE;
205a237e38eSth 	vfsp->vfs_fstype = sharefs_fstype;
206a237e38eSth 	do {
207a237e38eSth 		dev = makedevice(sharefs_major,
2081a5e258fSJosef 'Jeff' Sipek 		    atomic_inc_32_nv(&sharefs_minor) & L_MAXMIN32);
209a237e38eSth 	} while (vfs_devismounted(dev));
210a237e38eSth 	vfs_make_fsid(&vfsp->vfs_fsid, dev, sharefs_fstype);
211a237e38eSth 	vfsp->vfs_data = data;
212a237e38eSth 	vfsp->vfs_dev = dev;
213a237e38eSth 
214a237e38eSth 	/*
215a237e38eSth 	 * Create root
216a237e38eSth 	 */
217a237e38eSth 	data->sharefs_vfs_root = sharefs_create_root_file(vfsp);
218a237e38eSth 
219a237e38eSth 	return (0);
220a237e38eSth }
221a237e38eSth 
222a237e38eSth static int
sharefs_unmount(vfs_t * vfsp,int flag,struct cred * cr)223a237e38eSth sharefs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
224a237e38eSth {
225a237e38eSth 	sharefs_vfs_t	*data;
226a237e38eSth 
227a237e38eSth 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
228a237e38eSth 		return (EPERM);
229a237e38eSth 
230a237e38eSth 	/*
231a237e38eSth 	 * We do not currently support forced unmounts
232a237e38eSth 	 */
233a237e38eSth 	if (flag & MS_FORCE)
234a237e38eSth 		return (ENOTSUP);
235a237e38eSth 
236a237e38eSth 	/*
237a237e38eSth 	 * We should never have a reference count of less than 2: one for the
238a237e38eSth 	 * caller, one for the root vnode.
239a237e38eSth 	 */
240a237e38eSth 	ASSERT(vfsp->vfs_count >= 2);
241a237e38eSth 
242a237e38eSth 	/*
243a237e38eSth 	 * Any active vnodes will result in a hold on the root vnode
244a237e38eSth 	 */
245a237e38eSth 	data = vfsp->vfs_data;
246a237e38eSth 	if (data->sharefs_vfs_root->v_count > 1)
247a237e38eSth 		return (EBUSY);
248a237e38eSth 
249a237e38eSth 	/*
250a237e38eSth 	 * Release the last hold on the root vnode
251a237e38eSth 	 */
252a237e38eSth 	VN_RELE(data->sharefs_vfs_root);
253a237e38eSth 
254a237e38eSth 	kmem_free(data, sizeof (sharefs_vfs_t));
255a237e38eSth 
256a237e38eSth 	return (0);
257a237e38eSth }
258a237e38eSth 
259a237e38eSth static int
sharefs_root(vfs_t * vfsp,vnode_t ** vpp)260a237e38eSth sharefs_root(vfs_t *vfsp, vnode_t **vpp)
261a237e38eSth {
262a237e38eSth 	sharefs_vfs_t	*data = vfsp->vfs_data;
263a237e38eSth 
264a237e38eSth 	*vpp = data->sharefs_vfs_root;
265a237e38eSth 	VN_HOLD(*vpp);
266a237e38eSth 
267a237e38eSth 	return (0);
268a237e38eSth }
269a237e38eSth 
270a237e38eSth static int
sharefs_statvfs(vfs_t * vfsp,statvfs64_t * sp)271a237e38eSth sharefs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
272a237e38eSth {
273a237e38eSth 	dev32_t	d32;
274a237e38eSth 	int	total = 1;
275a237e38eSth 
276a237e38eSth 	bzero(sp, sizeof (*sp));
277a237e38eSth 	sp->f_bsize = DEV_BSIZE;
278a237e38eSth 	sp->f_frsize = DEV_BSIZE;
279a237e38eSth 	sp->f_files = total;
280a237e38eSth 	sp->f_ffree = sp->f_favail = INT_MAX - total;
281a237e38eSth 	(void) cmpldev(&d32, vfsp->vfs_dev);
282a237e38eSth 	sp->f_fsid = d32;
283a237e38eSth 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
284a237e38eSth 	    sizeof (sp->f_basetype));
285a237e38eSth 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
286a237e38eSth 	sp->f_namemax = SHAREFS_NAME_MAX;
287a237e38eSth 	(void) strlcpy(sp->f_fstr, "sharefs", sizeof (sp->f_fstr));
288a237e38eSth 
289a237e38eSth 	return (0);
290a237e38eSth }
291a237e38eSth 
292a237e38eSth static const fs_operation_def_t sharefs_vfstops[] = {
293a237e38eSth 	{ VFSNAME_MOUNT,	{ .vfs_mount = sharefs_mount } },
294a237e38eSth 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = sharefs_unmount } },
295a237e38eSth 	{ VFSNAME_ROOT,		{ .vfs_root = sharefs_root } },
296a237e38eSth 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = sharefs_statvfs } },
297a237e38eSth 	{ NULL }
298a237e38eSth };
299