Fri Jun 14 05:54:04 2013 UTC ()
Allocate large struct from heap instead of stack for the benefit of
low-stack environments in which this code can run.


(pooka)
diff -r1.116 -r1.117 src/sys/rump/librump/rumpvfs/rumpfs.c

cvs diff -r1.116 -r1.117 src/sys/rump/librump/rumpvfs/rumpfs.c (switch to unified diff)

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