@@ -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) {