xref: /netbsd-src/sys/rump/librump/rumpvfs/rump_vfs.c (revision d536862b7d93d77932ef5de7eebdc48d76921b77)
1 /*	$NetBSD: rump_vfs.c,v 1.93 2020/04/25 15:42:15 bouyer Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by the
7  * Finnish Cultural Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: rump_vfs.c,v 1.93 2020/04/25 15:42:15 bouyer Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/buf.h>
36 #include <sys/conf.h>
37 #include <sys/evcnt.h>
38 #include <sys/fcntl.h>
39 #include <sys/filedesc.h>
40 #include <sys/fstrans.h>
41 #include <sys/lockf.h>
42 #include <sys/kthread.h>
43 #include <sys/module.h>
44 #include <sys/namei.h>
45 #include <sys/queue.h>
46 #include <sys/stat.h>
47 #include <sys/vfs_syscalls.h>
48 #include <sys/vnode.h>
49 #include <sys/wapbl.h>
50 #include <sys/bufq.h>
51 
52 #include <miscfs/specfs/specdev.h>
53 
54 #include <rump-sys/kern.h>
55 #include <rump-sys/vfs.h>
56 
57 #include <rump/rump.h>
58 #include <rump/rumpuser.h>
59 
60 extern struct cwdinfo cwdi0;
61 const char *rootfstype = ROOT_FSTYPE_ANY;
62 
63 static void
64 pvfs_init(struct proc *p)
65 {
66 
67 	p->p_cwdi = cwdinit();
68 }
69 
70 static void
71 pvfs_rele(struct proc *p)
72 {
73 
74 	cwdfree(p->p_cwdi);
75 }
76 
77 static void
78 fini(void)
79 {
80 
81 	vfs_shutdown();
82 	rumpblk_fini();
83 }
84 
85 static void
86 drainbufs(int npages)
87 {
88 
89 	mutex_enter(&bufcache_lock);
90 	buf_drain(npages);
91 	mutex_exit(&bufcache_lock);
92 }
93 
94 RUMP_COMPONENT(RUMP__FACTION_VFS)
95 {
96 	extern struct vfsops rumpfs_vfsops;
97 	char buf[64];
98 	char *mbase;
99 	int rv, i;
100 
101 	/* initialize indirect interfaces */
102 	rump_vfs_fini = fini;
103 	rump_vfs_drainbufs = drainbufs;
104 
105 	if (rumpuser_getparam("RUMP_NVNODES", buf, sizeof(buf)) == 0) {
106 		desiredvnodes = strtoul(buf, NULL, 10);
107 	} else {
108 		desiredvnodes = 1<<10;
109 	}
110 
111 	rumpblk_init();
112 
113 	for (i = 0; i < ncpu; i++) {
114 		struct cpu_info *ci = cpu_lookup(i);
115 		cache_cpu_init(ci);
116 	}
117 
118 	/* make number of bufpages 5% of total memory limit */
119 	if (rump_physmemlimit != RUMPMEM_UNLIMITED) {
120 		extern u_int bufpages;
121 		bufpages = rump_physmemlimit / (20 * PAGE_SIZE);
122 	}
123 
124 	bufq_init();
125 	fstrans_init();
126 	vfsinit();
127 	bufinit();
128 	cwd_sys_init();
129 	lf_init();
130 	spec_init();
131 
132 	root_device = &rump_rootdev;
133 
134 	/* bootstrap cwdi (rest done in vfs_mountroot() */
135 	proc0.p_cwdi = &cwdi0;
136 	proc0.p_cwdi = cwdinit();
137 
138 	vfs_attach(&rumpfs_vfsops);
139 	vfs_mountroot();
140 
141 	/* "mtree": create /dev and /tmp */
142 	do_sys_mkdir("/dev", 0755, UIO_SYSSPACE);
143 	do_sys_mkdir("/tmp", 01777, UIO_SYSSPACE);
144 	do_sys_chmodat(curlwp, AT_FDCWD, "/tmp", 01777, 0);
145 
146 	rump_proc_vfs_init = pvfs_init;
147 	rump_proc_vfs_release = pvfs_rele;
148 
149 	if (rump_threads) {
150 		if ((rv = kthread_create(PRI_IOFLUSH, KTHREAD_MPSAFE, NULL,
151 		    sched_sync, NULL, NULL, "ioflush")) != 0)
152 			panic("syncer thread create failed: %d", rv);
153 	} else {
154 		syncdelay = 0;
155 	}
156 
157 	/*
158 	 * On archs where the native kernel ABI is supported, map
159 	 * host module directory to rump.  This means that kernel
160 	 * modules from the host will be autoloaded to rump kernels.
161 	 */
162 	if (rump_nativeabi_p()) {
163 		if (rumpuser_getparam("RUMP_MODULEBASE", buf, sizeof(buf)) == 0)
164 			mbase = buf;
165 		else
166 			mbase = module_base;
167 
168 		if (strlen(mbase) != 0 && *mbase != '0') {
169 			rump_etfs_register(module_base, mbase,
170 			    RUMP_ETFS_DIR_SUBDIRS);
171 		}
172 	}
173 
174 	module_init_class(MODULE_CLASS_BUFQ);
175 	module_init_class(MODULE_CLASS_VFS);
176 
177 	/*
178 	 * Don't build device names for a large set of devices by
179 	 * default.  While the pseudo-devfs is a fun experiment,
180 	 * creating many many device nodes may increase rump kernel
181 	 * bootstrap time by ~40%.  Device nodes should be created
182 	 * per-demand in the component constructors.
183 	 */
184 #if 0
185 	{
186 	extern struct devsw_conv devsw_conv0[];
187 	extern int max_devsw_convs;
188 	rump_vfs_builddevs(devsw_conv0, max_devsw_convs);
189 	}
190 #else
191 	rump_vfs_builddevs(NULL, 0);
192 #endif
193 
194 	/* attach null device and create /dev/{null,zero} */
195 	rump_devnull_init();
196 
197 	rump_component_init(RUMP_COMPONENT_VFS);
198 }
199 
200 struct rumpcn {
201 	struct componentname rcn_cn;
202 	char *rcn_path;
203 };
204 
205 struct componentname *
206 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen,
207 	kauth_cred_t creds, struct lwp *l)
208 {
209 	struct rumpcn *rcn;
210 	struct componentname *cnp;
211 
212 	rcn = kmem_zalloc(sizeof(*rcn), KM_SLEEP);
213 	cnp = &rcn->rcn_cn;
214 
215 	rcn->rcn_path = PNBUF_GET();
216 	strlcpy(rcn->rcn_path, name, MAXPATHLEN);
217 	cnp->cn_nameptr = rcn->rcn_path;
218 
219 	cnp->cn_nameiop = nameiop;
220 	cnp->cn_flags = flags & (MODMASK | PARAMASK);
221 
222 	cnp->cn_namelen = namelen;
223 
224 	cnp->cn_cred = creds;
225 
226 	return cnp;
227 }
228 
229 void
230 rump_freecn(struct componentname *cnp, int flags)
231 {
232 	struct rumpcn *rcn = (void *)cnp;
233 
234 	if (flags & RUMPCN_FREECRED)
235 		rump_cred_put(cnp->cn_cred);
236 
237 	PNBUF_PUT(rcn->rcn_path);
238 	kmem_free(rcn, sizeof(*rcn));
239 }
240 
241 /* hey baby, what's your namei? */
242 int
243 rump_namei(uint32_t op, uint32_t flags, const char *namep,
244 	struct vnode **dvpp, struct vnode **vpp, struct componentname **cnpp)
245 {
246 	struct pathbuf *pb;
247 	struct nameidata nd;
248 	int rv;
249 
250 	pb = pathbuf_create(namep);
251 	if (pb == NULL) {
252 		return ENOMEM;
253 	}
254 	NDINIT(&nd, op, flags, pb);
255 	rv = namei(&nd);
256 	if (rv) {
257 		pathbuf_destroy(pb);
258 		return rv;
259 	}
260 
261 	if (dvpp) {
262 		KASSERT(flags & LOCKPARENT);
263 		*dvpp = nd.ni_dvp;
264 	} else {
265 		KASSERT((flags & LOCKPARENT) == 0);
266 	}
267 
268 	if (vpp) {
269 		*vpp = nd.ni_vp;
270 	} else {
271 		if (nd.ni_vp) {
272 			if (flags & LOCKLEAF)
273 				vput(nd.ni_vp);
274 			else
275 				vrele(nd.ni_vp);
276 		}
277 	}
278 
279 	if (cnpp) {
280 		struct componentname *cnp;
281 
282 		cnp = kmem_alloc(sizeof(*cnp), KM_SLEEP);
283 		memcpy(cnp, &nd.ni_cnd, sizeof(*cnp));
284 		*cnpp = cnp;
285 	}
286 	pathbuf_destroy(pb);
287 
288 	return rv;
289 }
290 
291 void
292 rump_getvninfo(struct vnode *vp, enum rump_vtype *vtype,
293 	voff_t *vsize, dev_t *vdev)
294 {
295 
296 	*vtype = (enum rump_vtype)vp->v_type;
297 	*vsize = vp->v_size;
298 	if (vp->v_specnode)
299 		*vdev = vp->v_rdev;
300 	else
301 		*vdev = 0;
302 }
303 
304 struct vfsops *
305 rump_vfslist_iterate(struct vfsops *ops)
306 {
307 
308 	if (ops == NULL)
309 		return LIST_FIRST(&vfs_list);
310 	else
311 		return LIST_NEXT(ops, vfs_list);
312 }
313 
314 struct vfsops *
315 rump_vfs_getopsbyname(const char *name)
316 {
317 
318 	return vfs_getopsbyname(name);
319 }
320 
321 int
322 rump_vfs_getmp(const char *path, struct mount **mpp)
323 {
324 	struct vnode *vp;
325 	int rv;
326 
327 	if ((rv = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp)) != 0)
328 		return rv;
329 
330 	*mpp = vp->v_mount;
331 	vrele(vp);
332 	return 0;
333 }
334 
335 struct vattr*
336 rump_vattr_init(void)
337 {
338 	struct vattr *vap;
339 
340 	vap = kmem_alloc(sizeof(struct vattr), KM_SLEEP);
341 	vattr_null(vap);
342 
343 	return vap;
344 }
345 
346 void
347 rump_vattr_settype(struct vattr *vap, enum rump_vtype vt)
348 {
349 
350 	vap->va_type = (enum vtype)vt;
351 }
352 
353 void
354 rump_vattr_setmode(struct vattr *vap, mode_t mode)
355 {
356 
357 	vap->va_mode = mode;
358 }
359 
360 void
361 rump_vattr_setrdev(struct vattr *vap, dev_t dev)
362 {
363 
364 	vap->va_rdev = dev;
365 }
366 
367 void
368 rump_vattr_free(struct vattr *vap)
369 {
370 
371 	kmem_free(vap, sizeof(*vap));
372 }
373 
374 void
375 rump_vp_incref(struct vnode *vp)
376 {
377 
378 	vref(vp);
379 }
380 
381 int
382 rump_vp_getref(struct vnode *vp)
383 {
384 
385 	return vrefcnt(vp);
386 }
387 
388 void
389 rump_vp_rele(struct vnode *vp)
390 {
391 
392 	vrele(vp);
393 }
394 
395 void
396 rump_vp_interlock(struct vnode *vp)
397 {
398 
399 	mutex_enter(vp->v_interlock);
400 }
401 
402 void
403 rump_vp_vmobjlock(struct vnode *vp, int write)
404 {
405 
406 	rw_enter(vp->v_uobj.vmobjlock, write ? RW_WRITER : RW_READER);
407 }
408 
409 int
410 rump_vfs_unmount(struct mount *mp, int mntflags)
411 {
412 
413 	return VFS_UNMOUNT(mp, mntflags);
414 }
415 
416 int
417 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock)
418 {
419 	int rv;
420 
421 	rv = VFS_ROOT(mp, LK_EXCLUSIVE, vpp);
422 	if (rv)
423 		return rv;
424 
425 	if (!lock)
426 		VOP_UNLOCK(*vpp);
427 
428 	return 0;
429 }
430 
431 int
432 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp)
433 {
434 
435 	return VFS_STATVFS(mp, sbp);
436 }
437 
438 int
439 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred)
440 {
441 
442 	return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred);
443 }
444 
445 int
446 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
447 {
448 
449 	return VFS_FHTOVP(mp, fid, LK_EXCLUSIVE, vpp);
450 }
451 
452 int
453 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize)
454 {
455 
456 	return VFS_VPTOFH(vp, fid, fidsize);
457 }
458 
459 int
460 rump_vfs_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
461 	int attrnamespace, const char *attrname)
462 {
463 
464 	return VFS_EXTATTRCTL(mp, cmd, vp, attrnamespace, attrname);
465 }
466 
467 /*ARGSUSED*/
468 void
469 rump_vfs_syncwait(struct mount *mp)
470 {
471 	int n;
472 
473 	n = vfs_syncwait();
474 	if (n)
475 		printf("syncwait: unsynced buffers: %d\n", n);
476 }
477 
478 /*
479  * Dump info about mount point.  No locking.
480  */
481 static bool
482 rump_print_selector(void *cl, struct vnode *vp)
483 {
484 	int *full = cl;
485 
486 	KASSERT(mutex_owned(vp->v_interlock));
487 
488 	vfs_vnode_print(vp, *full, (void *)rumpuser_dprintf);
489 	return false;
490 }
491 
492 void
493 rump_vfs_mount_print(const char *path, int full)
494 {
495 #ifdef DEBUGPRINT
496 	struct vnode *mvp;
497 	struct vnode_iterator *marker;
498 	int error;
499 
500 	rumpuser_dprintf("\n==== dumping mountpoint at ``%s'' ====\n\n", path);
501 	if ((error = namei_simple_user(path, NSM_FOLLOW_NOEMULROOT, &mvp))!=0) {
502 		rumpuser_dprintf("==== lookup error %d ====\n\n", error);
503 		return;
504 	}
505 	vfs_mount_print(mvp->v_mount, full, (void *)rumpuser_dprintf);
506 	if (full) {
507 		rumpuser_dprintf("\n== dumping vnodes ==\n\n");
508 		vfs_vnode_iterator_init(mvp->v_mount, &marker);
509 		vfs_vnode_iterator_next(marker, rump_print_selector, &full);
510 		vfs_vnode_iterator_destroy(marker);
511 	}
512 	vrele(mvp);
513 	rumpuser_dprintf("\n==== done ====\n\n");
514 #else
515 	rumpuser_dprintf("mount dump not supported without DEBUGPRINT\n");
516 #endif
517 }
518 
519 void
520 rump_biodone(void *arg, size_t count, int error)
521 {
522 	struct buf *bp = arg;
523 
524 	bp->b_resid = bp->b_bcount - count;
525 	KASSERT(bp->b_resid >= 0);
526 	bp->b_error = error;
527 
528 	biodone(bp);
529 }
530