diff options
Diffstat (limited to 'fs/cachefiles')
| -rw-r--r-- | fs/cachefiles/internal.h | 1 | ||||
| -rw-r--r-- | fs/cachefiles/namei.c | 98 |
2 files changed, 87 insertions, 12 deletions
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index f7c255f9c624..a8cd821226da 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h | |||
| @@ -34,6 +34,7 @@ struct cachefiles_object { | |||
| 34 | loff_t i_size; /* object size */ | 34 | loff_t i_size; /* object size */ |
| 35 | unsigned long flags; | 35 | unsigned long flags; |
| 36 | #define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */ | 36 | #define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */ |
| 37 | #define CACHEFILES_OBJECT_BURIED 1 /* T if preemptively buried */ | ||
| 37 | atomic_t usage; /* object usage count */ | 38 | atomic_t usage; /* object usage count */ |
| 38 | uint8_t type; /* object type */ | 39 | uint8_t type; /* object type */ |
| 39 | uint8_t new; /* T if object new */ | 40 | uint8_t new; /* T if object new */ |
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index d5db84a1ee0d..f4a7840bf42c 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
| @@ -93,6 +93,59 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object, | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /* | 95 | /* |
| 96 | * mark the owner of a dentry, if there is one, to indicate that that dentry | ||
| 97 | * has been preemptively deleted | ||
| 98 | * - the caller must hold the i_mutex on the dentry's parent as required to | ||
| 99 | * call vfs_unlink(), vfs_rmdir() or vfs_rename() | ||
| 100 | */ | ||
| 101 | static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, | ||
| 102 | struct dentry *dentry) | ||
| 103 | { | ||
| 104 | struct cachefiles_object *object; | ||
| 105 | struct rb_node *p; | ||
| 106 | |||
| 107 | _enter(",'%*.*s'", | ||
| 108 | dentry->d_name.len, dentry->d_name.len, dentry->d_name.name); | ||
| 109 | |||
| 110 | write_lock(&cache->active_lock); | ||
| 111 | |||
| 112 | p = cache->active_nodes.rb_node; | ||
| 113 | while (p) { | ||
| 114 | object = rb_entry(p, struct cachefiles_object, active_node); | ||
| 115 | if (object->dentry > dentry) | ||
| 116 | p = p->rb_left; | ||
| 117 | else if (object->dentry < dentry) | ||
| 118 | p = p->rb_right; | ||
| 119 | else | ||
| 120 | goto found_dentry; | ||
| 121 | } | ||
| 122 | |||
| 123 | write_unlock(&cache->active_lock); | ||
| 124 | _leave(" [no owner]"); | ||
| 125 | return; | ||
| 126 | |||
| 127 | /* found the dentry for */ | ||
| 128 | found_dentry: | ||
| 129 | kdebug("preemptive burial: OBJ%x [%s] %p", | ||
| 130 | object->fscache.debug_id, | ||
| 131 | fscache_object_states[object->fscache.state], | ||
| 132 | dentry); | ||
| 133 | |||
| 134 | if (object->fscache.state < FSCACHE_OBJECT_DYING) { | ||
| 135 | printk(KERN_ERR "\n"); | ||
| 136 | printk(KERN_ERR "CacheFiles: Error:" | ||
| 137 | " Can't preemptively bury live object\n"); | ||
| 138 | cachefiles_printk_object(object, NULL); | ||
| 139 | } else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { | ||
| 140 | printk(KERN_ERR "CacheFiles: Error:" | ||
| 141 | " Object already preemptively buried\n"); | ||
| 142 | } | ||
| 143 | |||
| 144 | write_unlock(&cache->active_lock); | ||
| 145 | _leave(" [owner marked]"); | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 96 | * record the fact that an object is now active | 149 | * record the fact that an object is now active |
| 97 | */ | 150 | */ |
| 98 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, | 151 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
| @@ -219,7 +272,8 @@ requeue: | |||
| 219 | */ | 272 | */ |
| 220 | static int cachefiles_bury_object(struct cachefiles_cache *cache, | 273 | static int cachefiles_bury_object(struct cachefiles_cache *cache, |
| 221 | struct dentry *dir, | 274 | struct dentry *dir, |
| 222 | struct dentry *rep) | 275 | struct dentry *rep, |
| 276 | bool preemptive) | ||
| 223 | { | 277 | { |
| 224 | struct dentry *grave, *trap; | 278 | struct dentry *grave, *trap; |
| 225 | char nbuffer[8 + 8 + 1]; | 279 | char nbuffer[8 + 8 + 1]; |
| @@ -229,11 +283,16 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache, | |||
| 229 | dir->d_name.len, dir->d_name.len, dir->d_name.name, | 283 | dir->d_name.len, dir->d_name.len, dir->d_name.name, |
| 230 | rep->d_name.len, rep->d_name.len, rep->d_name.name); | 284 | rep->d_name.len, rep->d_name.len, rep->d_name.name); |
| 231 | 285 | ||
| 286 | _debug("remove %p from %p", rep, dir); | ||
| 287 | |||
| 232 | /* non-directories can just be unlinked */ | 288 | /* non-directories can just be unlinked */ |
| 233 | if (!S_ISDIR(rep->d_inode->i_mode)) { | 289 | if (!S_ISDIR(rep->d_inode->i_mode)) { |
| 234 | _debug("unlink stale object"); | 290 | _debug("unlink stale object"); |
| 235 | ret = vfs_unlink(dir->d_inode, rep); | 291 | ret = vfs_unlink(dir->d_inode, rep); |
| 236 | 292 | ||
| 293 | if (preemptive) | ||
| 294 | cachefiles_mark_object_buried(cache, rep); | ||
| 295 | |||
| 237 | mutex_unlock(&dir->d_inode->i_mutex); | 296 | mutex_unlock(&dir->d_inode->i_mutex); |
| 238 | 297 | ||
| 239 | if (ret == -EIO) | 298 | if (ret == -EIO) |
| @@ -325,6 +384,9 @@ try_again: | |||
| 325 | if (ret != 0 && ret != -ENOMEM) | 384 | if (ret != 0 && ret != -ENOMEM) |
| 326 | cachefiles_io_error(cache, "Rename failed with error %d", ret); | 385 | cachefiles_io_error(cache, "Rename failed with error %d", ret); |
| 327 | 386 | ||
| 387 | if (preemptive) | ||
| 388 | cachefiles_mark_object_buried(cache, rep); | ||
| 389 | |||
| 328 | unlock_rename(cache->graveyard, dir); | 390 | unlock_rename(cache->graveyard, dir); |
| 329 | dput(grave); | 391 | dput(grave); |
| 330 | _leave(" = 0"); | 392 | _leave(" = 0"); |
| @@ -340,7 +402,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
| 340 | struct dentry *dir; | 402 | struct dentry *dir; |
| 341 | int ret; | 403 | int ret; |
| 342 | 404 | ||
| 343 | _enter(",{%p}", object->dentry); | 405 | _enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry); |
| 344 | 406 | ||
| 345 | ASSERT(object->dentry); | 407 | ASSERT(object->dentry); |
| 346 | ASSERT(object->dentry->d_inode); | 408 | ASSERT(object->dentry->d_inode); |
| @@ -350,15 +412,25 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
| 350 | 412 | ||
| 351 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 413 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
| 352 | 414 | ||
| 353 | /* we need to check that our parent is _still_ our parent - it may have | 415 | if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { |
| 354 | * been renamed */ | 416 | /* object allocation for the same key preemptively deleted this |
| 355 | if (dir == object->dentry->d_parent) { | 417 | * object's file so that it could create its own file */ |
| 356 | ret = cachefiles_bury_object(cache, dir, object->dentry); | 418 | _debug("object preemptively buried"); |
| 357 | } else { | ||
| 358 | /* it got moved, presumably by cachefilesd culling it, so it's | ||
| 359 | * no longer in the key path and we can ignore it */ | ||
| 360 | mutex_unlock(&dir->d_inode->i_mutex); | 419 | mutex_unlock(&dir->d_inode->i_mutex); |
| 361 | ret = 0; | 420 | ret = 0; |
| 421 | } else { | ||
| 422 | /* we need to check that our parent is _still_ our parent - it | ||
| 423 | * may have been renamed */ | ||
| 424 | if (dir == object->dentry->d_parent) { | ||
| 425 | ret = cachefiles_bury_object(cache, dir, | ||
| 426 | object->dentry, false); | ||
| 427 | } else { | ||
| 428 | /* it got moved, presumably by cachefilesd culling it, | ||
| 429 | * so it's no longer in the key path and we can ignore | ||
| 430 | * it */ | ||
| 431 | mutex_unlock(&dir->d_inode->i_mutex); | ||
| 432 | ret = 0; | ||
| 433 | } | ||
| 362 | } | 434 | } |
| 363 | 435 | ||
| 364 | dput(dir); | 436 | dput(dir); |
| @@ -381,7 +453,9 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, | |||
| 381 | const char *name; | 453 | const char *name; |
| 382 | int ret, nlen; | 454 | int ret, nlen; |
| 383 | 455 | ||
| 384 | _enter("{%p},,%s,", parent->dentry, key); | 456 | _enter("OBJ%x{%p},OBJ%x,%s,", |
| 457 | parent->fscache.debug_id, parent->dentry, | ||
| 458 | object->fscache.debug_id, key); | ||
| 385 | 459 | ||
| 386 | cache = container_of(parent->fscache.cache, | 460 | cache = container_of(parent->fscache.cache, |
| 387 | struct cachefiles_cache, cache); | 461 | struct cachefiles_cache, cache); |
| @@ -509,7 +583,7 @@ lookup_again: | |||
| 509 | * mutex) */ | 583 | * mutex) */ |
| 510 | object->dentry = NULL; | 584 | object->dentry = NULL; |
| 511 | 585 | ||
| 512 | ret = cachefiles_bury_object(cache, dir, next); | 586 | ret = cachefiles_bury_object(cache, dir, next, true); |
| 513 | dput(next); | 587 | dput(next); |
| 514 | next = NULL; | 588 | next = NULL; |
| 515 | 589 | ||
| @@ -828,7 +902,7 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | |||
| 828 | /* actually remove the victim (drops the dir mutex) */ | 902 | /* actually remove the victim (drops the dir mutex) */ |
| 829 | _debug("bury"); | 903 | _debug("bury"); |
| 830 | 904 | ||
| 831 | ret = cachefiles_bury_object(cache, dir, victim); | 905 | ret = cachefiles_bury_object(cache, dir, victim, false); |
| 832 | if (ret < 0) | 906 | if (ret < 0) |
| 833 | goto error; | 907 | goto error; |
| 834 | 908 | ||
