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
_init(void)121 _init(void)
122 {
123 return (mod_install(&modlinkage));
124 }
125
126 int
_info(struct modinfo * modinfop)127 _info(struct modinfo *modinfop)
128 {
129 return (mod_info(&modlinkage, modinfop));
130 }
131
132 int
_fini(void)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
sharefs_init(int fstype,char * name)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
sharefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)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
sharefs_unmount(vfs_t * vfsp,int flag,struct cred * cr)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
sharefs_root(vfs_t * vfsp,vnode_t ** vpp)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
sharefs_statvfs(vfs_t * vfsp,statvfs64_t * sp)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