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
117 int
118 _init(void)
119 {
120 return (mod_install(&modlinkage));
121 }
122
123 int
124 _info(struct modinfo *modinfop)
125 {
126 return (mod_info(&modlinkage, modinfop));
127 }
128
129 int
130 _fini(void)
131 {
132 /*
133 * The sharetab filesystem cannot be unloaded.
134 */
135 return (EBUSY);
136 }
137
138 /*
139 * Filesystem initialization.
140 */
141
142 static int sharefs_fstype;
143 static major_t sharefs_major;
144 static minor_t sharefs_minor;
145
146 static gfs_opsvec_t sharefs_opsvec[] = {
147 { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data },
148 { NULL }
149 };
150
151 /* ARGSUSED */
152 static int
153 sharefs_init(int fstype, char *name)
154 {
155 vfsops_t *vfsops;
156 int error;
157
158 sharefs_fstype = fstype;
159 if (error = vfs_setfsops(fstype, sharefs_vfstops, &vfsops)) {
160 cmn_err(CE_WARN, "sharefs_init: bad vfs ops template");
161 return (error);
162 }
163
164 if (error = gfs_make_opsvec(sharefs_opsvec)) {
165 (void) vfs_freevfsops(vfsops);
166 return (error);
167 }
168
169 if ((sharefs_major = getudev()) == (major_t)-1) {
170 cmn_err(CE_WARN,
171 "sharefs_init: can't get unique device number");
172 sharefs_major = 0;
173 }
174
175 sharefs_sharetab_init();
176
177 return (0);
178 }
179
180 /*
181 * VFS entry points
182 */
183 static int
184 sharefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
185 {
186 sharefs_vfs_t *data;
187 dev_t dev;
188
189 if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
190 return (EPERM);
191
192 if ((uap->flags & MS_OVERLAY) == 0 &&
193 (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
194 return (EBUSY);
195
196 data = kmem_alloc(sizeof (sharefs_vfs_t), KM_SLEEP);
197
198 /*
199 * Initialize vfs fields
200 */
201 vfsp->vfs_bsize = DEV_BSIZE;
202 vfsp->vfs_fstype = sharefs_fstype;
203 do {
204 dev = makedevice(sharefs_major,
205 atomic_inc_32_nv(&sharefs_minor) & L_MAXMIN32);
206 } while (vfs_devismounted(dev));
207 vfs_make_fsid(&vfsp->vfs_fsid, dev, sharefs_fstype);
208 vfsp->vfs_data = data;
209 vfsp->vfs_dev = dev;
210
211 /*
212 * Create root
213 */
214 data->sharefs_vfs_root = sharefs_create_root_file(vfsp);
215
216 return (0);
217 }
218
219 static int
220 sharefs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
221 {
222 sharefs_vfs_t *data;
223
224 if (secpolicy_fs_unmount(cr, vfsp) != 0)
225 return (EPERM);
226
227 /*
228 * We do not currently support forced unmounts
229 */
230 if (flag & MS_FORCE)
231 return (ENOTSUP);
232
233 /*
234 * We should never have a reference count of less than 2: one for the
235 * caller, one for the root vnode.
236 */
237 ASSERT(vfsp->vfs_count >= 2);
238
239 /*
240 * Any active vnodes will result in a hold on the root vnode
241 */
242 data = vfsp->vfs_data;
243 if (data->sharefs_vfs_root->v_count > 1)
244 return (EBUSY);
245
246 /*
247 * Only allow an unmount iff there are no entries in memory.
248 */
249 rw_enter(&sharetab_lock, RW_READER);
250 if (sharetab_size != 0) {
251 rw_exit(&sharetab_lock);
252 return (EBUSY);
253 }
254 rw_exit(&sharetab_lock);
255
256 /*
257 * Release the last hold on the root vnode
258 */
259 VN_RELE(data->sharefs_vfs_root);
260
261 kmem_free(data, sizeof (sharefs_vfs_t));
262
263 return (0);
264 }
265
266 static int
267 sharefs_root(vfs_t *vfsp, vnode_t **vpp)
268 {
269 sharefs_vfs_t *data = vfsp->vfs_data;
270
271 *vpp = data->sharefs_vfs_root;
272 VN_HOLD(*vpp);
273
274 return (0);
275 }
276
277 static int
278 sharefs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
279 {
280 dev32_t d32;
281 int total = 1;
282
283 bzero(sp, sizeof (*sp));
284 sp->f_bsize = DEV_BSIZE;
285 sp->f_frsize = DEV_BSIZE;
286 sp->f_files = total;
287 sp->f_ffree = sp->f_favail = INT_MAX - total;
288 (void) cmpldev(&d32, vfsp->vfs_dev);
289 sp->f_fsid = d32;
290 (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
291 sizeof (sp->f_basetype));
292 sp->f_flag = vf_to_stf(vfsp->vfs_flag);
293 sp->f_namemax = SHAREFS_NAME_MAX;
294 (void) strlcpy(sp->f_fstr, "sharefs", sizeof (sp->f_fstr));
295
296 return (0);
297 }
298
299 static const fs_operation_def_t sharefs_vfstops[] = {
300 { VFSNAME_MOUNT, { .vfs_mount = sharefs_mount } },
301 { VFSNAME_UNMOUNT, { .vfs_unmount = sharefs_unmount } },
302 { VFSNAME_ROOT, { .vfs_root = sharefs_root } },
303 { VFSNAME_STATVFS, { .vfs_statvfs = sharefs_statvfs } },
304 { NULL }
305 };