From: Hou Tao <houtao1@xxxxxxxxxx> The bounce buffer for fuse args in virtiofs will be extended to support scatterd pages later. Therefore, move the allocation and the free of argbuf out of the copy procedures and factor them into virtio_fs_argbuf_{new|free}() helpers. Signed-off-by: Hou Tao <houtao1@xxxxxxxxxx> --- fs/fuse/virtio_fs.c | 52 +++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 5f1be1da92ce9..cd1330506daba 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -404,6 +404,24 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) } } +static void virtio_fs_argbuf_free(void *argbuf) +{ + kfree(argbuf); +} + +static void *virtio_fs_argbuf_new(struct fuse_args *args, gfp_t gfp) +{ + unsigned int numargs; + unsigned int len; + + numargs = args->in_numargs - args->in_pages; + len = fuse_len_args(numargs, (struct fuse_arg *) args->in_args); + numargs = args->out_numargs - args->out_pages; + len += fuse_len_args(numargs, args->out_args); + + return kmalloc(len, gfp); +} + /* * Returns 1 if queue is full and sender should wait a bit before sending * next request, 0 otherwise. @@ -487,36 +505,24 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) } } -/* Allocate and copy args into req->argbuf */ -static int copy_args_to_argbuf(struct fuse_req *req) +/* Copy args into req->argbuf */ +static void copy_args_to_argbuf(struct fuse_req *req) { struct fuse_args *args = req->args; unsigned int offset = 0; unsigned int num_in; - unsigned int num_out; - unsigned int len; unsigned int i; num_in = args->in_numargs - args->in_pages; - num_out = args->out_numargs - args->out_pages; - len = fuse_len_args(num_in, (struct fuse_arg *) args->in_args) + - fuse_len_args(num_out, args->out_args); - - req->argbuf = kmalloc(len, GFP_ATOMIC); - if (!req->argbuf) - return -ENOMEM; - for (i = 0; i < num_in; i++) { memcpy(req->argbuf + offset, args->in_args[i].value, args->in_args[i].size); offset += args->in_args[i].size; } - - return 0; } -/* Copy args out of and free req->argbuf */ +/* Copy args out of req->argbuf */ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) { unsigned int remaining; @@ -549,9 +555,6 @@ static void copy_args_from_argbuf(struct fuse_args *args, struct fuse_req *req) /* Store the actual size of the variable-length arg */ if (args->out_argvar) args->out_args[args->out_numargs - 1].size = remaining; - - kfree(req->argbuf); - req->argbuf = NULL; } /* Work function for request completion */ @@ -571,6 +574,9 @@ static void virtio_fs_request_complete(struct fuse_req *req, args = req->args; copy_args_from_argbuf(args, req); + virtio_fs_argbuf_free(req->argbuf); + req->argbuf = NULL; + if (args->out_pages && args->page_zeroing) { len = args->out_args[args->out_numargs - 1].size; ap = container_of(args, typeof(*ap), args); @@ -1149,9 +1155,13 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, } /* Use a bounce buffer since stack args cannot be mapped */ - ret = copy_args_to_argbuf(req); - if (ret < 0) + req->argbuf = virtio_fs_argbuf_new(args, GFP_ATOMIC); + if (!req->argbuf) { + ret = -ENOMEM; goto out; + } + + copy_args_to_argbuf(req); /* Request elements */ sg_init_one(&sg[out_sgs++], &req->in.h, sizeof(req->in.h)); @@ -1210,7 +1220,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, out: if (ret < 0 && req->argbuf) { - kfree(req->argbuf); + virtio_fs_argbuf_free(req->argbuf); req->argbuf = NULL; } if (sgs != stack_sgs) { -- 2.29.2