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