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