| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: rumpfs.c,v 1.52 2010/06/15 17:23:31 njoly Exp $ */ | | 1 | /* $NetBSD: rumpfs.c,v 1.53 2010/06/15 18:53:48 pooka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009 Antti Kantee. All Rights Reserved. | | 4 | * Copyright (c) 2009 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 | * |
| @@ -16,27 +16,27 @@ | | | @@ -16,27 +16,27 @@ |
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.52 2010/06/15 17:23:31 njoly Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.53 2010/06/15 18:53:48 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/dirent.h> | | 33 | #include <sys/dirent.h> |
34 | #include <sys/errno.h> | | 34 | #include <sys/errno.h> |
35 | #include <sys/filedesc.h> | | 35 | #include <sys/filedesc.h> |
36 | #include <sys/fcntl.h> | | 36 | #include <sys/fcntl.h> |
37 | #include <sys/kauth.h> | | 37 | #include <sys/kauth.h> |
38 | #include <sys/malloc.h> | | 38 | #include <sys/malloc.h> |
39 | #include <sys/module.h> | | 39 | #include <sys/module.h> |
40 | #include <sys/mount.h> | | 40 | #include <sys/mount.h> |
41 | #include <sys/namei.h> | | 41 | #include <sys/namei.h> |
42 | #include <sys/lock.h> | | 42 | #include <sys/lock.h> |
| @@ -162,26 +162,28 @@ static struct rumpfs_node *makeprivate(e | | | @@ -162,26 +162,28 @@ static struct rumpfs_node *makeprivate(e |
162 | | | 162 | |
163 | /* | | 163 | /* |
164 | * Extra Terrestrial stuff. We map a given key (pathname) to a file on | | 164 | * Extra Terrestrial stuff. We map a given key (pathname) to a file on |
165 | * the host FS. ET phones home only from the root node of rumpfs. | | 165 | * the host FS. ET phones home only from the root node of rumpfs. |
166 | * | | 166 | * |
167 | * When an etfs node is removed, a vnode potentially behind it is not | | 167 | * When an etfs node is removed, a vnode potentially behind it is not |
168 | * immediately recycled. | | 168 | * immediately recycled. |
169 | */ | | 169 | */ |
170 | | | 170 | |
171 | struct etfs { | | 171 | struct etfs { |
172 | char et_key[MAXPATHLEN]; | | 172 | char et_key[MAXPATHLEN]; |
173 | size_t et_keylen; | | 173 | size_t et_keylen; |
174 | bool et_prefixkey; | | 174 | bool et_prefixkey; |
| | | 175 | bool et_removing; |
| | | 176 | devminor_t et_blkmin; |
175 | | | 177 | |
176 | LIST_ENTRY(etfs) et_entries; | | 178 | LIST_ENTRY(etfs) et_entries; |
177 | | | 179 | |
178 | struct rumpfs_node *et_rn; | | 180 | struct rumpfs_node *et_rn; |
179 | }; | | 181 | }; |
180 | static kmutex_t etfs_lock; | | 182 | static kmutex_t etfs_lock; |
181 | static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list); | | 183 | static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list); |
182 | | | 184 | |
183 | static enum vtype | | 185 | static enum vtype |
184 | ettype_to_vtype(enum rump_etfs_type et) | | 186 | ettype_to_vtype(enum rump_etfs_type et) |
185 | { | | 187 | { |
186 | enum vtype vt; | | 188 | enum vtype vt; |
187 | | | 189 | |
| @@ -257,27 +259,27 @@ etfs_find(const char *key, struct etfs * | | | @@ -257,27 +259,27 @@ etfs_find(const char *key, struct etfs * |
257 | return false; | | 259 | return false; |
258 | } | | 260 | } |
259 | | | 261 | |
260 | #define REGDIR(ftype) \ | | 262 | #define REGDIR(ftype) \ |
261 | ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS) | | 263 | ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS) |
262 | static int | | 264 | static int |
263 | doregister(const char *key, const char *hostpath, | | 265 | doregister(const char *key, const char *hostpath, |
264 | enum rump_etfs_type ftype, uint64_t begin, uint64_t size) | | 266 | enum rump_etfs_type ftype, uint64_t begin, uint64_t size) |
265 | { | | 267 | { |
266 | struct etfs *et; | | 268 | struct etfs *et; |
267 | struct rumpfs_node *rn; | | 269 | struct rumpfs_node *rn; |
268 | uint64_t fsize; | | 270 | uint64_t fsize; |
269 | dev_t rdev = NODEV; | | 271 | dev_t rdev = NODEV; |
270 | devminor_t dmin; | | 272 | devminor_t dmin = -1; |
271 | int hft, error; | | 273 | int hft, error; |
272 | | | 274 | |
273 | if (rumpuser_getfileinfo(hostpath, &fsize, &hft, &error)) | | 275 | if (rumpuser_getfileinfo(hostpath, &fsize, &hft, &error)) |
274 | return error; | | 276 | return error; |
275 | | | 277 | |
276 | /* etfs directory requires a directory on the host */ | | 278 | /* etfs directory requires a directory on the host */ |
277 | if (REGDIR(ftype)) { | | 279 | if (REGDIR(ftype)) { |
278 | if (hft != RUMPUSER_FT_DIR) | | 280 | if (hft != RUMPUSER_FT_DIR) |
279 | return ENOTDIR; | | 281 | return ENOTDIR; |
280 | if (begin != 0) | | 282 | if (begin != 0) |
281 | return EISDIR; | | 283 | return EISDIR; |
282 | if (size != RUMP_ETFS_SIZE_ENDOFF) | | 284 | if (size != RUMP_ETFS_SIZE_ENDOFF) |
283 | return EISDIR; | | 285 | return EISDIR; |
| @@ -293,53 +295,56 @@ doregister(const char *key, const char * | | | @@ -293,53 +295,56 @@ doregister(const char *key, const char * |
293 | | | 295 | |
294 | if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) { | | 296 | if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) { |
295 | error = rumpblk_register(hostpath, &dmin, begin, size); | | 297 | error = rumpblk_register(hostpath, &dmin, begin, size); |
296 | if (error != 0) { | | 298 | if (error != 0) { |
297 | return error; | | 299 | return error; |
298 | } | | 300 | } |
299 | rdev = makedev(RUMPBLK_DEVMAJOR, dmin); | | 301 | rdev = makedev(RUMPBLK_DEVMAJOR, dmin); |
300 | } | | 302 | } |
301 | | | 303 | |
302 | et = kmem_alloc(sizeof(*et), KM_SLEEP); | | 304 | et = kmem_alloc(sizeof(*et), KM_SLEEP); |
303 | strcpy(et->et_key, key); | | 305 | strcpy(et->et_key, key); |
304 | et->et_keylen = strlen(et->et_key); | | 306 | et->et_keylen = strlen(et->et_key); |
305 | et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size); | | 307 | et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size); |
| | | 308 | et->et_removing = false; |
| | | 309 | et->et_blkmin = dmin; |
306 | | | 310 | |
307 | if (ftype == RUMP_ETFS_REG || REGDIR(ftype)) { | | 311 | if (ftype == RUMP_ETFS_REG || REGDIR(ftype) || et->et_blkmin != -1) { |
308 | size_t len = strlen(hostpath)+1; | | 312 | size_t len = strlen(hostpath)+1; |
309 | | | 313 | |
310 | rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO); | | 314 | rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO); |
311 | memcpy(rn->rn_hostpath, hostpath, len); | | 315 | memcpy(rn->rn_hostpath, hostpath, len); |
312 | rn->rn_offset = begin; | | 316 | rn->rn_offset = begin; |
313 | } | | 317 | } |
314 | | | 318 | |
315 | if (REGDIR(ftype)) { | | 319 | if (REGDIR(ftype)) { |
316 | rn->rn_flags |= RUMPNODE_DIR_ET; | | 320 | rn->rn_flags |= RUMPNODE_DIR_ET; |
317 | et->et_prefixkey = true; | | 321 | et->et_prefixkey = true; |
318 | } else { | | 322 | } else { |
319 | et->et_prefixkey = false; | | 323 | et->et_prefixkey = false; |
320 | } | | 324 | } |
321 | | | 325 | |
322 | if (ftype == RUMP_ETFS_DIR_SUBDIRS) | | 326 | if (ftype == RUMP_ETFS_DIR_SUBDIRS) |
323 | rn->rn_flags |= RUMPNODE_DIR_ETSUBS; | | 327 | rn->rn_flags |= RUMPNODE_DIR_ETSUBS; |
324 | | | 328 | |
325 | mutex_enter(&etfs_lock); | | 329 | mutex_enter(&etfs_lock); |
326 | if (etfs_find(key, NULL, REGDIR(ftype))) { | | 330 | if (etfs_find(key, NULL, REGDIR(ftype))) { |
327 | mutex_exit(&etfs_lock); | | 331 | mutex_exit(&etfs_lock); |
| | | 332 | if (et->et_blkmin != -1) |
| | | 333 | rumpblk_deregister(hostpath); |
328 | if (et->et_rn->rn_hostpath != NULL) | | 334 | if (et->et_rn->rn_hostpath != NULL) |
329 | free(et->et_rn->rn_hostpath, M_TEMP); | | 335 | free(et->et_rn->rn_hostpath, M_TEMP); |
330 | kmem_free(et->et_rn, sizeof(*et->et_rn)); | | 336 | kmem_free(et->et_rn, sizeof(*et->et_rn)); |
331 | kmem_free(et, sizeof(*et)); | | 337 | kmem_free(et, sizeof(*et)); |
332 | /* XXX: rumpblk_deregister(hostpath); */ | | | |
333 | return EEXIST; | | 338 | return EEXIST; |
334 | } | | 339 | } |
335 | LIST_INSERT_HEAD(&etfs_list, et, et_entries); | | 340 | LIST_INSERT_HEAD(&etfs_list, et, et_entries); |
336 | mutex_exit(&etfs_lock); | | 341 | mutex_exit(&etfs_lock); |
337 | | | 342 | |
338 | return 0; | | 343 | return 0; |
339 | } | | 344 | } |
340 | #undef REGDIR | | 345 | #undef REGDIR |
341 | | | 346 | |
342 | int | | 347 | int |
343 | rump_etfs_register(const char *key, const char *hostpath, | | 348 | rump_etfs_register(const char *key, const char *hostpath, |
344 | enum rump_etfs_type ftype) | | 349 | enum rump_etfs_type ftype) |
345 | { | | 350 | { |
| @@ -356,47 +361,73 @@ rump_etfs_register_withsize(const char * | | | @@ -356,47 +361,73 @@ rump_etfs_register_withsize(const char * |
356 | * Check that we're mapping at block offsets. I guess this | | 361 | * Check that we're mapping at block offsets. I guess this |
357 | * is not technically necessary except for BLK/CHR backends | | 362 | * is not technically necessary except for BLK/CHR backends |
358 | * (i.e. what getfileinfo() returns, not ftype) and can be | | 363 | * (i.e. what getfileinfo() returns, not ftype) and can be |
359 | * removed later if there are problems. | | 364 | * removed later if there are problems. |
360 | */ | | 365 | */ |
361 | if ((begin & (DEV_BSIZE-1)) != 0) | | 366 | if ((begin & (DEV_BSIZE-1)) != 0) |
362 | return EINVAL; | | 367 | return EINVAL; |
363 | if (size != RUMP_ETFS_SIZE_ENDOFF && (size & (DEV_BSIZE-1)) != 0) | | 368 | if (size != RUMP_ETFS_SIZE_ENDOFF && (size & (DEV_BSIZE-1)) != 0) |
364 | return EINVAL; | | 369 | return EINVAL; |
365 | | | 370 | |
366 | return doregister(key, hostpath, ftype, begin, size); | | 371 | return doregister(key, hostpath, ftype, begin, size); |
367 | } | | 372 | } |
368 | | | 373 | |
| | | 374 | /* remove etfs mapping. caller's responsibility to make sure it's not in use */ |
369 | int | | 375 | int |
370 | rump_etfs_remove(const char *key) | | 376 | rump_etfs_remove(const char *key) |
371 | { | | 377 | { |
372 | struct etfs *et; | | 378 | struct etfs *et; |
373 | size_t keylen = strlen(key); | | 379 | size_t keylen = strlen(key); |
| | | 380 | int rv; |
374 | | | 381 | |
375 | mutex_enter(&etfs_lock); | | 382 | mutex_enter(&etfs_lock); |
376 | LIST_FOREACH(et, &etfs_list, et_entries) { | | 383 | LIST_FOREACH(et, &etfs_list, et_entries) { |
377 | if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) { | | 384 | if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) { |
378 | LIST_REMOVE(et, et_entries); | | 385 | if (et->et_removing) |
379 | if (et->et_rn->rn_hostpath != NULL) | | 386 | et = NULL; |
380 | free(et->et_rn->rn_hostpath, M_TEMP); | | 387 | else |
381 | kmem_free(et->et_rn, sizeof(*et->et_rn)); | | 388 | et->et_removing = true; |
382 | kmem_free(et, sizeof(*et)); | | | |
383 | break; | | 389 | break; |
384 | } | | 390 | } |
385 | } | | 391 | } |
386 | mutex_exit(&etfs_lock); | | 392 | mutex_exit(&etfs_lock); |
387 | | | | |
388 | if (!et) | | 393 | if (!et) |
389 | return ENOENT; | | 394 | return ENOENT; |
| | | 395 | |
| | | 396 | /* |
| | | 397 | * ok, we know what we want to remove and have signalled there |
| | | 398 | * actually are men at work. first, unregister from rumpblk |
| | | 399 | */ |
| | | 400 | if (et->et_blkmin != -1) { |
| | | 401 | rv = rumpblk_deregister(et->et_rn->rn_hostpath); |
| | | 402 | } else { |
| | | 403 | rv = 0; |
| | | 404 | } |
| | | 405 | KASSERT(rv == 0); |
| | | 406 | |
| | | 407 | /* then do the actual removal */ |
| | | 408 | mutex_enter(&etfs_lock); |
| | | 409 | LIST_REMOVE(et, et_entries); |
| | | 410 | mutex_exit(&etfs_lock); |
| | | 411 | |
| | | 412 | /* node is unreachable, safe to nuke all device copies */ |
| | | 413 | if (et->et_blkmin != -1) |
| | | 414 | vdevgone(RUMPBLK_DEVMAJOR, et->et_blkmin, et->et_blkmin, VBLK); |
| | | 415 | |
| | | 416 | if (et->et_rn->rn_hostpath != NULL) |
| | | 417 | free(et->et_rn->rn_hostpath, M_TEMP); |
| | | 418 | kmem_free(et->et_rn, sizeof(*et->et_rn)); |
| | | 419 | kmem_free(et, sizeof(*et)); |
| | | 420 | |
390 | return 0; | | 421 | return 0; |
391 | } | | 422 | } |
392 | | | 423 | |
393 | /* | | 424 | /* |
394 | * rumpfs | | 425 | * rumpfs |
395 | */ | | 426 | */ |
396 | | | 427 | |
397 | static int lastino = 1; | | 428 | static int lastino = 1; |
398 | static kmutex_t reclock; | | 429 | static kmutex_t reclock; |
399 | | | 430 | |
400 | static struct rumpfs_node * | | 431 | static struct rumpfs_node * |
401 | makeprivate(enum vtype vt, dev_t rdev, off_t size) | | 432 | makeprivate(enum vtype vt, dev_t rdev, off_t size) |
402 | { | | 433 | { |