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