[Devel] [PATCH VZ9] fs/fuse: avoid copying out data to killed requests.
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Fri Jan 10 12:49:56 MSK 2025
On 1/7/25 20:57, Liu Kui wrote:
> 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
>
> For branch-rh9-5.14.0-427.33.1.vz9.72.x-ovz
Common practice in mailing lists is to ignore previous letters with same
subject, so I had no idea we already have a patch for older kernels and
spent time to port it myself.
Please add RK tag to patch subject in case sending patch for RK, so it
is easier to find it. Also please mention this full identifying subject
in jira.
>
> Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
> ---
> fs/fuse/dev.c | 15 ++++++---------
> fs/fuse/inode.c | 6 +++++-
> 2 files changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 01df9d4e4e70..29f8c4cc9525 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -2016,6 +2016,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;
> @@ -2215,14 +2218,6 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
> goto copy_finish;
> }
>
> - if (oh.error == FUSE_OUT_SPLICES) {
> - 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;
> @@ -2232,7 +2227,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)
> 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 */
--
Best regards, Tikhomirov Pavel
Senior Software Developer, Virtuozzo.
More information about the Devel
mailing list