From: Hou Tao <houtao1@xxxxxxxxxx> Factor out more common methods for bounce buffer of fuse args: 1) virtio_fs_argbuf_setup_sg: set-up sgs for bounce buffer 2) virtio_fs_argbuf_copy_from_in_arg: copy each in-arg to bounce buffer 3) virtio_fs_argbuf_out_args_offset: calc the start offset of out-arg 4) virtio_fs_argbuf_copy_to_out_arg: copy bounce buffer to each out-arg These methods will be used to implement bounce buffer backed by scattered pages which are allocated separatedly. Signed-off-by: Hou Tao <houtao1@xxxxxxxxxx> --- fs/fuse/virtio_fs.c | 77 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index cd1330506daba..f10fff7f23a0f 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -86,6 +86,10 @@ struct virtio_fs_req_work { struct work_struct done_work; }; +struct virtio_fs_argbuf { + DECLARE_FLEX_ARRAY(u8, buf); +}; + static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, struct fuse_req *req, bool in_flight); @@ -404,13 +408,15 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) } } -static void virtio_fs_argbuf_free(void *argbuf) +static void virtio_fs_argbuf_free(struct virtio_fs_argbuf *argbuf) { kfree(argbuf); } -static void *virtio_fs_argbuf_new(struct fuse_args *args, gfp_t gfp) +static struct virtio_fs_argbuf *virtio_fs_argbuf_new(struct fuse_args *args, + gfp_t gfp) { + struct virtio_fs_argbuf *argbuf; unsigned int numargs; unsigned int len; @@ -419,7 +425,41 @@ static void *virtio_fs_argbuf_new(struct fuse_args *args, gfp_t gfp) numargs = args->out_numargs - args->out_pages; len += fuse_len_args(numargs, args->out_args); - return kmalloc(len, gfp); + argbuf = kmalloc(struct_size(argbuf, buf, len), gfp); + + return argbuf; +} + +static unsigned int virtio_fs_argbuf_setup_sg(struct virtio_fs_argbuf *argbuf, + unsigned int offset, + unsigned int len, + struct scatterlist *sg) +{ + sg_init_one(sg, argbuf->buf + offset, len); + return 1; +} + +static void virtio_fs_argbuf_copy_from_in_arg(struct virtio_fs_argbuf *argbuf, + unsigned int offset, + const void *src, unsigned int len) +{ + memcpy(argbuf->buf + offset, src, len); +} + +static unsigned int +virtio_fs_argbuf_out_args_offset(struct virtio_fs_argbuf *argbuf, + const struct fuse_args *args) +{ + unsigned int num_in = args->in_numargs - args->in_pages; + + return fuse_len_args(num_in, (struct fuse_arg *)args->in_args); +} + +static void virtio_fs_argbuf_copy_to_out_arg(struct virtio_fs_argbuf *argbuf, + unsigned int offset, void *dst, + unsigned int len) +{ + memcpy(dst, argbuf->buf + offset, len); } /* @@ -515,9 +555,9 @@ static void copy_args_to_argbuf(struct fuse_req *req) num_in = args->in_numargs - args->in_pages; for (i = 0; i < num_in; i++) { - memcpy(req->argbuf + offset, - args->in_args[i].value, - args->in_args[i].size); + virtio_fs_argbuf_copy_from_in_arg(req->argbuf, offset, + args->in_args[i].value, + args->in_args[i].size); offset += args->in_args[i].size; } } @@ -525,17 +565,19 @@ static void copy_args_to_argbuf(struct fuse_req *req) /* Copy args out of req->argbuf */ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) { + struct virtio_fs_argbuf *argbuf; unsigned int remaining; unsigned int offset; - unsigned int num_in; unsigned int num_out; unsigned int i; remaining = req->out.h.len - sizeof(req->out.h); - num_in = args->in_numargs - args->in_pages; num_out = args->out_numargs - args->out_pages; - offset = fuse_len_args(num_in, (struct fuse_arg *)args->in_args); + if (!num_out) + goto out; + argbuf = req->argbuf; + offset = virtio_fs_argbuf_out_args_offset(argbuf, args); for (i = 0; i < num_out; i++) { unsigned int argsize = args->out_args[i].size; @@ -545,13 +587,16 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) argsize = remaining; } - memcpy(args->out_args[i].value, req->argbuf + offset, argsize); + virtio_fs_argbuf_copy_to_out_arg(argbuf, offset, + args->out_args[i].value, + argsize); offset += argsize; if (i != args->out_numargs - 1) remaining -= argsize; } +out: /* Store the actual size of the variable-length arg */ if (args->out_argvar) args->out_args[args->out_numargs - 1].size = remaining; @@ -1100,7 +1145,6 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg, struct fuse_arg *args, unsigned int numargs, bool argpages, - void *argbuf, unsigned int *len_used) { struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args); @@ -1109,7 +1153,8 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg, len = fuse_len_args(numargs - argpages, args); if (len) - sg_init_one(&sg[total_sgs++], argbuf, len); + total_sgs += virtio_fs_argbuf_setup_sg(req->argbuf, *len_used, + len, &sg[total_sgs]); if (argpages) total_sgs += sg_init_fuse_pages(&sg[total_sgs], @@ -1117,8 +1162,7 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg, ap->num_pages, args[numargs - 1].size); - if (len_used) - *len_used = len; + *len_used = len; return total_sgs; } @@ -1168,7 +1212,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, out_sgs += sg_init_fuse_args(&sg[out_sgs], req, (struct fuse_arg *)args->in_args, args->in_numargs, args->in_pages, - req->argbuf, &argbuf_used); + &argbuf_used); /* Reply elements */ if (test_bit(FR_ISREPLY, &req->flags)) { @@ -1176,8 +1220,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, &req->out.h, sizeof(req->out.h)); in_sgs += sg_init_fuse_args(&sg[out_sgs + in_sgs], req, args->out_args, args->out_numargs, - args->out_pages, - req->argbuf + argbuf_used, NULL); + args->out_pages, &argbuf_used); } WARN_ON(out_sgs + in_sgs != total_sgs); -- 2.29.2