[Devel] [PATCH RHEL7 COMMIT] fs/fuse kio: keep fuse_file for requests waiting for shrink
Konstantin Khorenko
khorenko at virtuozzo.com
Tue May 21 19:02:19 MSK 2019
The commit is pushed to "branch-rh7-3.10.0-957.12.2.vz7.96.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.12.2.vz7.96.1
------>
commit 7893d6caa488b0cab5252d3047005d13ac30cc19
Author: Pavel Butsykin <pbutsykin at virtuozzo.com>
Date: Tue May 21 19:02:17 2019 +0300
fs/fuse kio: keep fuse_file for requests waiting for shrink
A pending request due to shrink operation may lose passed fuse_file. To fix it,
let's take the reference and save ff pointer to req->ff and then release it in
req->end() callback.
Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
=====================
Patchset description:
fix deadlock between synchronous reqs and fuse_invalidate_files
One more deadlock with fuse_invalidate_files():
[<ffffffff92ba7cc4>] __lock_page+0x74/0x90
[<ffffffff92bb9a75>] invalidate_inode_pages2_range+0x445/0x470
[<ffffffff92bb9ab7>] invalidate_inode_pages2+0x17/0x20
[<ffffffffc034cde5>] fuse_invalidate_files+0x235/0x270 [fuse]
[<ffffffffc033d3fb>] fuse_dev_do_write+0x7fb/0xe20 [fuse]
[<ffffffffc033ddc1>] fuse_dev_write+0x71/0xa0 [fuse]
[<ffffffff92c3c2e6>] do_sync_write+0x96/0xe0
[<ffffffff92c3cdc0>] vfs_write+0xc0/0x1f0
[<ffffffff92c3dbef>] SyS_write+0x7f/0xf0
[<ffffffff9315589b>] system_call_fastpath+0x22/0x27
This happened because synchronous kio read request was not dropped by kill_requests:
PID: 20684 TASK: ffff9543c2e71160 CPU: 5 COMMAND: "co_io"
[ffff9547b0faf9f8] __schedule at ffffffff93148a9f
[ffff9547b0fafa88] schedule at ffffffff93148fe9
[ffff9547b0fafa98] kpcs_req_send at ffffffffc047dab5 [fuse_kio_pcs]
[ffff9547b0fafb08] __fuse_request_send at ffffffffc033a987 [fuse]
[ffff9547b0fafb40] fuse_request_check_and_send at ffffffffc033e097 [fuse]
[ffff9547b0fafb50] fuse_send_read at ffffffffc03463ec [fuse]
[ffff9547b0fafb90] __fuse_readpage at ffffffffc03475ad [fuse]
[ffff9547b0fafc40] fuse_readpage at ffffffffc0347a3c [fuse]
[ffff9547b0fafca0] generic_file_read_iter at ffffffff92baa186
[ffff9547b0fafd58] generic_file_aio_read at ffffffff92baa5c5
[ffff9547b0fafdc0] fuse_file_aio_read at ffffffffc0343788 [fuse]
[ffff9547b0fafdf0] do_sync_read at ffffffff92c3c206
[ffff9547b0fafed0] vfs_read at ffffffff92c3cc2f
[ffff9547b0faff00] sys_pread64 at ffffffff92c3dcf2
[ffff9547b0faff50] system_call_fastpath at ffffffff9315589b
struct pcs_fuse_req {
req = {
list = {
next = 0xffff95479374eb18,
prev = 0xffff9547acf76e00
},
...
page_cache = 1,
page_needs_release = 0,
killed = 0,
...
ff = 0x0,
io_inode = 0xffff95445da0b740,
The fuse_file pointer was not initialized in req->ff, that means we can't check
ff->ff_state inside pcs_fuse_submit(), despite the fact that this request has
locked pages. It's believed that requests with an empty req->ff don't have pages,
therefore, such requests may not be synchronized with fuse_invalidate_files().
However, synchronous requests don't reference ff, but pass it as a parameter to
fuse_request_check_and_send().
This patchset fixes it.
https://pmc.acronis.com/browse/VSTOR-23034
Reviewed-by: Kirill Tkhai <ktkhai at virtuozzo.com>
Pavel Butsykin (4):
fs/fuse kio: forward fuse_file pointer to kpcs_req_send()
fs/fuse kio: add pending kio requests to kqueue
fs/fuse kio: style fix in pcs_fuse_submit()
fs/fuse kio: keep fuse_file for requests waiting for shrink
---
fs/fuse/file.c | 1 +
fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 0222854340df..a1dc3216da87 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -120,6 +120,7 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff)
atomic_inc(&ff->count);
return ff;
}
+EXPORT_SYMBOL_GPL(fuse_file_get);
static void fuse_release_async(struct work_struct *work)
{
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index cd3ec4897225..d53540b74b1c 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -823,6 +823,17 @@ static void wait_shrink(struct pcs_fuse_req *r, struct pcs_dentry_info *di)
list_add_tail(&r->exec.ireq.list, &di->size.queue);
}
+static void _pcs_ff_free_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+ struct pcs_fuse_req *r = pcs_req_from_fuse(req);
+
+ BUG_ON(!req->ff);
+ fuse_release_ff(req->inode, req->ff);
+
+ if (r->end)
+ r->end(fc, req);
+}
+
static bool kqueue_insert(struct pcs_dentry_info *di, struct fuse_file *ff,
struct fuse_req *req)
{
@@ -852,6 +863,11 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r, struct fuse_file *ff)
spin_lock(&di->lock);
/* Deffer all requests if shrink requested to prevent livelock */
if (di->size.op == PCS_SIZE_SHRINK) {
+ if (ff && !r->req.ff) {
+ r->end = r->req.end;
+ r->req.ff = fuse_file_get(ff);
+ r->req.end = _pcs_ff_free_end;
+ }
wait_shrink(r, di);
ret = 1;
goto out;
More information about the Devel
mailing list