xref: /titanic_41/usr/src/uts/common/fs/sharefs/sharefs_vfsops.c (revision 0d6bb4c6728fd20087fe25f4028a3838250e6e9c)
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