diff options
author | Kiran Kumar Modukuri <kiran.modukuri@gmail.com> | 2018-06-21 16:25:53 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-07-25 09:49:00 -0400 |
commit | 5ce83d4bb7d8e11e8c1c687d09f4b5ae67ef3ce3 (patch) | |
tree | b2c096773a06825b1d82304cfe125175d091e79a /fs/cachefiles/namei.c | |
parent | f29507ce66701084c39aeb1b0ae71690cbff3554 (diff) |
cachefiles: Fix missing clear of the CACHEFILES_OBJECT_ACTIVE flag
In cachefiles_mark_object_active(), the new object is marked active and
then we try to add it to the active object tree. If a conflicting object
is already present, we want to wait for that to go away. After the wait,
we go round again and try to re-mark the object as being active - but it's
already marked active from the first time we went through and a BUG is
issued.
Fix this by clearing the CACHEFILES_OBJECT_ACTIVE flag before we try again.
Analysis from Kiran Kumar Modukuri:
[Impact]
Oops during heavy NFS + FSCache + Cachefiles
CacheFiles: Error: Overlong wait for old active object to go away.
BUG: unable to handle kernel NULL pointer dereference at 0000000000000002
CacheFiles: Error: Object already active kernel BUG at
fs/cachefiles/namei.c:163!
[Cause]
In a heavily loaded system with big files being read and truncated, an
fscache object for a cookie is being dropped and a new object being
looked. The new object being looked for has to wait for the old object
to go away before the new object is moved to active state.
[Fix]
Clear the flag 'CACHEFILES_OBJECT_ACTIVE' for the new object when
retrying the object lookup.
[Testcase]
Have run ~100 hours of NFS stress tests and have not seen this bug recur.
[Regression Potential]
- Limited to fscache/cachefiles.
Fixes: 9ae326a69004 ("CacheFiles: A cache that backs onto a mounted filesystem")
Signed-off-by: Kiran Kumar Modukuri <kiran.modukuri@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/cachefiles/namei.c')
-rw-r--r-- | fs/cachefiles/namei.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index ab0bbe93b398..b5d6dd72dfa0 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -186,6 +186,7 @@ try_again: | |||
186 | * need to wait for it to be destroyed */ | 186 | * need to wait for it to be destroyed */ |
187 | wait_for_old_object: | 187 | wait_for_old_object: |
188 | trace_cachefiles_wait_active(object, dentry, xobject); | 188 | trace_cachefiles_wait_active(object, dentry, xobject); |
189 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | ||
189 | 190 | ||
190 | if (fscache_object_is_live(&xobject->fscache)) { | 191 | if (fscache_object_is_live(&xobject->fscache)) { |
191 | pr_err("\n"); | 192 | pr_err("\n"); |
@@ -248,7 +249,6 @@ wait_for_old_object: | |||
248 | goto try_again; | 249 | goto try_again; |
249 | 250 | ||
250 | requeue: | 251 | requeue: |
251 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | ||
252 | cache->cache.ops->put_object(&xobject->fscache, cachefiles_obj_put_wait_timeo); | 252 | cache->cache.ops->put_object(&xobject->fscache, cachefiles_obj_put_wait_timeo); |
253 | _leave(" = -ETIMEDOUT"); | 253 | _leave(" = -ETIMEDOUT"); |
254 | return -ETIMEDOUT; | 254 | return -ETIMEDOUT; |