xref: /netbsd/sys/rump/librump/rumpvfs/rumpfs.c (revision 1b25d88d)
1 /*	$NetBSD: rumpfs.c,v 1.167 2023/06/27 19:30:27 andvar Exp $	*/
2 
3 /*
4  * Copyright (c) 2009, 2010, 2011 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.167 2023/06/27 19:30:27 andvar Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/atomic.h>
33 #include <sys/buf.h>
34 #include <sys/dirent.h>
35 #include <sys/errno.h>
36 #include <sys/filedesc.h>
37 #include <sys/fcntl.h>
38 #include <sys/kauth.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
43 #include <sys/lock.h>
44 #include <sys/lockf.h>
45 #include <sys/queue.h>
46 #include <sys/stat.h>
47 #include <sys/syscallargs.h>
48 #include <sys/vnode.h>
49 #include <sys/fstrans.h>
50 #include <sys/unistd.h>
51 
52 #include <miscfs/specfs/specdev.h>
53 #include <miscfs/genfs/genfs.h>
54 #include <miscfs/genfs/genfs_node.h>
55 
56 #include <uvm/uvm_extern.h>
57 
58 #include <rump-sys/kern.h>
59 #include <rump-sys/vfs.h>
60 
61 #include <rump/rumpfs.h>
62 #include <rump/rumpuser.h>
63 
64 static int rump_vop_parsepath(void *);
65 static int rump_vop_lookup(void *);
66 static int rump_vop_getattr(void *);
67 static int rump_vop_setattr(void *);
68 static int rump_vop_mkdir(void *);
69 static int rump_vop_rmdir(void *);
70 static int rump_vop_remove(void *);
71 static int rump_vop_mknod(void *);
72 static int rump_vop_create(void *);
73 static int rump_vop_inactive(void *);
74 static int rump_vop_reclaim(void *);
75 static int rump_vop_success(void *);
76 static int rump_vop_readdir(void *);
77 static int rump_vop_spec(void *);
78 static int rump_vop_read(void *);
79 static int rump_vop_write(void *);
80 static int rump_vop_open(void *);
81 static int rump_vop_symlink(void *);
82 static int rump_vop_readlink(void *);
83 static int rump_vop_whiteout(void *);
84 static int rump_vop_pathconf(void *);
85 static int rump_vop_bmap(void *);
86 static int rump_vop_strategy(void *);
87 static int rump_vop_advlock(void *);
88 static int rump_vop_access(void *);
89 static int rump_vop_fcntl(void *);
90 
91 int (**rump_vnodeop_p)(void *);
92 const struct vnodeopv_entry_desc rump_vnodeop_entries[] = {
93 	{ &vop_default_desc, vn_default_error },
94 	{ &vop_parsepath_desc, rump_vop_parsepath },
95 	{ &vop_lookup_desc, rump_vop_lookup },
96 	{ &vop_getattr_desc, rump_vop_getattr },
97 	{ &vop_setattr_desc, rump_vop_setattr },
98 	{ &vop_mkdir_desc, rump_vop_mkdir },
99 	{ &vop_rmdir_desc, rump_vop_rmdir },
100 	{ &vop_remove_desc, rump_vop_remove },
101 	{ &vop_mknod_desc, rump_vop_mknod },
102 	{ &vop_create_desc, rump_vop_create },
103 	{ &vop_symlink_desc, rump_vop_symlink },
104 	{ &vop_readlink_desc, rump_vop_readlink },
105 	{ &vop_access_desc, rump_vop_access },
106 	{ &vop_accessx_desc, genfs_accessx },
107 	{ &vop_readdir_desc, rump_vop_readdir },
108 	{ &vop_read_desc, rump_vop_read },
109 	{ &vop_write_desc, rump_vop_write },
110 	{ &vop_open_desc, rump_vop_open },
111 	{ &vop_close_desc, genfs_nullop },
112 	{ &vop_seek_desc, genfs_seek },
113 	{ &vop_getpages_desc, genfs_getpages },
114 	{ &vop_putpages_desc, genfs_putpages },
115 	{ &vop_whiteout_desc, rump_vop_whiteout },
116 	{ &vop_fsync_desc, rump_vop_success },
117 	{ &vop_lock_desc, genfs_lock },
118 	{ &vop_unlock_desc, genfs_unlock },
119 	{ &vop_islocked_desc, genfs_islocked },
120 	{ &vop_inactive_desc, rump_vop_inactive },
121 	{ &vop_reclaim_desc, rump_vop_reclaim },
122 	{ &vop_link_desc, genfs_eopnotsupp },
123 	{ &vop_pathconf_desc, rump_vop_pathconf },
124 	{ &vop_bmap_desc, rump_vop_bmap },
125 	{ &vop_strategy_desc, rump_vop_strategy },
126 	{ &vop_advlock_desc, rump_vop_advlock },
127 	{ &vop_fcntl_desc, rump_vop_fcntl },
128 	{ NULL, NULL }
129 };
130 const struct vnodeopv_desc rump_vnodeop_opv_desc =
131 	{ &rump_vnodeop_p, rump_vnodeop_entries };
132 
133 int (**rump_specop_p)(void *);
134 const struct vnodeopv_entry_desc rump_specop_entries[] = {
135 	{ &vop_default_desc, rump_vop_spec },
136 	{ NULL, NULL }
137 };
138 const struct vnodeopv_desc rump_specop_opv_desc =
139 	{ &rump_specop_p, rump_specop_entries };
140 
141 const struct vnodeopv_desc * const rump_opv_descs[] = {
142 	&rump_vnodeop_opv_desc,
143 	&rump_specop_opv_desc,
144 	NULL
145 };
146 
147 #define RUMPFS_WHITEOUT ((void *)-1)
148 #define RDENT_ISWHITEOUT(rdp) (rdp->rd_node == RUMPFS_WHITEOUT)
149 struct rumpfs_dent {
150 	char *rd_name;
151 	int rd_namelen;
152 	struct rumpfs_node *rd_node;
153 
154 	LIST_ENTRY(rumpfs_dent) rd_entries;
155 };
156 
157 struct genfs_ops rumpfs_genfsops = {
158 	.gop_size = genfs_size,
159 	.gop_write = genfs_gop_write,
160 	.gop_putrange = genfs_gop_putrange,
161 
162 	/* optional */
163 	.gop_alloc = NULL,
164 	.gop_markupdate = NULL,
165 };
166 
167 struct rumpfs_node {
168 	struct genfs_node rn_gn;
169 	struct vattr rn_va;
170 	struct vnode *rn_vp;
171 	char *rn_hostpath;
172 	int rn_flags;
173 	struct lockf *rn_lockf;
174 
175 	union {
176 		struct {		/* VREG */
177 			int readfd;
178 			int writefd;
179 			uint64_t offset;
180 		} reg;
181 		struct {
182 			void *data;
183 			size_t dlen;
184 		} reg_noet;
185 		struct {		/* VDIR */
186 			LIST_HEAD(, rumpfs_dent) dents;
187 			struct rumpfs_node *parent;
188 			int flags;
189 		} dir;
190 		struct {
191 			char *target;
192 			size_t len;
193 		} link;
194 	} rn_u;
195 };
196 #define rn_readfd	rn_u.reg.readfd
197 #define rn_writefd	rn_u.reg.writefd
198 #define rn_offset	rn_u.reg.offset
199 #define rn_data		rn_u.reg_noet.data
200 #define rn_dlen		rn_u.reg_noet.dlen
201 #define rn_dir		rn_u.dir.dents
202 #define rn_parent	rn_u.dir.parent
203 #define rn_linktarg	rn_u.link.target
204 #define rn_linklen	rn_u.link.len
205 
206 #define RUMPNODE_CANRECLAIM	0x01
207 #define RUMPNODE_DIR_ET		0x02
208 #define RUMPNODE_DIR_ETSUBS	0x04
209 #define RUMPNODE_ET_PHONE_HOST	0x10
210 #define RUMPNODE_EXTSTORAGE	0x20
211 
212 struct rumpfs_mount {
213 	struct vnode *rfsmp_rvp;
214 };
215 
216 #define INO_WHITEOUT 1
217 static int lastino = 2;
218 static kmutex_t reclock;
219 
220 #define RUMPFS_DEFAULTMODE 0755
221 static void freedir(struct rumpfs_node *, struct componentname *);
222 static struct rumpfs_node *makeprivate(enum vtype, mode_t, dev_t, off_t, bool);
223 static void freeprivate(struct rumpfs_node *);
224 
225 /*
226  * Extra Terrestrial stuff.  We map a given key (pathname) to a file on
227  * the host FS.  ET phones home only from the root node of rumpfs.
228  *
229  * When an etfs node is removed, a vnode potentially behind it is not
230  * immediately recycled.
231  */
232 
233 struct etfs {
234 	char et_key[MAXPATHLEN];
235 	size_t et_keylen;
236 	bool et_prefixkey;
237 	bool et_removing;
238 	devminor_t et_blkmin;
239 
240 	LIST_ENTRY(etfs) et_entries;
241 
242 	struct rumpfs_node *et_rn;
243 };
244 static kmutex_t etfs_lock;
245 static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list);
246 
247 static enum vtype
ettype_to_vtype(enum rump_etfs_type et)248 ettype_to_vtype(enum rump_etfs_type et)
249 {
250 	enum vtype vt;
251 
252 	switch (et) {
253 	case RUMP_ETFS_REG:
254 		vt = VREG;
255 		break;
256 	case RUMP_ETFS_BLK:
257 		vt = VBLK;
258 		break;
259 	case RUMP_ETFS_CHR:
260 		vt = VCHR;
261 		break;
262 	case RUMP_ETFS_DIR:
263 		vt = VDIR;
264 		break;
265 	case RUMP_ETFS_DIR_SUBDIRS:
266 		vt = VDIR;
267 		break;
268 	default:
269 		panic("invalid et type: %d", et);
270 	}
271 
272 	return vt;
273 }
274 
275 static enum vtype
hft_to_vtype(int hft)276 hft_to_vtype(int hft)
277 {
278 	enum vtype vt;
279 
280 	switch (hft) {
281 	case RUMPUSER_FT_OTHER:
282 		vt = VNON;
283 		break;
284 	case RUMPUSER_FT_DIR:
285 		vt = VDIR;
286 		break;
287 	case RUMPUSER_FT_REG:
288 		vt = VREG;
289 		break;
290 	case RUMPUSER_FT_BLK:
291 		vt = VBLK;
292 		break;
293 	case RUMPUSER_FT_CHR:
294 		vt = VCHR;
295 		break;
296 	default:
297 		vt = VNON;
298 		break;
299 	}
300 
301 	return vt;
302 }
303 
304 static bool
etfs_find(const char * key,struct etfs ** etp,bool forceprefix)305 etfs_find(const char *key, struct etfs **etp, bool forceprefix)
306 {
307 	struct etfs *et;
308 	size_t keylen = strlen(key);
309 
310 	KASSERT(mutex_owned(&etfs_lock));
311 
312 	LIST_FOREACH(et, &etfs_list, et_entries) {
313 		if ((keylen == et->et_keylen || et->et_prefixkey || forceprefix)
314 		    && strncmp(key, et->et_key, et->et_keylen) == 0) {
315 			if (etp)
316 				*etp = et;
317 			return true;
318 		}
319 	}
320 
321 	return false;
322 }
323 
324 #define REGDIR(ftype) \
325     ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS)
326 static int
etfsregister(const char * key,const char * hostpath,enum rump_etfs_type ftype,uint64_t begin,uint64_t size)327 etfsregister(const char *key, const char *hostpath,
328 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
329 {
330 	char buf[9];
331 	struct etfs *et;
332 	struct rumpfs_node *rn;
333 	uint64_t fsize;
334 	dev_t rdev = NODEV;
335 	devminor_t dmin = -1;
336 	int hft, error;
337 
338 	if (key[0] != '/') {
339 		return EINVAL;
340 	}
341 	while (key[0] == '/') {
342 		key++;
343 	}
344 
345 	if ((error = rumpuser_getfileinfo(hostpath, &fsize, &hft)) != 0)
346 		return error;
347 
348 	/* etfs directory requires a directory on the host */
349 	if (REGDIR(ftype)) {
350 		if (hft != RUMPUSER_FT_DIR)
351 			return ENOTDIR;
352 		if (begin != 0)
353 			return EISDIR;
354 		if (size != RUMP_ETFS_SIZE_ENDOFF)
355 			return EISDIR;
356 		size = fsize;
357 	} else {
358 		if (begin > fsize)
359 			return EINVAL;
360 		if (size == RUMP_ETFS_SIZE_ENDOFF)
361 			size = fsize - begin;
362 		if (begin + size > fsize)
363 			return EINVAL;
364 	}
365 
366 	if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) {
367 		error = rumpblk_register(hostpath, &dmin, begin, size);
368 		if (error != 0) {
369 			return error;
370 		}
371 		rdev = makedev(RUMPBLK_DEVMAJOR, dmin);
372 	}
373 
374 	et = kmem_alloc(sizeof(*et), KM_SLEEP);
375 	strcpy(et->et_key, key);
376 	et->et_keylen = strlen(et->et_key);
377 	et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), RUMPFS_DEFAULTMODE,
378 	    rdev, size, true);
379 	et->et_removing = false;
380 	et->et_blkmin = dmin;
381 
382 	rn->rn_flags |= RUMPNODE_ET_PHONE_HOST;
383 
384 	if (ftype == RUMP_ETFS_REG || REGDIR(ftype) || et->et_blkmin != -1) {
385 		size_t len = strlen(hostpath)+1;
386 
387 		rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
388 		memcpy(rn->rn_hostpath, hostpath, len);
389 		rn->rn_offset = begin;
390 	}
391 
392 	if (REGDIR(ftype)) {
393 		rn->rn_flags |= RUMPNODE_DIR_ET;
394 		et->et_prefixkey = true;
395 	} else {
396 		et->et_prefixkey = false;
397 	}
398 
399 	if (ftype == RUMP_ETFS_DIR_SUBDIRS)
400 		rn->rn_flags |= RUMPNODE_DIR_ETSUBS;
401 
402 	mutex_enter(&etfs_lock);
403 	if (etfs_find(key, NULL, REGDIR(ftype))) {
404 		mutex_exit(&etfs_lock);
405 		if (et->et_blkmin != -1)
406 			rumpblk_deregister(hostpath);
407 		if (et->et_rn->rn_hostpath != NULL)
408 			free(et->et_rn->rn_hostpath, M_TEMP);
409 		freeprivate(et->et_rn);
410 		kmem_free(et, sizeof(*et));
411 		return EEXIST;
412 	}
413 	LIST_INSERT_HEAD(&etfs_list, et, et_entries);
414 	mutex_exit(&etfs_lock);
415 
416 	if (ftype == RUMP_ETFS_BLK) {
417 		format_bytes(buf, sizeof(buf), size);
418 		aprint_verbose("/%s: hostpath %s (%s)\n", key, hostpath, buf);
419 	}
420 
421 	return 0;
422 }
423 #undef REGDIR
424 
425 /* remove etfs mapping.  caller's responsibility to make sure it's not in use */
426 static int
etfsremove(const char * key)427 etfsremove(const char *key)
428 {
429 	struct etfs *et;
430 	size_t keylen;
431 	int rv __diagused;
432 
433 	if (key[0] != '/') {
434 		return EINVAL;
435 	}
436 	while (key[0] == '/') {
437 		key++;
438 	}
439 
440 	keylen = strlen(key);
441 
442 	mutex_enter(&etfs_lock);
443 	LIST_FOREACH(et, &etfs_list, et_entries) {
444 		if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) {
445 			if (et->et_removing)
446 				et = NULL;
447 			else
448 				et->et_removing = true;
449 			break;
450 		}
451 	}
452 	mutex_exit(&etfs_lock);
453 	if (!et)
454 		return ENOENT;
455 
456 	/*
457 	 * ok, we know what we want to remove and have signalled there
458 	 * actually are men at work.  first, unregister from rumpblk
459 	 */
460 	if (et->et_blkmin != -1) {
461 		rv = rumpblk_deregister(et->et_rn->rn_hostpath);
462 	} else {
463 		rv = 0;
464 	}
465 	KASSERT(rv == 0);
466 
467 	/* then do the actual removal */
468 	mutex_enter(&etfs_lock);
469 	LIST_REMOVE(et, et_entries);
470 	mutex_exit(&etfs_lock);
471 
472 	/* node is unreachable, safe to nuke all device copies */
473 	if (et->et_blkmin != -1) {
474 		vdevgone(RUMPBLK_DEVMAJOR, et->et_blkmin, et->et_blkmin, VBLK);
475 	} else {
476 		struct vnode *vp;
477 		struct mount *mp;
478 		struct rumpfs_node *rn;
479 
480 		mutex_enter(&reclock);
481 		if ((vp = et->et_rn->rn_vp) != NULL) {
482 			mp = vp->v_mount;
483 			rn = vp->v_data;
484 			KASSERT(rn == et->et_rn);
485 		} else {
486 			mp = NULL;
487 		}
488 		mutex_exit(&reclock);
489 		if (mp && vcache_get(mp, &rn, sizeof(rn), &vp) == 0) {
490 			rv = vfs_suspend(mp, 0);
491 			KASSERT(rv == 0);
492 			vgone(vp);
493 			vfs_resume(mp);
494 		}
495 	}
496 
497 	if (et->et_rn->rn_hostpath != NULL)
498 		free(et->et_rn->rn_hostpath, M_TEMP);
499 	freeprivate(et->et_rn);
500 	kmem_free(et, sizeof(*et));
501 
502 	return 0;
503 }
504 
505 /*
506  * rumpfs
507  */
508 
509 static struct rumpfs_node *
makeprivate(enum vtype vt,mode_t mode,dev_t rdev,off_t size,bool et)510 makeprivate(enum vtype vt, mode_t mode, dev_t rdev, off_t size, bool et)
511 {
512 	struct rumpfs_node *rn;
513 	struct vattr *va;
514 	struct timespec ts;
515 
516 	KASSERT((mode & ~ALLPERMS) == 0);
517 	rn = kmem_zalloc(sizeof(*rn), KM_SLEEP);
518 
519 	switch (vt) {
520 	case VDIR:
521 		LIST_INIT(&rn->rn_dir);
522 		break;
523 	case VREG:
524 		if (et) {
525 			rn->rn_readfd = -1;
526 			rn->rn_writefd = -1;
527 		}
528 		break;
529 	default:
530 		break;
531 	}
532 
533 	nanotime(&ts);
534 
535 	va = &rn->rn_va;
536 	va->va_type = vt;
537 	va->va_mode = mode;
538 	if (vt == VDIR)
539 		va->va_nlink = 2;
540 	else
541 		va->va_nlink = 1;
542 	va->va_uid = 0;
543 	va->va_gid = 0;
544 	va->va_fsid =
545 	va->va_fileid = atomic_inc_uint_nv(&lastino);
546 	va->va_size = size;
547 	va->va_blocksize = 512;
548 	va->va_atime = ts;
549 	va->va_mtime = ts;
550 	va->va_ctime = ts;
551 	va->va_birthtime = ts;
552 	va->va_gen = 0;
553 	va->va_flags = 0;
554 	va->va_rdev = rdev;
555 	va->va_bytes = 512;
556 	va->va_filerev = 0;
557 	va->va_vaflags = 0;
558 
559 	return rn;
560 }
561 
562 static void
freeprivate(struct rumpfs_node * rn)563 freeprivate(struct rumpfs_node *rn)
564 {
565 
566 	kmem_free(rn, sizeof(*rn));
567 }
568 
569 static void
makedir(struct rumpfs_node * rnd,struct componentname * cnp,struct rumpfs_node * rn)570 makedir(struct rumpfs_node *rnd,
571 	struct componentname *cnp, struct rumpfs_node *rn)
572 {
573 	struct rumpfs_dent *rdent;
574 
575 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
576 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
577 	rdent->rd_node = rn;
578 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
579 	rdent->rd_namelen = strlen(rdent->rd_name);
580 
581 	if ((cnp->cn_flags & ISWHITEOUT) != 0) {
582 		KASSERT((cnp->cn_flags & DOWHITEOUT) == 0);
583 		freedir(rnd, cnp);
584 	}
585 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
586 }
587 
588 static void
freedir(struct rumpfs_node * rnd,struct componentname * cnp)589 freedir(struct rumpfs_node *rnd, struct componentname *cnp)
590 {
591 	struct rumpfs_dent *rd = NULL;
592 
593 	LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
594 		if (rd->rd_namelen == cnp->cn_namelen &&
595 		    strncmp(rd->rd_name, cnp->cn_nameptr,
596 		            cnp->cn_namelen) == 0)
597 			break;
598 	}
599 	if (rd == NULL)
600 		panic("could not find directory entry: %s", cnp->cn_nameptr);
601 
602 	if (cnp->cn_flags & DOWHITEOUT) {
603 		rd->rd_node = RUMPFS_WHITEOUT;
604 	} else {
605 		LIST_REMOVE(rd, rd_entries);
606 		kmem_free(rd->rd_name, rd->rd_namelen+1);
607 		kmem_free(rd, sizeof(*rd));
608 	}
609 }
610 
611 #define	RUMPFS_ACCESS	1
612 #define	RUMPFS_MODIFY	2
613 #define	RUMPFS_CHANGE	4
614 
615 static int
rumpfs_update(int flags,struct vnode * vp,const struct timespec * acc,const struct timespec * mod,const struct timespec * chg)616 rumpfs_update(int flags, struct vnode *vp, const struct timespec *acc,
617     const struct timespec *mod, const struct timespec *chg)
618 {
619 	struct rumpfs_node *rn = vp->v_data;
620 
621 	if (flags == 0)
622 		return 0;
623 
624 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
625 		return EROFS;
626 
627 	if (flags & RUMPFS_ACCESS)
628 		rn->rn_va.va_atime = *acc;
629 	if (flags & RUMPFS_MODIFY)
630 		rn->rn_va.va_mtime = *mod;
631 	if (flags & RUMPFS_CHANGE)
632 		rn->rn_va.va_ctime = *chg;
633 
634 	return 0;
635 }
636 
637 /*
638  * parsepath for rump file systems - check for etfs entries.
639  */
640 static int
rump_vop_parsepath(void * v)641 rump_vop_parsepath(void *v)
642 {
643 	struct vop_parsepath_args /* {
644 		struct vnode *a_dvp;
645 		const char *a_name;
646 		size_t *a_retval;
647 	}; */ *ap = v;
648 	struct etfs *et;
649 	bool found;
650 
651 	/* check for etfs */
652 	if (ap->a_dvp == rootvnode) {
653 		mutex_enter(&etfs_lock);
654 		found = etfs_find(ap->a_name, &et, false);
655 		mutex_exit(&etfs_lock);
656 		if (found) {
657 			*ap->a_retval = et->et_keylen;
658 			return 0;
659 		}
660 	}
661 	return genfs_parsepath(v);
662 }
663 
664 /*
665  * Simple lookup for rump file systems.
666  *
667  * uhm, this is twisted.  C F C C, hope of C C F C looming
668  */
669 static int
rump_vop_lookup(void * v)670 rump_vop_lookup(void *v)
671 {
672 	struct vop_lookup_v2_args /* {
673 		struct vnode *a_dvp;
674 		struct vnode **a_vpp;
675 		struct componentname *a_cnp;
676 	}; */ *ap = v;
677 	struct componentname *cnp = ap->a_cnp;
678 	struct vnode *dvp = ap->a_dvp;
679 	struct vnode **vpp = ap->a_vpp;
680 	struct rumpfs_node *rnd = dvp->v_data, *rn;
681 	struct rumpfs_dent *rd = NULL;
682 	struct etfs *et;
683 	bool dotdot = (cnp->cn_flags & ISDOTDOT) != 0;
684 	int rv = 0;
685 
686 	*vpp = NULL;
687 
688 	rv = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
689 	if (rv)
690 		return rv;
691 
692 	if ((cnp->cn_flags & ISLASTCN)
693 	    && (dvp->v_mount->mnt_flag & MNT_RDONLY)
694 	    && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
695 		return EROFS;
696 
697 	/* check for dot, return directly if the case */
698 	if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
699 		vref(dvp);
700 		*vpp = dvp;
701 		return 0;
702 	}
703 
704 	/* we don't do rename */
705 	if (!(((cnp->cn_flags & ISLASTCN) == 0) || (cnp->cn_nameiop != RENAME)))
706 		return EOPNOTSUPP;
707 
708 	/* check for etfs */
709 	if (dvp == rootvnode &&
710 	    (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == CREATE)) {
711 		bool found;
712 		mutex_enter(&etfs_lock);
713 		found = etfs_find(cnp->cn_nameptr, &et, false);
714 		mutex_exit(&etfs_lock);
715 
716 		if (found) {
717 			if (et->et_keylen != cnp->cn_namelen) {
718 				/*
719 				 * This can theoretically happen if an
720 				 * etfs entry is added or removed
721 				 * while lookups are being done as we
722 				 * don't hold etfs_lock across here
723 				 * and parsepath. Won't ordinarily be
724 				 * the case. No biggie, just retry.
725 				 */
726 				return ERESTART;
727 			}
728 			rn = et->et_rn;
729 			goto getvnode;
730 		}
731 	}
732 
733 	if (rnd->rn_flags & RUMPNODE_DIR_ET) {
734 		uint64_t fsize;
735 		char *newpath;
736 		size_t newpathlen;
737 		int hft, error;
738 
739 		if (dotdot)
740 			return EOPNOTSUPP;
741 
742 		newpathlen = strlen(rnd->rn_hostpath) + 1 + cnp->cn_namelen + 1;
743 		newpath = malloc(newpathlen, M_TEMP, M_WAITOK);
744 
745 		strlcpy(newpath, rnd->rn_hostpath, newpathlen);
746 		strlcat(newpath, "/", newpathlen);
747 		strlcat(newpath, cnp->cn_nameptr, newpathlen);
748 
749 		if ((error = rumpuser_getfileinfo(newpath, &fsize, &hft)) != 0){
750 			free(newpath, M_TEMP);
751 			return error;
752 		}
753 
754 		/* allow only dirs and regular files */
755 		if (hft != RUMPUSER_FT_REG && hft != RUMPUSER_FT_DIR) {
756 			free(newpath, M_TEMP);
757 			return ENOENT;
758 		}
759 
760 		rn = makeprivate(hft_to_vtype(hft), RUMPFS_DEFAULTMODE,
761 		    NODEV, fsize, true);
762 		rn->rn_flags |= RUMPNODE_CANRECLAIM;
763 		if (rnd->rn_flags & RUMPNODE_DIR_ETSUBS) {
764 			rn->rn_flags |= RUMPNODE_DIR_ET | RUMPNODE_DIR_ETSUBS;
765 			rn->rn_flags |= RUMPNODE_ET_PHONE_HOST;
766 		}
767 		rn->rn_hostpath = newpath;
768 
769 		goto getvnode;
770 	} else {
771 		if (dotdot) {
772 			if ((rn = rnd->rn_parent) != NULL)
773 				goto getvnode;
774 		} else {
775 			LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
776 				if (rd->rd_namelen == cnp->cn_namelen &&
777 				    strncmp(rd->rd_name, cnp->cn_nameptr,
778 				      cnp->cn_namelen) == 0)
779 					break;
780 			}
781 		}
782 	}
783 
784 	if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE))
785 		return ENOENT;
786 
787 	if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
788 		if (dvp->v_mount->mnt_flag & MNT_RDONLY)
789 			return EROFS;
790 		rv = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
791 		if (rv)
792 			return rv;
793 		return EJUSTRETURN;
794 	}
795 
796 	if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == DELETE) {
797 		rv = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
798 		if (rv)
799 			return rv;
800 	}
801 
802 	if (RDENT_ISWHITEOUT(rd)) {
803 		cnp->cn_flags |= ISWHITEOUT;
804 		if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE)
805 			return EJUSTRETURN;
806 		return ENOENT;
807 	}
808 
809 	rn = rd->rd_node;
810 
811  getvnode:
812 	KASSERT(rn);
813 	rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp);
814 	if (rv) {
815 		if (rnd->rn_flags & RUMPNODE_DIR_ET)
816 			freeprivate(rn);
817 		return rv;
818 	}
819 
820 	return 0;
821 }
822 
823 static int
rump_check_possible(struct vnode * vp,struct rumpfs_node * rnode,mode_t mode)824 rump_check_possible(struct vnode *vp, struct rumpfs_node *rnode,
825     mode_t mode)
826 {
827 
828 	if ((mode & VWRITE) == 0)
829 		return 0;
830 
831 	switch (vp->v_type) {
832 	case VDIR:
833 	case VLNK:
834 	case VREG:
835 		break;
836 	default:
837 		/* special file is always writable. */
838 		return 0;
839 	}
840 
841 	return vp->v_mount->mnt_flag & MNT_RDONLY ? EROFS : 0;
842 }
843 
844 static int
rump_check_permitted(struct vnode * vp,struct rumpfs_node * rnode,accmode_t accmode,kauth_cred_t cred)845 rump_check_permitted(struct vnode *vp, struct rumpfs_node *rnode,
846     accmode_t accmode, kauth_cred_t cred)
847 {
848 	struct vattr *attr = &rnode->rn_va;
849 
850 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
851 	    vp->v_type, attr->va_mode), vp, NULL, genfs_can_access(vp, cred,
852 	    attr->va_uid, attr->va_gid, attr->va_mode, NULL, accmode));
853 }
854 
855 int
rump_vop_access(void * v)856 rump_vop_access(void *v)
857 {
858 	struct vop_access_args /* {
859 		const struct vnodeop_desc *a_desc;
860 		struct vnode *a_vp;
861 		int a_mode;
862 		kauth_cred_t a_cred;
863 	} */ *ap = v;
864 	struct vnode *vp = ap->a_vp;
865 	struct rumpfs_node *rn = vp->v_data;
866 	int error;
867 
868 	error = rump_check_possible(vp, rn, ap->a_accmode);
869 	if (error)
870 		return error;
871 
872 	error = rump_check_permitted(vp, rn, ap->a_accmode, ap->a_cred);
873 
874 	return error;
875 }
876 
877 static int
rump_vop_getattr(void * v)878 rump_vop_getattr(void *v)
879 {
880 	struct vop_getattr_args /* {
881 		struct vnode *a_vp;
882 		struct vattr *a_vap;
883 		kauth_cred_t a_cred;
884 	} */ *ap = v;
885 	struct vnode *vp = ap->a_vp;
886 	struct rumpfs_node *rn = vp->v_data;
887 	struct vattr *vap = ap->a_vap;
888 
889 	memcpy(vap, &rn->rn_va, sizeof(struct vattr));
890 	vap->va_size = vp->v_size;
891 	return 0;
892 }
893 
894 static int
rump_vop_setattr(void * v)895 rump_vop_setattr(void *v)
896 {
897 	struct vop_setattr_args /* {
898 		struct vnode *a_vp;
899 		struct vattr *a_vap;
900 		kauth_cred_t a_cred;
901 	} */ *ap = v;
902 	struct vnode *vp = ap->a_vp;
903 	struct vattr *vap = ap->a_vap;
904 	struct rumpfs_node *rn = vp->v_data;
905 	struct vattr *attr = &rn->rn_va;
906 	struct timespec now;
907 	kauth_cred_t cred = ap->a_cred;
908 	int error;
909 
910 #define	CHANGED(a, t)	(vap->a != (t)VNOVAL)
911 #define SETIFVAL(a,t) if (CHANGED(a, t)) rn->rn_va.a = vap->a
912 	if (CHANGED(va_atime.tv_sec, time_t) ||
913 	    CHANGED(va_ctime.tv_sec, time_t) ||
914 	    CHANGED(va_mtime.tv_sec, time_t) ||
915 	    CHANGED(va_birthtime.tv_sec, time_t) ||
916 	    CHANGED(va_atime.tv_nsec, long) ||
917 	    CHANGED(va_ctime.tv_nsec, long) ||
918 	    CHANGED(va_mtime.tv_nsec, long) ||
919 	    CHANGED(va_birthtime.tv_nsec, long)) {
920 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
921 		    NULL, genfs_can_chtimes(vp, cred, attr->va_uid,
922 		    vap->va_vaflags));
923 		if (error)
924 			return error;
925 	}
926 
927 	int flags = 0;
928 	getnanotime(&now);
929 	if (vap->va_atime.tv_sec != VNOVAL)
930 		if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
931 			flags |= RUMPFS_ACCESS;
932 	if (vap->va_mtime.tv_sec != VNOVAL) {
933 		flags |= RUMPFS_CHANGE | RUMPFS_MODIFY;
934 		if (vp->v_mount->mnt_flag & MNT_RELATIME)
935 			flags |= RUMPFS_ACCESS;
936 	} else if (vap->va_size == 0) {
937 		flags |= RUMPFS_MODIFY;
938 		vap->va_mtime = now;
939 	}
940 	SETIFVAL(va_birthtime.tv_sec, time_t);
941 	SETIFVAL(va_birthtime.tv_nsec, long);
942 	flags |= RUMPFS_CHANGE;
943 	error = rumpfs_update(flags, vp, &vap->va_atime, &vap->va_mtime, &now);
944 	if (error)
945 		return error;
946 
947 	if (CHANGED(va_flags, u_long)) {
948 		/* XXX Can we handle system flags here...? */
949 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp,
950 		    NULL, genfs_can_chflags(vp, cred, attr->va_uid, false));
951 		if (error)
952 			return error;
953 	}
954 
955 	SETIFVAL(va_flags, u_long);
956 #undef  SETIFVAL
957 #undef	CHANGED
958 
959 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) {
960 		uid_t uid =
961 		    (vap->va_uid != (uid_t)VNOVAL) ? vap->va_uid : attr->va_uid;
962 		gid_t gid =
963 		    (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->va_gid;
964 		error = kauth_authorize_vnode(cred,
965 		    KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
966 		    genfs_can_chown(vp, cred, attr->va_uid, attr->va_gid, uid,
967 		    gid));
968 		if (error)
969 			return error;
970 		attr->va_uid = uid;
971 		attr->va_gid = gid;
972 	}
973 
974 	if (vap->va_mode != (mode_t)VNOVAL) {
975 		mode_t mode = vap->va_mode;
976 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
977 		    vp, NULL, genfs_can_chmod(vp, cred, attr->va_uid,
978 		    attr->va_gid, mode));
979 		if (error)
980 			return error;
981 		attr->va_mode = mode;
982 	}
983 
984 	if (vp->v_type == VREG &&
985 	    vap->va_size != VSIZENOTSET &&
986 	    vap->va_size != rn->rn_dlen &&
987 	    (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0) {
988 		void *newdata;
989 		size_t copylen, newlen;
990 
991 		newlen = vap->va_size;
992 		newdata = rump_hypermalloc(newlen, 0, false, "rumpfs");
993 		if (newdata == NULL)
994 			return ENOSPC;
995 
996 		copylen = MIN(rn->rn_dlen, newlen);
997 		if (copylen > 0)
998 			memcpy(newdata, rn->rn_data, copylen);
999 		memset((char *)newdata + copylen, 0, newlen - copylen);
1000 
1001 		if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) {
1002 			rump_hyperfree(rn->rn_data, rn->rn_dlen);
1003 		} else {
1004 			rn->rn_flags &= ~RUMPNODE_EXTSTORAGE;
1005 		}
1006 
1007 		rn->rn_data = newdata;
1008 		rn->rn_dlen = newlen;
1009 		uvm_vnp_setsize(vp, newlen);
1010 	}
1011 	return 0;
1012 }
1013 
1014 static int
rump_vop_mkdir(void * v)1015 rump_vop_mkdir(void *v)
1016 {
1017 	struct vop_mkdir_v3_args /* {
1018 		struct vnode *a_dvp;
1019 		struct vnode **a_vpp;
1020 		struct componentname *a_cnp;
1021 		struct vattr *a_vap;
1022 	}; */ *ap = v;
1023 	struct vnode *dvp = ap->a_dvp;
1024 	struct vnode **vpp = ap->a_vpp;
1025 	struct componentname *cnp = ap->a_cnp;
1026 	struct vattr *va = ap->a_vap;
1027 	struct rumpfs_node *rnd = dvp->v_data, *rn;
1028 	int rv = 0;
1029 
1030 	rn = makeprivate(VDIR, va->va_mode & ALLPERMS, NODEV, DEV_BSIZE, false);
1031 	if ((cnp->cn_flags & ISWHITEOUT) != 0)
1032 		rn->rn_va.va_flags |= UF_OPAQUE;
1033 	rn->rn_parent = rnd;
1034 	rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp);
1035 	if (rv) {
1036 		freeprivate(rn);
1037 		return rv;
1038 	}
1039 
1040 	makedir(rnd, cnp, rn);
1041 
1042 	return rv;
1043 }
1044 
1045 static int
rump_vop_rmdir(void * v)1046 rump_vop_rmdir(void *v)
1047 {
1048         struct vop_rmdir_v2_args /* {
1049                 struct vnode *a_dvp;
1050                 struct vnode *a_vp;
1051                 struct componentname *a_cnp;
1052         }; */ *ap = v;
1053 	struct vnode *dvp = ap->a_dvp;
1054 	struct vnode *vp = ap->a_vp;
1055 	struct componentname *cnp = ap->a_cnp;
1056 	struct rumpfs_node *rnd = dvp->v_data;
1057 	struct rumpfs_node *rn = vp->v_data;
1058 	struct rumpfs_dent *rd;
1059 	int rv = 0;
1060 
1061 	LIST_FOREACH(rd, &rn->rn_dir, rd_entries) {
1062 		if (rd->rd_node != RUMPFS_WHITEOUT) {
1063 			rv = ENOTEMPTY;
1064 			goto out;
1065 		}
1066 	}
1067 	while ((rd = LIST_FIRST(&rn->rn_dir)) != NULL) {
1068 		KASSERT(rd->rd_node == RUMPFS_WHITEOUT);
1069 		LIST_REMOVE(rd, rd_entries);
1070 		kmem_free(rd->rd_name, rd->rd_namelen+1);
1071 		kmem_free(rd, sizeof(*rd));
1072 	}
1073 
1074 	freedir(rnd, cnp);
1075 	rn->rn_flags |= RUMPNODE_CANRECLAIM;
1076 	rn->rn_parent = NULL;
1077 	rn->rn_va.va_nlink = 0;
1078 
1079 out:
1080 	vput(vp);
1081 	return rv;
1082 }
1083 
1084 static int
rump_vop_remove(void * v)1085 rump_vop_remove(void *v)
1086 {
1087         struct vop_remove_v3_args /* {
1088                 struct vnode *a_dvp;
1089                 struct vnode *a_vp;
1090                 struct componentname *a_cnp;
1091 		nlink_t ctx_vp_new_nlink;
1092         }; */ *ap = v;
1093 	struct vnode *dvp = ap->a_dvp;
1094 	struct vnode *vp = ap->a_vp;
1095 	struct componentname *cnp = ap->a_cnp;
1096 	struct rumpfs_node *rnd = dvp->v_data;
1097 	struct rumpfs_node *rn = vp->v_data;
1098 	int rv = 0;
1099 
1100 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
1101 		return EOPNOTSUPP;
1102 
1103 	freedir(rnd, cnp);
1104 	rn->rn_flags |= RUMPNODE_CANRECLAIM;
1105 	rn->rn_va.va_nlink = 0;
1106 
1107 	vput(vp);
1108 	return rv;
1109 }
1110 
1111 static int
rump_vop_mknod(void * v)1112 rump_vop_mknod(void *v)
1113 {
1114 	struct vop_mknod_v3_args /* {
1115 		struct vnode *a_dvp;
1116 		struct vnode **a_vpp;
1117 		struct componentname *a_cnp;
1118 		struct vattr *a_vap;
1119 	}; */ *ap = v;
1120 	struct vnode *dvp = ap->a_dvp;
1121 	struct vnode **vpp = ap->a_vpp;
1122 	struct componentname *cnp = ap->a_cnp;
1123 	struct vattr *va = ap->a_vap;
1124 	struct rumpfs_node *rnd = dvp->v_data, *rn;
1125 	int rv;
1126 
1127 	rn = makeprivate(va->va_type, va->va_mode & ALLPERMS, va->va_rdev,
1128 	    DEV_BSIZE, false);
1129 	if ((cnp->cn_flags & ISWHITEOUT) != 0)
1130 		rn->rn_va.va_flags |= UF_OPAQUE;
1131 	rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp);
1132 	if (rv) {
1133 		freeprivate(rn);
1134 		return rv;
1135 	}
1136 
1137 	makedir(rnd, cnp, rn);
1138 
1139 	return rv;
1140 }
1141 
1142 static int
rump_vop_create(void * v)1143 rump_vop_create(void *v)
1144 {
1145 	struct vop_create_v3_args /* {
1146 		struct vnode *a_dvp;
1147 		struct vnode **a_vpp;
1148 		struct componentname *a_cnp;
1149 		struct vattr *a_vap;
1150 	}; */ *ap = v;
1151 	struct vnode *dvp = ap->a_dvp;
1152 	struct vnode **vpp = ap->a_vpp;
1153 	struct componentname *cnp = ap->a_cnp;
1154 	struct vattr *va = ap->a_vap;
1155 	struct rumpfs_node *rnd = dvp->v_data, *rn;
1156 	off_t newsize;
1157 	int rv;
1158 
1159 	newsize = va->va_type == VSOCK ? DEV_BSIZE : 0;
1160 	rn = makeprivate(va->va_type, va->va_mode & ALLPERMS, NODEV,
1161 	    newsize, false);
1162 	if ((cnp->cn_flags & ISWHITEOUT) != 0)
1163 		rn->rn_va.va_flags |= UF_OPAQUE;
1164 	rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp);
1165 	if (rv) {
1166 		freeprivate(rn);
1167 		return rv;
1168 	}
1169 
1170 	makedir(rnd, cnp, rn);
1171 
1172 	return rv;
1173 }
1174 
1175 static int
rump_vop_symlink(void * v)1176 rump_vop_symlink(void *v)
1177 {
1178 	struct vop_symlink_v3_args /* {
1179 		struct vnode *a_dvp;
1180 		struct vnode **a_vpp;
1181 		struct componentname *a_cnp;
1182 		struct vattr *a_vap;
1183 		char *a_target;
1184 	}; */ *ap = v;
1185 	struct vnode *dvp = ap->a_dvp;
1186 	struct vnode **vpp = ap->a_vpp;
1187 	struct componentname *cnp = ap->a_cnp;
1188 	struct vattr *va = ap->a_vap;
1189 	struct rumpfs_node *rnd = dvp->v_data, *rn;
1190 	const char *target = ap->a_target;
1191 	size_t linklen;
1192 	int rv;
1193 
1194 	linklen = strlen(target);
1195 	KASSERT(linklen < MAXPATHLEN);
1196 	rn = makeprivate(VLNK, va->va_mode & ALLPERMS, NODEV, linklen, false);
1197 	if ((cnp->cn_flags & ISWHITEOUT) != 0)
1198 		rn->rn_va.va_flags |= UF_OPAQUE;
1199 	rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp);
1200 	if (rv) {
1201 		freeprivate(rn);
1202 		return rv;
1203 	}
1204 
1205 	makedir(rnd, cnp, rn);
1206 
1207 	KASSERT(linklen < MAXPATHLEN);
1208 	rn->rn_linktarg = PNBUF_GET();
1209 	rn->rn_linklen = linklen;
1210 	strcpy(rn->rn_linktarg, target);
1211 
1212 	return rv;
1213 }
1214 
1215 static int
rump_vop_readlink(void * v)1216 rump_vop_readlink(void *v)
1217 {
1218 	struct vop_readlink_args /* {
1219 		struct vnode *a_vp;
1220 		struct uio *a_uio;
1221 		kauth_cred_t a_cred;
1222 	}; */ *ap = v;
1223 	struct vnode *vp = ap->a_vp;
1224 	struct rumpfs_node *rn = vp->v_data;
1225 	struct uio *uio = ap->a_uio;
1226 
1227 	return uiomove(rn->rn_linktarg, rn->rn_linklen, uio);
1228 }
1229 
1230 static int
rump_vop_whiteout(void * v)1231 rump_vop_whiteout(void *v)
1232 {
1233 	struct vop_whiteout_args /* {
1234 		struct vnode            *a_dvp;
1235 		struct componentname    *a_cnp;
1236 		int                     a_flags;
1237 	} */ *ap = v;
1238 	struct vnode *dvp = ap->a_dvp;
1239 	struct rumpfs_node *rnd = dvp->v_data;
1240 	struct componentname *cnp = ap->a_cnp;
1241 	int flags = ap->a_flags;
1242 
1243 	switch (flags) {
1244 	case LOOKUP:
1245 		break;
1246 	case CREATE:
1247 		makedir(rnd, cnp, RUMPFS_WHITEOUT);
1248 		break;
1249 	case DELETE:
1250 		cnp->cn_flags &= ~DOWHITEOUT; /* cargo culting never fails ? */
1251 		freedir(rnd, cnp);
1252 		break;
1253 	default:
1254 		panic("unknown whiteout op %d", flags);
1255 	}
1256 
1257 	return 0;
1258 }
1259 
1260 static int
rump_vop_open(void * v)1261 rump_vop_open(void *v)
1262 {
1263 	struct vop_open_args /* {
1264 		struct vnode *a_vp;
1265 		int a_mode;
1266 		kauth_cred_t a_cred;
1267 	} */ *ap = v;
1268 	struct vnode *vp = ap->a_vp;
1269 	struct rumpfs_node *rn = vp->v_data;
1270 	int mode = ap->a_mode;
1271 	int error = EINVAL;
1272 
1273 	if (vp->v_type != VREG || (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0)
1274 		return 0;
1275 
1276 	if (mode & FREAD) {
1277 		if (rn->rn_readfd != -1)
1278 			return 0;
1279 		error = rumpuser_open(rn->rn_hostpath,
1280 		    RUMPUSER_OPEN_RDONLY, &rn->rn_readfd);
1281 	}
1282 
1283 	if (mode & FWRITE) {
1284 		if (rn->rn_writefd != -1)
1285 			return 0;
1286 		error = rumpuser_open(rn->rn_hostpath,
1287 		    RUMPUSER_OPEN_WRONLY, &rn->rn_writefd);
1288 	}
1289 
1290 	return error;
1291 }
1292 
1293 /* simple readdir.  even omits dotstuff and periods */
1294 static int
rump_vop_readdir(void * v)1295 rump_vop_readdir(void *v)
1296 {
1297 	struct vop_readdir_args /* {
1298 		struct vnode *a_vp;
1299 		struct uio *a_uio;
1300 		kauth_cred_t a_cred;
1301 		int *a_eofflag;
1302 		off_t **a_cookies;
1303 		int *a_ncookies;
1304 	} */ *ap = v;
1305 	struct vnode *vp = ap->a_vp;
1306 	struct uio *uio = ap->a_uio;
1307 	struct rumpfs_node *rnd = vp->v_data;
1308 	struct rumpfs_dent *rdent;
1309 	struct dirent *dentp = NULL;
1310 	unsigned i;
1311 	int rv = 0;
1312 
1313 	/* seek to current entry */
1314 	for (i = 0, rdent = LIST_FIRST(&rnd->rn_dir);
1315 	    (i < uio->uio_offset) && rdent;
1316 	    i++, rdent = LIST_NEXT(rdent, rd_entries))
1317 		continue;
1318 	if (!rdent)
1319 		goto out;
1320 
1321 	/* copy entries */
1322 	dentp = kmem_alloc(sizeof(*dentp), KM_SLEEP);
1323 	for (; rdent && uio->uio_resid > 0;
1324 	    rdent = LIST_NEXT(rdent, rd_entries), i++) {
1325 		strlcpy(dentp->d_name, rdent->rd_name, sizeof(dentp->d_name));
1326 		dentp->d_namlen = strlen(dentp->d_name);
1327 		dentp->d_reclen = _DIRENT_RECLEN(dentp, dentp->d_namlen);
1328 
1329 		if (__predict_false(RDENT_ISWHITEOUT(rdent))) {
1330 			dentp->d_fileno = INO_WHITEOUT;
1331 			dentp->d_type = DT_WHT;
1332 		} else {
1333 			dentp->d_fileno = rdent->rd_node->rn_va.va_fileid;
1334 			dentp->d_type = vtype2dt(rdent->rd_node->rn_va.va_type);
1335 		}
1336 
1337 		if (uio->uio_resid < dentp->d_reclen) {
1338 			i--;
1339 			break;
1340 		}
1341 
1342 		rv = uiomove(dentp, dentp->d_reclen, uio);
1343 		if (rv) {
1344 			i--;
1345 			break;
1346 		}
1347 	}
1348 	kmem_free(dentp, sizeof(*dentp));
1349 	dentp = NULL;
1350 
1351  out:
1352 	KASSERT(dentp == NULL);
1353 	if (ap->a_cookies) {
1354 		*ap->a_ncookies = 0;
1355 		*ap->a_cookies = NULL;
1356 	}
1357 	if (rdent)
1358 		*ap->a_eofflag = 0;
1359 	else
1360 		*ap->a_eofflag = 1;
1361 	uio->uio_offset = i;
1362 
1363 	return rv;
1364 }
1365 
1366 static int
etread(struct rumpfs_node * rn,struct uio * uio)1367 etread(struct rumpfs_node *rn, struct uio *uio)
1368 {
1369 	struct rumpuser_iovec iov;
1370 	uint8_t *buf;
1371 	size_t bufsize, n;
1372 	int error = 0;
1373 
1374 	bufsize = uio->uio_resid;
1375 	if (bufsize == 0)
1376 		return 0;
1377 	buf = kmem_alloc(bufsize, KM_SLEEP);
1378 
1379 	iov.iov_base = buf;
1380 	iov.iov_len = bufsize;
1381 	if ((error = rumpuser_iovread(rn->rn_readfd, &iov, 1,
1382 	    uio->uio_offset + rn->rn_offset, &n)) == 0) {
1383 		KASSERT(n <= bufsize);
1384 		error = uiomove(buf, n, uio);
1385 	}
1386 
1387 	kmem_free(buf, bufsize);
1388 	return error;
1389 }
1390 
1391 static int
rump_vop_read(void * v)1392 rump_vop_read(void *v)
1393 {
1394 	struct vop_read_args /* {
1395 		struct vnode *a_vp;
1396 		struct uio *a_uio;
1397 		int ioflags a_ioflag;
1398 		kauth_cred_t a_cred;
1399 	}; */ *ap = v;
1400 	struct vnode *vp = ap->a_vp;
1401 	struct rumpfs_node *rn = vp->v_data;
1402 	struct uio *uio = ap->a_uio;
1403 	const int advice = IO_ADV_DECODE(ap->a_ioflag);
1404 	off_t chunk;
1405 	int error = 0;
1406 	struct timespec ts;
1407 
1408 	if (vp->v_type == VDIR)
1409 		return EISDIR;
1410 
1411 	/* et op? */
1412 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
1413 		return etread(rn, uio);
1414 
1415 	getnanotime(&ts);
1416 	(void)rumpfs_update(RUMPFS_ACCESS, vp, &ts, &ts, &ts);
1417 
1418 	/* otherwise, it's off to ubc with us */
1419 	while (uio->uio_resid > 0) {
1420 		chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset);
1421 		if (chunk == 0)
1422 			break;
1423 		error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice,
1424 		    UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
1425 		if (error)
1426 			break;
1427 	}
1428 
1429 	return error;
1430 }
1431 
1432 static int
etwrite(struct rumpfs_node * rn,struct uio * uio)1433 etwrite(struct rumpfs_node *rn, struct uio *uio)
1434 {
1435 	struct rumpuser_iovec iov;
1436 	uint8_t *buf;
1437 	size_t bufsize, n;
1438 	int error = 0;
1439 
1440 	bufsize = uio->uio_resid;
1441 	if (bufsize == 0)
1442 		return 0;
1443 	buf = kmem_alloc(bufsize, KM_SLEEP);
1444 	error = uiomove(buf, bufsize, uio);
1445 	if (error)
1446 		goto out;
1447 
1448 	KASSERT(uio->uio_resid == 0);
1449 	iov.iov_base = buf;
1450 	iov.iov_len = bufsize;
1451 	if ((error = rumpuser_iovwrite(rn->rn_writefd, &iov, 1,
1452 	    (uio->uio_offset-bufsize) + rn->rn_offset, &n)) == 0) {
1453 		KASSERT(n <= bufsize);
1454 		uio->uio_resid = bufsize - n;
1455 	}
1456 
1457  out:
1458 	kmem_free(buf, bufsize);
1459 	return error;
1460 }
1461 
1462 static int
rump_vop_write(void * v)1463 rump_vop_write(void *v)
1464 {
1465 	struct vop_write_args /* {
1466 		struct vnode *a_vp;
1467 		struct uio *a_uio;
1468 		int ioflags a_ioflag;
1469 		kauth_cred_t a_cred;
1470 	}; */ *ap = v;
1471 	struct vnode *vp = ap->a_vp;
1472 	struct rumpfs_node *rn = vp->v_data;
1473 	struct uio *uio = ap->a_uio;
1474 	const int advice = IO_ADV_DECODE(ap->a_ioflag);
1475 	void *olddata;
1476 	size_t oldlen, newlen;
1477 	off_t chunk;
1478 	int error = 0;
1479 	bool allocd = false;
1480 	struct timespec ts;
1481 
1482 	getnanotime(&ts);
1483 	(void)rumpfs_update(RUMPFS_MODIFY, vp, &ts, &ts, &ts);
1484 
1485 	if (ap->a_ioflag & IO_APPEND)
1486 		uio->uio_offset = vp->v_size;
1487 
1488 	/* consult et? */
1489 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
1490 		return etwrite(rn, uio);
1491 
1492 	/*
1493 	 * Otherwise, it's a case of ubcmove.
1494 	 */
1495 
1496 	/*
1497 	 * First, make sure we have enough storage.
1498 	 *
1499 	 * No, you don't need to tell me it's not very efficient.
1500 	 * No, it doesn't really support sparse files, just fakes it.
1501 	 */
1502 	newlen = uio->uio_offset + uio->uio_resid;
1503 	oldlen = 0; /* XXXgcc */
1504 	olddata = NULL;
1505 	if (rn->rn_dlen < newlen) {
1506 		oldlen = rn->rn_dlen;
1507 		olddata = rn->rn_data;
1508 
1509 		rn->rn_data = rump_hypermalloc(newlen, 0, false, "rumpfs");
1510 		if (rn->rn_data == NULL)
1511 			return ENOSPC;
1512 		rn->rn_dlen = newlen;
1513 		memset(rn->rn_data, 0, newlen);
1514 		if (oldlen > 0)
1515 			memcpy(rn->rn_data, olddata, oldlen);
1516 		allocd = true;
1517 		uvm_vnp_setsize(vp, newlen);
1518 	}
1519 
1520 	/* ok, we have enough storage.  write */
1521 	while (uio->uio_resid > 0) {
1522 		chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset);
1523 		if (chunk == 0)
1524 			break;
1525 		error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice,
1526 		    UBC_WRITE | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
1527 		if (error)
1528 			break;
1529 	}
1530 
1531 	if (allocd) {
1532 		if (error) {
1533 			rump_hyperfree(rn->rn_data, newlen);
1534 			rn->rn_data = olddata;
1535 			rn->rn_dlen = oldlen;
1536 			uvm_vnp_setsize(vp, oldlen);
1537 		} else {
1538 			if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) {
1539 				rump_hyperfree(olddata, oldlen);
1540 			} else {
1541 				rn->rn_flags &= ~RUMPNODE_EXTSTORAGE;
1542 			}
1543 		}
1544 	}
1545 
1546 	return error;
1547 }
1548 
1549 static int
rump_vop_bmap(void * v)1550 rump_vop_bmap(void *v)
1551 {
1552 	struct vop_bmap_args /* {
1553 		struct vnode *a_vp;
1554 		daddr_t a_bn;
1555 		struct vnode **a_vpp;
1556 		daddr_t *a_bnp;
1557 		int *a_runp;
1558 	} */ *ap = v;
1559 
1560 	/* 1:1 mapping */
1561 	if (ap->a_vpp)
1562 		*ap->a_vpp = ap->a_vp;
1563 	if (ap->a_bnp)
1564 		*ap->a_bnp = ap->a_bn;
1565 	if (ap->a_runp)
1566 		*ap->a_runp = 16;
1567 
1568 	return 0;
1569 }
1570 
1571 static int
rump_vop_strategy(void * v)1572 rump_vop_strategy(void *v)
1573 {
1574 	struct vop_strategy_args /* {
1575 		struct vnode *a_vp;
1576 		struct buf *a_bp;
1577 	} */ *ap = v;
1578 	struct vnode *vp = ap->a_vp;
1579 	struct rumpfs_node *rn = vp->v_data;
1580 	struct buf *bp = ap->a_bp;
1581 	off_t copylen, copyoff;
1582 	int error;
1583 
1584 	if (vp->v_type != VREG || rn->rn_flags & RUMPNODE_ET_PHONE_HOST) {
1585 		error = EINVAL;
1586 		goto out;
1587 	}
1588 
1589 	copyoff = bp->b_blkno << DEV_BSHIFT;
1590 	copylen = MIN(rn->rn_dlen - copyoff, bp->b_bcount);
1591 	if (BUF_ISWRITE(bp)) {
1592 		memcpy((uint8_t *)rn->rn_data + copyoff, bp->b_data, copylen);
1593 	} else {
1594 		memset((uint8_t*)bp->b_data + copylen, 0, bp->b_bcount-copylen);
1595 		memcpy(bp->b_data, (uint8_t *)rn->rn_data + copyoff, copylen);
1596 	}
1597 	bp->b_resid = 0;
1598 	error = 0;
1599 
1600  out:
1601 	bp->b_error = error;
1602 	biodone(bp);
1603 	return 0;
1604 }
1605 
1606 static int
rump_vop_pathconf(void * v)1607 rump_vop_pathconf(void *v)
1608 {
1609 	struct vop_pathconf_args /* {
1610 		struct vnode *a_vp;
1611 		int a_name;
1612 		register_t *a_retval;
1613 	}; */ *ap = v;
1614 	int name = ap->a_name;
1615 	register_t *retval = ap->a_retval;
1616 
1617 	switch (name) {
1618 	case _PC_LINK_MAX:
1619 		*retval = LINK_MAX;
1620 		return 0;
1621 	case _PC_NAME_MAX:
1622 		*retval = RUMPFS_MAXNAMLEN;
1623 		return 0;
1624 	case _PC_PATH_MAX:
1625 		*retval = PATH_MAX;
1626 		return 0;
1627 	case _PC_PIPE_BUF:
1628 		*retval = PIPE_BUF;
1629 		return 0;
1630 	case _PC_CHOWN_RESTRICTED:
1631 		*retval = 1;
1632 		return 0;
1633 	case _PC_NO_TRUNC:
1634 		*retval = 1;
1635 		return 0;
1636 	case _PC_SYNC_IO:
1637 		*retval = 1;
1638 		return 0;
1639 	case _PC_FILESIZEBITS:
1640 		*retval = 43; /* this one goes to 11 */
1641 		return 0;
1642 	case _PC_SYMLINK_MAX:
1643 		*retval = MAXPATHLEN;
1644 		return 0;
1645 	case _PC_2_SYMLINKS:
1646 		*retval = 1;
1647 		return 0;
1648 	default:
1649 		return EINVAL;
1650 	}
1651 }
1652 
1653 static int
rump_vop_success(void * v)1654 rump_vop_success(void *v)
1655 {
1656 
1657 	return 0;
1658 }
1659 
1660 static int
rump_vop_inactive(void * v)1661 rump_vop_inactive(void *v)
1662 {
1663 	struct vop_inactive_v2_args /* {
1664 		struct vnode *a_vp;
1665 		bool *a_recycle;
1666 	} */ *ap = v;
1667 	struct vnode *vp = ap->a_vp;
1668 	struct rumpfs_node *rn = vp->v_data;
1669 
1670 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST && vp->v_type == VREG) {
1671 		if (rn->rn_readfd != -1) {
1672 			rumpuser_close(rn->rn_readfd);
1673 			rn->rn_readfd = -1;
1674 		}
1675 		if (rn->rn_writefd != -1) {
1676 			rumpuser_close(rn->rn_writefd);
1677 			rn->rn_writefd = -1;
1678 		}
1679 	}
1680 	*ap->a_recycle = (rn->rn_flags & RUMPNODE_CANRECLAIM) ? true : false;
1681 
1682 	return 0;
1683 }
1684 
1685 static int
rump_vop_reclaim(void * v)1686 rump_vop_reclaim(void *v)
1687 {
1688 	struct vop_reclaim_v2_args /* {
1689 		struct vnode *a_vp;
1690 	} */ *ap = v;
1691 	struct vnode *vp = ap->a_vp;
1692 	struct rumpfs_node *rn = vp->v_data;
1693 
1694 	VOP_UNLOCK(vp);
1695 
1696 	mutex_enter(&reclock);
1697 	rn->rn_vp = NULL;
1698 	mutex_exit(&reclock);
1699 	genfs_node_destroy(vp);
1700 	vp->v_data = NULL;
1701 
1702 	if (rn->rn_flags & RUMPNODE_CANRECLAIM) {
1703 		if (vp->v_type == VREG
1704 		    && (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0
1705 		    && rn->rn_data) {
1706 			if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) {
1707 				rump_hyperfree(rn->rn_data, rn->rn_dlen);
1708 			} else {
1709 				rn->rn_flags &= ~RUMPNODE_EXTSTORAGE;
1710 			}
1711 			rn->rn_data = NULL;
1712 		}
1713 
1714 		if (vp->v_type == VLNK)
1715 			PNBUF_PUT(rn->rn_linktarg);
1716 		if (rn->rn_hostpath)
1717 			free(rn->rn_hostpath, M_TEMP);
1718 		freeprivate(rn);
1719 	}
1720 
1721 	return 0;
1722 }
1723 
1724 static int
rump_vop_spec(void * v)1725 rump_vop_spec(void *v)
1726 {
1727 	struct vop_generic_args *ap = v;
1728 	int (**opvec)(void *);
1729 
1730 	switch (ap->a_desc->vdesc_offset) {
1731 	case VOP_ACCESS_DESCOFFSET:
1732 	case VOP_ACCESSX_DESCOFFSET:
1733 	case VOP_GETATTR_DESCOFFSET:
1734 	case VOP_SETATTR_DESCOFFSET:
1735 	case VOP_LOCK_DESCOFFSET:
1736 	case VOP_UNLOCK_DESCOFFSET:
1737 	case VOP_ISLOCKED_DESCOFFSET:
1738 	case VOP_INACTIVE_DESCOFFSET:
1739 	case VOP_RECLAIM_DESCOFFSET:
1740 		opvec = rump_vnodeop_p;
1741 		break;
1742 	default:
1743 		opvec = spec_vnodeop_p;
1744 		break;
1745 	}
1746 
1747 	return VOCALL(opvec, ap->a_desc->vdesc_offset, v);
1748 }
1749 
1750 static int
rump_vop_advlock(void * v)1751 rump_vop_advlock(void *v)
1752 {
1753 	struct vop_advlock_args /* {
1754 		const struct vnodeop_desc *a_desc;
1755 		struct vnode *a_vp;
1756 		void *a_id;
1757 		int a_op;
1758 		struct flock *a_fl;
1759 		int a_flags;
1760 	} */ *ap = v;
1761 	struct vnode *vp = ap->a_vp;
1762 	struct rumpfs_node *rn = vp->v_data;
1763 
1764 	return lf_advlock(ap, &rn->rn_lockf, vp->v_size);
1765 }
1766 
1767 static int
rump_vop_fcntl(void * v)1768 rump_vop_fcntl(void *v)
1769 {
1770 	struct vop_fcntl_args /* {
1771 		struct vnode *a_vp;
1772 		u_int a_command;
1773 		void *a_data;
1774 		int a_fflag;
1775 		kauth_cred_t a_cred;
1776 	} */ *ap = v;
1777 	struct proc *p = curproc;
1778 	struct vnode *vp = ap->a_vp;
1779 	struct rumpfs_node *rn = vp->v_data;
1780 	u_int cmd = ap->a_command;
1781 	int fflag = ap->a_fflag;
1782 	struct rumpfs_extstorage *rfse = ap->a_data;
1783 	int error = 0;
1784 
1785 	/* none of the current rumpfs fcntlops are defined for remotes */
1786 	if (!RUMP_LOCALPROC_P(p))
1787 		return EINVAL;
1788 
1789 	switch (cmd) {
1790 	case RUMPFS_FCNTL_EXTSTORAGE_ADD:
1791 		break;
1792 	default:
1793 		return EINVAL;
1794 	}
1795 
1796 	if ((fflag & FWRITE) == 0)
1797 		return EBADF;
1798 
1799 	if (vp->v_type != VREG || (rn->rn_flags & RUMPNODE_ET_PHONE_HOST))
1800 		return EINVAL;
1801 
1802 	if (rfse->rfse_flags != 0)
1803 		return EINVAL;
1804 
1805 	/*
1806 	 * Ok, we are good to go.  Process.
1807 	 */
1808 
1809 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1810 
1811 	KASSERT(cmd == RUMPFS_FCNTL_EXTSTORAGE_ADD);
1812 	if (rn->rn_data && (rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) {
1813 		rump_hyperfree(rn->rn_data, rn->rn_dlen);
1814 	}
1815 
1816 	rn->rn_data = rfse->rfse_data;
1817 	rn->rn_dlen = rfse->rfse_dlen;
1818 	uvm_vnp_setsize(vp, rn->rn_dlen);
1819 	rn->rn_flags |= RUMPNODE_EXTSTORAGE;
1820 
1821 	VOP_UNLOCK(vp);
1822 
1823 	return error;
1824 }
1825 
1826 /*
1827  * Begin vfs-level stuff
1828  */
1829 
1830 VFS_PROTOS(rumpfs);
1831 struct vfsops rumpfs_vfsops = {
1832 	.vfs_name =		MOUNT_RUMPFS,
1833 	.vfs_min_mount_data = 	0,
1834 	.vfs_mount =		rumpfs_mount,
1835 	.vfs_start =		(void *)nullop,
1836 	.vfs_unmount = 		rumpfs_unmount,
1837 	.vfs_root =		rumpfs_root,
1838 	.vfs_quotactl =		(void *)eopnotsupp,
1839 	.vfs_statvfs =		genfs_statvfs,
1840 	.vfs_sync =		(void *)nullop,
1841 	.vfs_vget =		rumpfs_vget,
1842 	.vfs_loadvnode =	rumpfs_loadvnode,
1843 	.vfs_fhtovp =		(void *)eopnotsupp,
1844 	.vfs_vptofh =		(void *)eopnotsupp,
1845 	.vfs_init =		rumpfs_init,
1846 	.vfs_reinit =		NULL,
1847 	.vfs_done =		rumpfs_done,
1848 	.vfs_mountroot =	rumpfs_mountroot,
1849 	.vfs_snapshot =		(void *)eopnotsupp,
1850 	.vfs_extattrctl =	(void *)eopnotsupp,
1851 	.vfs_suspendctl =	genfs_suspendctl,
1852 	.vfs_renamelock_enter =	genfs_renamelock_enter,
1853 	.vfs_renamelock_exit =	genfs_renamelock_exit,
1854 	.vfs_opv_descs =	rump_opv_descs,
1855 	/* vfs_refcount */
1856 	/* vfs_list */
1857 };
1858 
1859 static int
rumpfs_mountfs(struct mount * mp)1860 rumpfs_mountfs(struct mount *mp)
1861 {
1862 	struct rumpfs_mount *rfsmp;
1863 	struct rumpfs_node *rn;
1864 	int error;
1865 
1866 	rfsmp = kmem_alloc(sizeof(*rfsmp), KM_SLEEP);
1867 
1868 	rn = makeprivate(VDIR, RUMPFS_DEFAULTMODE, NODEV, DEV_BSIZE, false);
1869 	rn->rn_parent = rn;
1870 	if ((error = vcache_get(mp, &rn, sizeof(rn), &rfsmp->rfsmp_rvp))
1871 	    != 0) {
1872 		freeprivate(rn);
1873 		kmem_free(rfsmp, sizeof(*rfsmp));
1874 		return error;
1875 	}
1876 
1877 	rfsmp->rfsmp_rvp->v_vflag |= VV_ROOT;
1878 
1879 	mp->mnt_data = rfsmp;
1880 	mp->mnt_stat.f_namemax = RUMPFS_MAXNAMLEN;
1881 	mp->mnt_stat.f_iosize = 512;
1882 	mp->mnt_flag |= MNT_LOCAL;
1883 	mp->mnt_iflag |= IMNT_MPSAFE | IMNT_CAN_RWTORO;
1884 	mp->mnt_fs_bshift = DEV_BSHIFT;
1885 	vfs_getnewfsid(mp);
1886 
1887 	return 0;
1888 }
1889 
1890 int
rumpfs_mount(struct mount * mp,const char * mntpath,void * arg,size_t * alen)1891 rumpfs_mount(struct mount *mp, const char *mntpath, void *arg, size_t *alen)
1892 {
1893 	int error, flags;
1894 
1895 	if (mp->mnt_flag & MNT_GETARGS) {
1896 		return 0;
1897 	}
1898 	if (mp->mnt_flag & MNT_UPDATE) {
1899 		if ((mp->mnt_iflag & IMNT_WANTRDONLY)) {
1900 			/* Changing from read/write to read-only. */
1901 			flags = WRITECLOSE;
1902 			if ((mp->mnt_flag & MNT_FORCE))
1903 				flags |= FORCECLOSE;
1904 			error = vflush(mp, NULL, flags);
1905 			if (error)
1906 				return error;
1907 		}
1908 		return 0;
1909 	}
1910 
1911 	error = set_statvfs_info(mntpath, UIO_USERSPACE, "rumpfs", UIO_SYSSPACE,
1912 	    mp->mnt_op->vfs_name, mp, curlwp);
1913 	if (error)
1914 		return error;
1915 
1916 	return rumpfs_mountfs(mp);
1917 }
1918 
1919 int
rumpfs_unmount(struct mount * mp,int mntflags)1920 rumpfs_unmount(struct mount *mp, int mntflags)
1921 {
1922 	struct rumpfs_mount *rfsmp = mp->mnt_data;
1923 	int flags = 0, error;
1924 
1925 	if (panicstr || mntflags & MNT_FORCE)
1926 		flags |= FORCECLOSE;
1927 
1928 	if (vrefcnt(rfsmp->rfsmp_rvp) > 1 && (flags & FORCECLOSE) == 0)
1929 		return EBUSY;
1930 
1931 	if ((error = vflush(mp, rfsmp->rfsmp_rvp, flags)) != 0)
1932 		return error;
1933 	vgone(rfsmp->rfsmp_rvp);
1934 
1935 	kmem_free(rfsmp, sizeof(*rfsmp));
1936 
1937 	return 0;
1938 }
1939 
1940 int
rumpfs_root(struct mount * mp,int lktype,struct vnode ** vpp)1941 rumpfs_root(struct mount *mp, int lktype, struct vnode **vpp)
1942 {
1943 	struct rumpfs_mount *rfsmp = mp->mnt_data;
1944 
1945 	vref(rfsmp->rfsmp_rvp);
1946 	vn_lock(rfsmp->rfsmp_rvp, lktype | LK_RETRY);
1947 	*vpp = rfsmp->rfsmp_rvp;
1948 	return 0;
1949 }
1950 
1951 int
rumpfs_vget(struct mount * mp,ino_t ino,int lktype,struct vnode ** vpp)1952 rumpfs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp)
1953 {
1954 
1955 	return EOPNOTSUPP;
1956 }
1957 
1958 int
rumpfs_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)1959 rumpfs_loadvnode(struct mount *mp, struct vnode *vp,
1960     const void *key, size_t key_len, const void **new_key)
1961 {
1962 	struct rumpfs_node *rn;
1963 	struct vattr *va;
1964 
1965 	KASSERT(!mutex_owned(&reclock));
1966 
1967 	KASSERT(key_len == sizeof(rn));
1968 	memcpy(&rn, key, key_len);
1969 
1970 	va = &rn->rn_va;
1971 
1972 	vp->v_tag = VT_RUMP;
1973 	vp->v_type = va->va_type;
1974 	switch (vp->v_type) {
1975 	case VCHR:
1976 	case VBLK:
1977 		vp->v_op = rump_specop_p;
1978 		spec_node_init(vp, va->va_rdev);
1979 		break;
1980 	default:
1981 		vp->v_op = rump_vnodeop_p;
1982 		break;
1983 	}
1984 	vp->v_size = vp->v_writesize = va->va_size;
1985 	vp->v_data = rn;
1986 
1987 	genfs_node_init(vp, &rumpfs_genfsops);
1988 	mutex_enter(&reclock);
1989 	rn->rn_vp = vp;
1990 	mutex_exit(&reclock);
1991 
1992 	*new_key = &vp->v_data;
1993 
1994 	return 0;
1995 }
1996 
1997 void
rumpfs_init()1998 rumpfs_init()
1999 {
2000 	extern rump_etfs_register_withsize_fn rump__etfs_register;
2001 	extern rump_etfs_remove_fn rump__etfs_remove;
2002 	extern struct rump_boot_etfs *ebstart;
2003 	struct rump_boot_etfs *eb;
2004 
2005 	CTASSERT(RUMP_ETFS_SIZE_ENDOFF == RUMPBLK_SIZENOTSET);
2006 
2007 	mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE);
2008 	mutex_init(&etfs_lock, MUTEX_DEFAULT, IPL_NONE);
2009 
2010 	rump__etfs_register = etfsregister;
2011 	rump__etfs_remove = etfsremove;
2012 
2013 	for (eb = ebstart; eb; eb = eb->_eb_next) {
2014 		eb->eb_status = etfsregister(eb->eb_key, eb->eb_hostpath,
2015 		    eb->eb_type, eb->eb_begin, eb->eb_size);
2016 	}
2017 }
2018 
2019 void
rumpfs_done()2020 rumpfs_done()
2021 {
2022 
2023 	mutex_destroy(&reclock);
2024 	mutex_destroy(&etfs_lock);
2025 }
2026 
2027 int
rumpfs_mountroot()2028 rumpfs_mountroot()
2029 {
2030 	struct mount *mp;
2031 	int error;
2032 
2033 	if ((error = vfs_rootmountalloc(MOUNT_RUMPFS, "rootdev", &mp)) != 0) {
2034 		vrele(rootvp);
2035 		return error;
2036 	}
2037 
2038 	if ((error = rumpfs_mountfs(mp)) != 0)
2039 		panic("mounting rootfs failed: %d", error);
2040 
2041 	mountlist_append(mp);
2042 
2043 	error = set_statvfs_info("/", UIO_SYSSPACE, "rumpfs", UIO_SYSSPACE,
2044 	    mp->mnt_op->vfs_name, mp, curlwp);
2045 	if (error)
2046 		panic("set_statvfs_info failed for rootfs: %d", error);
2047 
2048 	mp->mnt_flag &= ~MNT_RDONLY;
2049 	vfs_unbusy(mp);
2050 
2051 	return 0;
2052 }
2053