diff options
author | David Howells <dhowells@redhat.com> | 2017-01-18 09:29:25 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-01-31 13:23:09 -0500 |
commit | 6bdded59c8933940ac7e5b416448276ac89d1144 (patch) | |
tree | 0620c0018aef6e596711114622e40d2f408e4bd3 | |
parent | 62deb8187d116581c88c69a2dd9b5c16588545d4 (diff) |
fscache: Clear outstanding writes when disabling a cookie
fscache_disable_cookie() needs to clear the outstanding writes on the
cookie it's disabling because they cannot be completed after.
Without this, fscache_nfs_open_file() gets stuck because it disables the
cookie when the file is opened for writing but can't uncache the pages till
afterwards - otherwise there's a race between the open routine and anyone
who already has it open R/O and is still reading from it.
Looking in /proc/pid/stack of the offending process shows:
[<ffffffffa0142883>] __fscache_wait_on_page_write+0x82/0x9b [fscache]
[<ffffffffa014336e>] __fscache_uncache_all_inode_pages+0x91/0xe1 [fscache]
[<ffffffffa01740fa>] nfs_fscache_open_file+0x59/0x9e [nfs]
[<ffffffffa01ccf41>] nfs4_file_open+0x17f/0x1b8 [nfsv4]
[<ffffffff8117350e>] do_dentry_open+0x16d/0x2b7
[<ffffffff811743ac>] vfs_open+0x5c/0x65
[<ffffffff81184185>] path_openat+0x785/0x8fb
[<ffffffff81184343>] do_filp_open+0x48/0x9e
[<ffffffff81174710>] do_sys_open+0x13b/0x1cb
[<ffffffff811747b9>] SyS_open+0x19/0x1b
[<ffffffff81001c44>] do_syscall_64+0x80/0x17a
[<ffffffff8165c2da>] return_from_SYSCALL_64+0x0/0x7a
[<ffffffffffffffff>] 0xffffffffffffffff
Reported-by: Jianhong Yin <jiyin@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Steve Dickson <steved@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/fscache/cookie.c | 5 | ||||
-rw-r--r-- | fs/fscache/object.c | 6 |
2 files changed, 11 insertions, 0 deletions
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 4304072161aa..40d61077bead 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -542,6 +542,7 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) | |||
542 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { | 542 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { |
543 | if (invalidate) | 543 | if (invalidate) |
544 | set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); | 544 | set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); |
545 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
545 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | 546 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); |
546 | } | 547 | } |
547 | } else { | 548 | } else { |
@@ -560,6 +561,10 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) | |||
560 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, | 561 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, |
561 | TASK_UNINTERRUPTIBLE); | 562 | TASK_UNINTERRUPTIBLE); |
562 | 563 | ||
564 | /* Make sure any pending writes are cancelled. */ | ||
565 | if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) | ||
566 | fscache_invalidate_writes(cookie); | ||
567 | |||
563 | /* Reset the cookie state if it wasn't relinquished */ | 568 | /* Reset the cookie state if it wasn't relinquished */ |
564 | if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { | 569 | if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { |
565 | atomic_inc(&cookie->n_active); | 570 | atomic_inc(&cookie->n_active); |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 9e792e30f4db..be02a086ed9b 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -645,6 +645,12 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob | |||
645 | fscache_mark_object_dead(object); | 645 | fscache_mark_object_dead(object); |
646 | object->oob_event_mask = 0; | 646 | object->oob_event_mask = 0; |
647 | 647 | ||
648 | if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) { | ||
649 | /* Reject any new read/write ops and abort any that are pending. */ | ||
650 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
651 | fscache_cancel_all_ops(object); | ||
652 | } | ||
653 | |||
648 | if (list_empty(&object->dependents) && | 654 | if (list_empty(&object->dependents) && |
649 | object->n_ops == 0 && | 655 | object->n_ops == 0 && |
650 | object->n_children == 0) | 656 | object->n_children == 0) |