[Devel] [PATCH RHEL9 COMMIT] fs/fuse: avoid copying out data to killed requests
Konstantin Khorenko
khorenko at virtuozzo.com
Thu Jan 9 17:04:26 MSK 2025
The commit is pushed to "branch-rh9-5.14.0-427.44.1.vz9.80.x-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh9-5.14.0-427.44.1.vz9.80.3
------>
commit 47f3a6b72349729a0efe1c1b86287cc702aca3c4
Author: Liu Kui <kui.liu at virtuozzo.com>
Date: Tue Jan 7 20:55:10 2025 +0800
fs/fuse: avoid copying out data to killed requests
When a read request is killed, its buff pages would have been dropped,
copying data over would cause kernel crash due to invalid memory access.
Therefore we should not copying data over to a killed request.
Meanwhile if a read request is already under data write back IO, we
should wait for it to complete instead of killing it to avoid freeing
its buff pages.
Related to #VSTOR-96560
https://virtuozzo.atlassian.net/browse/VSTOR-96560
Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
Acked-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
Feature: fuse: enhanced splice support
---
fs/fuse/dev.c | 19 +++++++++----------
fs/fuse/inode.c | 6 +++++-
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0fef877f731f..101bd4907828 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -2017,6 +2017,9 @@ static int copy_out_splices(struct fuse_copy_state *cs, struct fuse_args *args,
struct page *dpage = ap->pages[0];
struct fd f = { .file = NULL };
+ if (args->out_numargs != 1 || !args->out_pages)
+ return -EINVAL;
+
nsplices = nbytes - sizeof(struct fuse_out_header);
if (nsplices & 3)
return -EINVAL;
@@ -2156,6 +2159,9 @@ static int copy_out_krpczc(struct fuse_copy_state *cs, struct fuse_args *args,
void *dst;
int err;
+ if (args->out_numargs != 1 || !args->out_pages)
+ return -EINVAL;
+
nchunks = nbytes - sizeof(struct fuse_out_header);
/* this is always at least one chunk */
@@ -2323,15 +2329,6 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
goto copy_finish;
}
- if (oh.error == FUSE_OUT_SPLICES &&
- oh.error == FUSE_OUT_KRPCZC) {
- if (req->args->out_numargs != 1 || !req->args->out_pages) {
- spin_unlock(&fpq->lock);
- err = -EINVAL;
- goto copy_finish;
- }
- }
-
clear_bit(FR_SENT, &req->flags);
list_move(&req->list, &fpq->io);
req->out.h = oh;
@@ -2341,7 +2338,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
if (!req->args->page_replace)
cs->move_pages = 0;
- if (oh.error == FUSE_OUT_SPLICES) {
+ if (req->args->killed) {
+ err = -EINVAL;
+ } else if (oh.error == FUSE_OUT_SPLICES) {
req->out.h.error = 0;
err = copy_out_splices(cs, req->args, nbytes);
} else if (oh.error == FUSE_OUT_KRPCZC) {
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e147f86a8f64..b27422d1ee38 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -491,6 +491,11 @@ void fuse_kill_requests(struct fuse_conn *fc, struct inode *inode,
int i;
BUG_ON(req->in.h.opcode != FUSE_READ);
+
+ /* skip the request that is under data write back IO */
+ if (test_bit(FR_LOCKED, &req->flags) && req->out.h.unique)
+ continue;
+
req->args->killed = 1;
for (i = 0; i < ia->ap.num_pages; i++) {
@@ -602,7 +607,6 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)
fuse_kill_requests(fc, inode, &fpq->processing[i]);
fuse_kill_requests(fc, inode, &fpq->io);
spin_unlock(&fpq->lock);
-
}
wake_up(&fi->page_waitq); /* readpage[s] can wait on fuse wb */
More information about the Devel
mailing list