xref: /netbsd-src/sys/miscfs/kernfs/kernfs_vfsops.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
1 /*	$NetBSD: kernfs_vfsops.c,v 1.99 2020/03/16 21:20:11 pgoyette 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.99 2020/03/16 21:20:11 pgoyette 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 void
78 kernfs_init(void)
79 {
80 
81 	malloc_type_attach(M_KERNFSMNT);
82 	mutex_init(&kfs_lock, MUTEX_DEFAULT, IPL_NONE);
83 }
84 
85 void
86 kernfs_reinit(void)
87 {
88 
89 }
90 
91 void
92 kernfs_done(void)
93 {
94 
95 	mutex_destroy(&kfs_lock);
96 	malloc_type_detach(M_KERNFSMNT);
97 }
98 
99 void
100 kernfs_get_rrootdev(void)
101 {
102 	static int tried = 0;
103 
104 	if (tried) {
105 		/* Already did it once. */
106 		return;
107 	}
108 	tried = 1;
109 
110 	if (rootdev == NODEV)
111 		return;
112 	rrootdev = devsw_blk2chr(rootdev);
113 	if (rrootdev != NODEV)
114 		return;
115 	rrootdev = NODEV;
116 	printf("kernfs_get_rrootdev: no raw root device\n");
117 }
118 
119 /*
120  * Mount the Kernel params filesystem
121  */
122 int
123 kernfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
124 {
125 	struct lwp *l = curlwp;
126 	int error = 0;
127 	struct kernfs_mount *fmp;
128 
129 	if (UIO_MX & (UIO_MX - 1)) {
130 		log(LOG_ERR, "kernfs: invalid directory entry size");
131 		return (EINVAL);
132 	}
133 
134 	if (mp->mnt_flag & MNT_GETARGS) {
135 		*data_len = 0;
136 		return 0;
137 	}
138 	/*
139 	 * Update is a no-op
140 	 */
141 	if (mp->mnt_flag & MNT_UPDATE)
142 		return (EOPNOTSUPP);
143 
144 	fmp = malloc(sizeof(struct kernfs_mount), M_KERNFSMNT, M_WAITOK|M_ZERO);
145 	TAILQ_INIT(&fmp->nodelist);
146 
147 	mp->mnt_stat.f_namemax = KERNFS_MAXNAMLEN;
148 	mp->mnt_flag |= MNT_LOCAL;
149 	mp->mnt_data = fmp;
150 	vfs_getnewfsid(mp);
151 
152 	if ((error = set_statvfs_info(path, UIO_USERSPACE, "kernfs",
153 	    UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l)) != 0) {
154 		free(fmp, M_KERNFSMNT);
155 		return error;
156 	}
157 
158 	kernfs_get_rrootdev();
159 	return 0;
160 }
161 
162 int
163 kernfs_start(struct mount *mp, int flags)
164 {
165 
166 	return (0);
167 }
168 
169 int
170 kernfs_unmount(struct mount *mp, int mntflags)
171 {
172 	int error;
173 	int flags = 0;
174 
175 	if (mntflags & MNT_FORCE)
176 		flags |= FORCECLOSE;
177 
178 	if ((error = vflush(mp, 0, flags)) != 0)
179 		return (error);
180 
181 	/*
182 	 * Finally, throw away the kernfs_mount structure
183 	 */
184 	free(mp->mnt_data, M_KERNFSMNT);
185 	mp->mnt_data = NULL;
186 	return (0);
187 }
188 
189 int
190 kernfs_root(struct mount *mp, int lktype, struct vnode **vpp)
191 {
192 	const struct kern_target *root_target = &kern_targets[0];
193 	int error;
194 
195 	/* setup "." */
196 	error = vcache_get(mp, &root_target, sizeof(root_target), vpp);
197 	if (error)
198 		return error;
199 	error = vn_lock(*vpp, lktype);
200 	if (error) {
201 		vrele(*vpp);
202 		*vpp = NULL;
203 		return error;
204 	}
205 	return 0;
206 }
207 
208 /*ARGSUSED*/
209 int
210 kernfs_sync(struct mount *mp, int waitfor,
211     kauth_cred_t uc)
212 {
213 
214 	return (0);
215 }
216 
217 /*
218  * Kernfs flat namespace lookup.
219  * Currently unsupported.
220  */
221 int
222 kernfs_vget(struct mount *mp, ino_t ino, int lktype,
223     struct vnode **vpp)
224 {
225 
226 	return (EOPNOTSUPP);
227 }
228 
229 int
230 kernfs_loadvnode(struct mount *mp, struct vnode *vp,
231     const void *key, size_t key_len, const void **new_key)
232 {
233 	const struct kern_target *kt;
234 	struct kernfs_node *kfs, *kfsp;
235 	long *cookie;
236 
237 	KASSERT(key_len == sizeof(kt));
238 	memcpy(&kt, key, key_len);
239 
240 	kfs = kmem_zalloc(sizeof(struct kernfs_node), KM_SLEEP);
241 	cookie = &(VFSTOKERNFS(mp)->fileno_cookie);
242 	mutex_enter(&kfs_lock);
243 again:
244 	TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) {
245 		if (kfsp->kfs_cookie == *cookie) {
246 			(*cookie) ++;
247 			goto again;
248 		}
249 		if (TAILQ_NEXT(kfsp, kfs_list)) {
250 			if (kfsp->kfs_cookie < *cookie &&
251 			    *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie)
252 				break;
253 			if (kfsp->kfs_cookie + 1 <
254 			    TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) {
255 				*cookie = kfsp->kfs_cookie + 1;
256 				break;
257 			}
258 		}
259 	}
260 
261 	kfs->kfs_cookie = *cookie;
262 
263 	if (kfsp)
264 		TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs,
265 		    kfs_list);
266 	else
267 		TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list);
268 
269 	kfs->kfs_type = kt->kt_tag;
270 	kfs->kfs_vnode = vp;
271 	kfs->kfs_fileno = KERNFS_FILENO(kt, kt->kt_tag, kfs->kfs_cookie);
272 	kfs->kfs_kt = kt;
273 	kfs->kfs_mode = kt->kt_mode;
274 	vp->v_tag = VT_KERNFS;
275 	vp->v_op = kernfs_vnodeop_p;
276 	vp->v_data = kfs;
277 	vp->v_type = kt->kt_vtype;
278 	mutex_exit(&kfs_lock);
279 
280 	if (kt->kt_tag == KFSkern)
281 		vp->v_vflag = VV_ROOT;
282 
283 	if (kt->kt_tag == KFSdevice) {
284 		vp->v_op = kernfs_specop_p;
285 		spec_node_init(vp, *(dev_t *)kt->kt_data);
286 	}
287 
288 	uvm_vnp_setsize(vp, 0);
289 
290 	*new_key = &kfs->kfs_kt;
291 	return 0;
292 }
293 
294 extern const struct vnodeopv_desc kernfs_vnodeop_opv_desc;
295 extern const struct vnodeopv_desc kernfs_specop_opv_desc;
296 
297 const struct vnodeopv_desc * const kernfs_vnodeopv_descs[] = {
298 	&kernfs_vnodeop_opv_desc,
299 	&kernfs_specop_opv_desc,
300 	NULL,
301 };
302 
303 struct vfsops kernfs_vfsops = {
304 	.vfs_name = MOUNT_KERNFS,
305 	.vfs_min_mount_data = 0,
306 	.vfs_mount = kernfs_mount,
307 	.vfs_start = kernfs_start,
308 	.vfs_unmount = kernfs_unmount,
309 	.vfs_root = kernfs_root,
310 	.vfs_quotactl = (void *)eopnotsupp,
311 	.vfs_statvfs = genfs_statvfs,
312 	.vfs_sync = kernfs_sync,
313 	.vfs_vget = kernfs_vget,
314 	.vfs_loadvnode = kernfs_loadvnode,
315 	.vfs_fhtovp = (void *)eopnotsupp,
316 	.vfs_vptofh = (void *)eopnotsupp,
317 	.vfs_init = kernfs_init,
318 	.vfs_reinit = kernfs_reinit,
319 	.vfs_done = kernfs_done,
320 	.vfs_snapshot = (void *)eopnotsupp,
321 	.vfs_extattrctl = vfs_stdextattrctl,
322 	.vfs_suspendctl = genfs_suspendctl,
323 	.vfs_renamelock_enter = genfs_renamelock_enter,
324 	.vfs_renamelock_exit = genfs_renamelock_exit,
325 	.vfs_fsync = (void *)eopnotsupp,
326 	.vfs_opv_descs = kernfs_vnodeopv_descs
327 };
328 
329 SYSCTL_SETUP(kernfs_sysctl_setup, "kernfs sysctl")
330 {
331 
332 	sysctl_createv(clog, 0, NULL, NULL,
333 		       CTLFLAG_PERMANENT,
334 		       CTLTYPE_NODE, "kernfs",
335 		       SYSCTL_DESCR("/kern file system"),
336 		       NULL, 0, NULL, 0,
337 		       CTL_VFS, 11, CTL_EOL);
338 	/*
339 	 * XXX the "11" above could be dynamic, thereby eliminating one
340 	 * more instance of the "number to vfs" mapping problem, but
341 	 * "11" is the order as taken from sys/mount.h
342 	 */
343 }
344 
345 static int
346 kernfs_modcmd(modcmd_t cmd, void *arg)
347 {
348 	int error;
349 
350 	switch (cmd) {
351 	case MODULE_CMD_INIT:
352 		error = vfs_attach(&kernfs_vfsops);
353 		if (error != 0)
354 			break;
355 		break;
356 	case MODULE_CMD_FINI:
357 		error = vfs_detach(&kernfs_vfsops);
358 		if (error != 0)
359 			break;
360 		break;
361 	default:
362 		error = ENOTTY;
363 		break;
364 	}
365 
366 	return (error);
367 }
368