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