[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