From: Hou Tao <hout...@huawei.com>

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 <hout...@huawei.com>
---
 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


Reply via email to