Commit 510c2963 authored by David Howells's avatar David Howells Committed by Sasha Levin

fscache: Clear outstanding writes when disabling a cookie

[ Upstream commit 6bdded59 ]

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: default avatarJianhong Yin <jiyin@redhat.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Acked-by: default avatarSteve Dickson <steved@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent 42c32ac3
...@@ -541,6 +541,7 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) ...@@ -541,6 +541,7 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate)
hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) {
if (invalidate) if (invalidate)
set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); set_bit(FSCACHE_OBJECT_RETIRED, &object->flags);
clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
} }
} else { } else {
...@@ -559,6 +560,10 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) ...@@ -559,6 +560,10 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate)
wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
/* Make sure any pending writes are cancelled. */
if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
fscache_invalidate_writes(cookie);
/* Reset the cookie state if it wasn't relinquished */ /* Reset the cookie state if it wasn't relinquished */
if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) {
atomic_inc(&cookie->n_active); atomic_inc(&cookie->n_active);
......
...@@ -632,6 +632,12 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob ...@@ -632,6 +632,12 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob
clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
object->oob_event_mask = 0; object->oob_event_mask = 0;
if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) {
/* Reject any new read/write ops and abort any that are pending. */
clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
fscache_cancel_all_ops(object);
}
if (list_empty(&object->dependents) && if (list_empty(&object->dependents) &&
object->n_ops == 0 && object->n_ops == 0 &&
object->n_children == 0) object->n_children == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment