aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cachefiles
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-09-30 09:50:28 -0400
committerDavid Howells <dhowells@redhat.com>2014-09-30 09:50:28 -0400
commita3b7c00484e1177e7eb9b047c46cac571b82442f (patch)
treeaf896c176c43d334691e5853104fe7bc126c4842 /fs/cachefiles
parentfe82dcec644244676d55a1384c958d5f67979adb (diff)
CacheFiles: Handle object being killed before being set up
If a cache object gets killed whilst in the process of being set up - for instance if the netfs relinquishes the cookie that the object is associated with - then the object's state machine will transit to the DROP_OBJECT state without necessarily going through the LOOKUP_OBJECT or CREATE_OBJECT states. This is a problem for CacheFiles because cachefiles_drop_object() assumes that object->dentry will be set upon reaching the DROP_OBJECT state and has an ASSERT() to that effect (see the oops below) - but object->dentry doesn't get set until the LOOKUP_OBJECT or CREATE_OBJECT states (and not always then if they fail). To fix this, just make the dentry cleanup in cachefiles_drop_object() conditional on the dentry actually being set and remove the assertion. CacheFiles: Assertion failed ------------[ cut here ]------------ kernel BUG at .../fs/cachefiles/namei.c:425! ... Workqueue: fscache_object fscache_object_work_func [fscache] ... RIP: ... cachefiles_delete_object+0xcd/0x110 [cachefiles] ... Call Trace: [<ffffffffa043280f>] ? cachefiles_drop_object+0xff/0x130 [cachefiles] [<ffffffffa02ac511>] ? fscache_drop_object+0xd1/0x1d0 [fscache] [<ffffffffa02ac697>] ? fscache_object_work_func+0x87/0x210 [fscache] [<ffffffff81080635>] ? process_one_work+0x155/0x450 [<ffffffff81081c44>] ? worker_thread+0x114/0x370 [<ffffffff81081b30>] ? manage_workers.isra.21+0x2c0/0x2c0 [<ffffffff81087fcc>] ? kthread+0xbc/0xe0 [<ffffffff81087f10>] ? flush_kthread_worker+0xa0/0xa0 [<ffffffff8150638c>] ? ret_from_fork+0x7c/0xb0 [<ffffffff81087f10>] ? flush_kthread_worker+0xa0/0xa0 Reported-by: Manuel Schölling <manuel.schoelling@gmx.de> Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'fs/cachefiles')
-rw-r--r--fs/cachefiles/interface.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 584743d456c3..1c7293c3a93a 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -268,20 +268,27 @@ static void cachefiles_drop_object(struct fscache_object *_object)
268 ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); 268 ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
269#endif 269#endif
270 270
271 /* delete retired objects */ 271 /* We need to tidy the object up if we did in fact manage to open it.
272 if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) && 272 * It's possible for us to get here before the object is fully
273 _object != cache->cache.fsdef 273 * initialised if the parent goes away or the object gets retired
274 ) { 274 * before we set it up.
275 _debug("- retire object OBJ%x", object->fscache.debug_id); 275 */
276 cachefiles_begin_secure(cache, &saved_cred); 276 if (object->dentry) {
277 cachefiles_delete_object(cache, object); 277 /* delete retired objects */
278 cachefiles_end_secure(cache, saved_cred); 278 if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) &&
279 } 279 _object != cache->cache.fsdef
280 ) {
281 _debug("- retire object OBJ%x", object->fscache.debug_id);
282 cachefiles_begin_secure(cache, &saved_cred);
283 cachefiles_delete_object(cache, object);
284 cachefiles_end_secure(cache, saved_cred);
285 }
280 286
281 /* close the filesystem stuff attached to the object */ 287 /* close the filesystem stuff attached to the object */
282 if (object->backer != object->dentry) 288 if (object->backer != object->dentry)
283 dput(object->backer); 289 dput(object->backer);
284 object->backer = NULL; 290 object->backer = NULL;
291 }
285 292
286 /* note that the object is now inactive */ 293 /* note that the object is now inactive */
287 if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { 294 if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {