diff options
Diffstat (limited to 'fs/cachefiles/namei.c')
-rw-r--r-- | fs/cachefiles/namei.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 14ac4806e291..f4a7840bf42c 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
22 | #include <linux/slab.h> | ||
22 | #include "internal.h" | 23 | #include "internal.h" |
23 | 24 | ||
24 | #define CACHEFILES_KEYBUF_SIZE 512 | 25 | #define CACHEFILES_KEYBUF_SIZE 512 |
@@ -92,6 +93,59 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object, | |||
92 | } | 93 | } |
93 | 94 | ||
94 | /* | 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 | /* | ||
95 | * record the fact that an object is now active | 149 | * record the fact that an object is now active |
96 | */ | 150 | */ |
97 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, | 151 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
@@ -218,7 +272,8 @@ requeue: | |||
218 | */ | 272 | */ |
219 | static int cachefiles_bury_object(struct cachefiles_cache *cache, | 273 | static int cachefiles_bury_object(struct cachefiles_cache *cache, |
220 | struct dentry *dir, | 274 | struct dentry *dir, |
221 | struct dentry *rep) | 275 | struct dentry *rep, |
276 | bool preemptive) | ||
222 | { | 277 | { |
223 | struct dentry *grave, *trap; | 278 | struct dentry *grave, *trap; |
224 | char nbuffer[8 + 8 + 1]; | 279 | char nbuffer[8 + 8 + 1]; |
@@ -228,11 +283,16 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache, | |||
228 | 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, |
229 | 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); |
230 | 285 | ||
286 | _debug("remove %p from %p", rep, dir); | ||
287 | |||
231 | /* non-directories can just be unlinked */ | 288 | /* non-directories can just be unlinked */ |
232 | if (!S_ISDIR(rep->d_inode->i_mode)) { | 289 | if (!S_ISDIR(rep->d_inode->i_mode)) { |
233 | _debug("unlink stale object"); | 290 | _debug("unlink stale object"); |
234 | ret = vfs_unlink(dir->d_inode, rep); | 291 | ret = vfs_unlink(dir->d_inode, rep); |
235 | 292 | ||
293 | if (preemptive) | ||
294 | cachefiles_mark_object_buried(cache, rep); | ||
295 | |||
236 | mutex_unlock(&dir->d_inode->i_mutex); | 296 | mutex_unlock(&dir->d_inode->i_mutex); |
237 | 297 | ||
238 | if (ret == -EIO) | 298 | if (ret == -EIO) |
@@ -324,6 +384,9 @@ try_again: | |||
324 | if (ret != 0 && ret != -ENOMEM) | 384 | if (ret != 0 && ret != -ENOMEM) |
325 | cachefiles_io_error(cache, "Rename failed with error %d", ret); | 385 | cachefiles_io_error(cache, "Rename failed with error %d", ret); |
326 | 386 | ||
387 | if (preemptive) | ||
388 | cachefiles_mark_object_buried(cache, rep); | ||
389 | |||
327 | unlock_rename(cache->graveyard, dir); | 390 | unlock_rename(cache->graveyard, dir); |
328 | dput(grave); | 391 | dput(grave); |
329 | _leave(" = 0"); | 392 | _leave(" = 0"); |
@@ -339,7 +402,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
339 | struct dentry *dir; | 402 | struct dentry *dir; |
340 | int ret; | 403 | int ret; |
341 | 404 | ||
342 | _enter(",{%p}", object->dentry); | 405 | _enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry); |
343 | 406 | ||
344 | ASSERT(object->dentry); | 407 | ASSERT(object->dentry); |
345 | ASSERT(object->dentry->d_inode); | 408 | ASSERT(object->dentry->d_inode); |
@@ -348,7 +411,27 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
348 | dir = dget_parent(object->dentry); | 411 | dir = dget_parent(object->dentry); |
349 | 412 | ||
350 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 413 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
351 | ret = cachefiles_bury_object(cache, dir, object->dentry); | 414 | |
415 | if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { | ||
416 | /* object allocation for the same key preemptively deleted this | ||
417 | * object's file so that it could create its own file */ | ||
418 | _debug("object preemptively buried"); | ||
419 | mutex_unlock(&dir->d_inode->i_mutex); | ||
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 | } | ||
434 | } | ||
352 | 435 | ||
353 | dput(dir); | 436 | dput(dir); |
354 | _leave(" = %d", ret); | 437 | _leave(" = %d", ret); |
@@ -370,7 +453,9 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, | |||
370 | const char *name; | 453 | const char *name; |
371 | int ret, nlen; | 454 | int ret, nlen; |
372 | 455 | ||
373 | _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); | ||
374 | 459 | ||
375 | cache = container_of(parent->fscache.cache, | 460 | cache = container_of(parent->fscache.cache, |
376 | struct cachefiles_cache, cache); | 461 | struct cachefiles_cache, cache); |
@@ -498,7 +583,7 @@ lookup_again: | |||
498 | * mutex) */ | 583 | * mutex) */ |
499 | object->dentry = NULL; | 584 | object->dentry = NULL; |
500 | 585 | ||
501 | ret = cachefiles_bury_object(cache, dir, next); | 586 | ret = cachefiles_bury_object(cache, dir, next, true); |
502 | dput(next); | 587 | dput(next); |
503 | next = NULL; | 588 | next = NULL; |
504 | 589 | ||
@@ -817,7 +902,7 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, | |||
817 | /* actually remove the victim (drops the dir mutex) */ | 902 | /* actually remove the victim (drops the dir mutex) */ |
818 | _debug("bury"); | 903 | _debug("bury"); |
819 | 904 | ||
820 | ret = cachefiles_bury_object(cache, dir, victim); | 905 | ret = cachefiles_bury_object(cache, dir, victim, false); |
821 | if (ret < 0) | 906 | if (ret < 0) |
822 | goto error; | 907 | goto error; |
823 | 908 | ||