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