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