[Devel] [PATCH VZ9] fs/fuse: avoid copying out data to killed requests.

Alexey Kuznetsov kuznet at virtuozzo.com
Tue Jan 7 16:42:29 MSK 2025


Ack

On Tue, Jan 7, 2025 at 8:56 PM Liu Kui <kui.liu at virtuozzo.com> 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
>
> Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
> ---
>  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 cd0dbd74db33..d1456a5e1693 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -489,6 +489,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++) {
> @@ -600,7 +605,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 */
> --
> 2.39.5 (Apple Git-154)



More information about the Devel mailing list