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