1 | /* $NetBSD: kernfs_vfsops.c,v 1.95 2014/07/20 13:58:04 hannken Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1992, 1993, 1995 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * This code is derived from software donated to Berkeley by |
8 | * Jan-Simon Pendry. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. |
33 | * |
34 | * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 |
35 | */ |
36 | |
37 | /* |
38 | * Kernel params Filesystem |
39 | */ |
40 | |
41 | #include <sys/cdefs.h> |
42 | __KERNEL_RCSID(0, "$NetBSD: kernfs_vfsops.c,v 1.95 2014/07/20 13:58:04 hannken Exp $" ); |
43 | |
44 | #ifdef _KERNEL_OPT |
45 | #include "opt_compat_netbsd.h" |
46 | #endif |
47 | |
48 | #include <sys/param.h> |
49 | #include <sys/systm.h> |
50 | #include <sys/sysctl.h> |
51 | #include <sys/conf.h> |
52 | #include <sys/proc.h> |
53 | #include <sys/vnode.h> |
54 | #include <sys/mount.h> |
55 | #include <sys/namei.h> |
56 | #include <sys/dirent.h> |
57 | #include <sys/malloc.h> |
58 | #include <sys/syslog.h> |
59 | #include <sys/kauth.h> |
60 | #include <sys/module.h> |
61 | |
62 | #include <miscfs/genfs/genfs.h> |
63 | #include <miscfs/specfs/specdev.h> |
64 | #include <miscfs/kernfs/kernfs.h> |
65 | |
66 | MODULE(MODULE_CLASS_VFS, kernfs, NULL); |
67 | |
68 | MALLOC_JUSTDEFINE(M_KERNFSMNT, "kernfs mount" , "kernfs mount structures" ); |
69 | |
70 | dev_t rrootdev = NODEV; |
71 | kmutex_t kfs_lock; |
72 | |
73 | VFS_PROTOS(kernfs); |
74 | |
75 | void kernfs_get_rrootdev(void); |
76 | |
77 | static struct sysctllog *kernfs_sysctl_log; |
78 | |
79 | void |
80 | kernfs_init(void) |
81 | { |
82 | |
83 | malloc_type_attach(M_KERNFSMNT); |
84 | mutex_init(&kfs_lock, MUTEX_DEFAULT, IPL_NONE); |
85 | } |
86 | |
87 | void |
88 | kernfs_reinit(void) |
89 | { |
90 | |
91 | } |
92 | |
93 | void |
94 | kernfs_done(void) |
95 | { |
96 | |
97 | mutex_destroy(&kfs_lock); |
98 | malloc_type_detach(M_KERNFSMNT); |
99 | } |
100 | |
101 | void |
102 | kernfs_get_rrootdev(void) |
103 | { |
104 | static int tried = 0; |
105 | |
106 | if (tried) { |
107 | /* Already did it once. */ |
108 | return; |
109 | } |
110 | tried = 1; |
111 | |
112 | if (rootdev == NODEV) |
113 | return; |
114 | rrootdev = devsw_blk2chr(rootdev); |
115 | if (rrootdev != NODEV) |
116 | return; |
117 | rrootdev = NODEV; |
118 | printf("kernfs_get_rrootdev: no raw root device\n" ); |
119 | } |
120 | |
121 | /* |
122 | * Mount the Kernel params filesystem |
123 | */ |
124 | int |
125 | kernfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) |
126 | { |
127 | struct lwp *l = curlwp; |
128 | int error = 0; |
129 | struct kernfs_mount *fmp; |
130 | |
131 | if (UIO_MX & (UIO_MX - 1)) { |
132 | log(LOG_ERR, "kernfs: invalid directory entry size" ); |
133 | return (EINVAL); |
134 | } |
135 | |
136 | if (mp->mnt_flag & MNT_GETARGS) { |
137 | *data_len = 0; |
138 | return 0; |
139 | } |
140 | /* |
141 | * Update is a no-op |
142 | */ |
143 | if (mp->mnt_flag & MNT_UPDATE) |
144 | return (EOPNOTSUPP); |
145 | |
146 | fmp = malloc(sizeof(struct kernfs_mount), M_KERNFSMNT, M_WAITOK|M_ZERO); |
147 | TAILQ_INIT(&fmp->nodelist); |
148 | |
149 | mp->mnt_stat.f_namemax = KERNFS_MAXNAMLEN; |
150 | mp->mnt_flag |= MNT_LOCAL; |
151 | mp->mnt_data = fmp; |
152 | vfs_getnewfsid(mp); |
153 | |
154 | if ((error = set_statvfs_info(path, UIO_USERSPACE, "kernfs" , |
155 | UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l)) != 0) { |
156 | free(fmp, M_KERNFSMNT); |
157 | return error; |
158 | } |
159 | |
160 | kernfs_get_rrootdev(); |
161 | return 0; |
162 | } |
163 | |
164 | int |
165 | kernfs_start(struct mount *mp, int flags) |
166 | { |
167 | |
168 | return (0); |
169 | } |
170 | |
171 | int |
172 | kernfs_unmount(struct mount *mp, int mntflags) |
173 | { |
174 | int error; |
175 | int flags = 0; |
176 | |
177 | if (mntflags & MNT_FORCE) |
178 | flags |= FORCECLOSE; |
179 | |
180 | if ((error = vflush(mp, 0, flags)) != 0) |
181 | return (error); |
182 | |
183 | /* |
184 | * Finally, throw away the kernfs_mount structure |
185 | */ |
186 | free(mp->mnt_data, M_KERNFSMNT); |
187 | mp->mnt_data = NULL; |
188 | return (0); |
189 | } |
190 | |
191 | int |
192 | kernfs_root(struct mount *mp, struct vnode **vpp) |
193 | { |
194 | const struct kern_target *root_target = &kern_targets[0]; |
195 | int error; |
196 | |
197 | /* setup "." */ |
198 | error = vcache_get(mp, &root_target, sizeof(root_target), vpp); |
199 | if (error) |
200 | return error; |
201 | error = vn_lock(*vpp, LK_EXCLUSIVE); |
202 | if (error) { |
203 | vrele(*vpp); |
204 | *vpp = NULL; |
205 | return error; |
206 | } |
207 | return 0; |
208 | } |
209 | |
210 | /*ARGSUSED*/ |
211 | int |
212 | kernfs_sync(struct mount *mp, int waitfor, |
213 | kauth_cred_t uc) |
214 | { |
215 | |
216 | return (0); |
217 | } |
218 | |
219 | /* |
220 | * Kernfs flat namespace lookup. |
221 | * Currently unsupported. |
222 | */ |
223 | int |
224 | kernfs_vget(struct mount *mp, ino_t ino, |
225 | struct vnode **vpp) |
226 | { |
227 | |
228 | return (EOPNOTSUPP); |
229 | } |
230 | |
231 | int |
232 | kernfs_loadvnode(struct mount *mp, struct vnode *vp, |
233 | const void *key, size_t key_len, const void **new_key) |
234 | { |
235 | const struct kern_target *kt; |
236 | struct kernfs_node *kfs, *kfsp; |
237 | long *cookie; |
238 | |
239 | KASSERT(key_len == sizeof(kt)); |
240 | memcpy(&kt, key, key_len); |
241 | |
242 | kfs = kmem_zalloc(sizeof(struct kernfs_node), KM_SLEEP); |
243 | cookie = &(VFSTOKERNFS(mp)->fileno_cookie); |
244 | mutex_enter(&kfs_lock); |
245 | again: |
246 | TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) { |
247 | if (kfsp->kfs_cookie == *cookie) { |
248 | (*cookie) ++; |
249 | goto again; |
250 | } |
251 | if (TAILQ_NEXT(kfsp, kfs_list)) { |
252 | if (kfsp->kfs_cookie < *cookie && |
253 | *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) |
254 | break; |
255 | if (kfsp->kfs_cookie + 1 < |
256 | TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) { |
257 | *cookie = kfsp->kfs_cookie + 1; |
258 | break; |
259 | } |
260 | } |
261 | } |
262 | |
263 | kfs->kfs_cookie = *cookie; |
264 | |
265 | if (kfsp) |
266 | TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs, |
267 | kfs_list); |
268 | else |
269 | TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list); |
270 | |
271 | kfs->kfs_type = kt->kt_tag; |
272 | kfs->kfs_vnode = vp; |
273 | kfs->kfs_fileno = KERNFS_FILENO(kt, kt->kt_tag, kfs->kfs_cookie); |
274 | kfs->kfs_kt = kt; |
275 | kfs->kfs_mode = kt->kt_mode; |
276 | vp->v_tag = VT_KERNFS; |
277 | vp->v_op = kernfs_vnodeop_p; |
278 | vp->v_data = kfs; |
279 | vp->v_type = kt->kt_vtype; |
280 | mutex_exit(&kfs_lock); |
281 | |
282 | if (kt->kt_tag == KFSkern) |
283 | vp->v_vflag = VV_ROOT; |
284 | |
285 | if (kt->kt_tag == KFSdevice) { |
286 | spec_node_init(vp, *(dev_t *)kt->kt_data); |
287 | } |
288 | |
289 | uvm_vnp_setsize(vp, 0); |
290 | |
291 | *new_key = &kfs->kfs_kt; |
292 | return 0; |
293 | } |
294 | |
295 | extern const struct vnodeopv_desc kernfs_vnodeop_opv_desc; |
296 | |
297 | const struct vnodeopv_desc * const kernfs_vnodeopv_descs[] = { |
298 | &kernfs_vnodeop_opv_desc, |
299 | NULL, |
300 | }; |
301 | |
302 | struct vfsops kernfs_vfsops = { |
303 | .vfs_name = MOUNT_KERNFS, |
304 | .vfs_min_mount_data = 0, |
305 | .vfs_mount = kernfs_mount, |
306 | .vfs_start = kernfs_start, |
307 | .vfs_unmount = kernfs_unmount, |
308 | .vfs_root = kernfs_root, |
309 | .vfs_quotactl = (void *)eopnotsupp, |
310 | .vfs_statvfs = genfs_statvfs, |
311 | .vfs_sync = kernfs_sync, |
312 | .vfs_vget = kernfs_vget, |
313 | .vfs_loadvnode = kernfs_loadvnode, |
314 | .vfs_fhtovp = (void *)eopnotsupp, |
315 | .vfs_vptofh = (void *)eopnotsupp, |
316 | .vfs_init = kernfs_init, |
317 | .vfs_reinit = kernfs_reinit, |
318 | .vfs_done = kernfs_done, |
319 | .vfs_snapshot = (void *)eopnotsupp, |
320 | .vfs_extattrctl = vfs_stdextattrctl, |
321 | .vfs_suspendctl = (void *)eopnotsupp, |
322 | .vfs_renamelock_enter = genfs_renamelock_enter, |
323 | .vfs_renamelock_exit = genfs_renamelock_exit, |
324 | .vfs_fsync = (void *)eopnotsupp, |
325 | .vfs_opv_descs = kernfs_vnodeopv_descs |
326 | }; |
327 | |
328 | static int |
329 | kernfs_modcmd(modcmd_t cmd, void *arg) |
330 | { |
331 | int error; |
332 | |
333 | switch (cmd) { |
334 | case MODULE_CMD_INIT: |
335 | error = vfs_attach(&kernfs_vfsops); |
336 | if (error != 0) |
337 | break; |
338 | sysctl_createv(&kernfs_sysctl_log, 0, NULL, NULL, |
339 | CTLFLAG_PERMANENT, |
340 | CTLTYPE_NODE, "kernfs" , |
341 | SYSCTL_DESCR("/kern file system" ), |
342 | NULL, 0, NULL, 0, |
343 | CTL_VFS, 11, CTL_EOL); |
344 | /* |
345 | * XXX the "11" above could be dynamic, thereby eliminating one |
346 | * more instance of the "number to vfs" mapping problem, but |
347 | * "11" is the order as taken from sys/mount.h |
348 | */ |
349 | break; |
350 | case MODULE_CMD_FINI: |
351 | error = vfs_detach(&kernfs_vfsops); |
352 | if (error != 0) |
353 | break; |
354 | sysctl_teardown(&kernfs_sysctl_log); |
355 | break; |
356 | default: |
357 | error = ENOTTY; |
358 | break; |
359 | } |
360 | |
361 | return (error); |
362 | } |
363 | |