fuse: add simple background helper
authorMiklos Szeredi <mszeredi@redhat.com>
Tue, 10 Sep 2019 13:04:10 +0000 (15:04 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 10 Sep 2019 14:29:49 +0000 (16:29 +0200)
Create a helper named fuse_simple_background() that is similar to
fuse_simple_request().  Unlike the latter, it returns immediately and calls
the supplied 'end' callback when the reply is received.

The supplied 'args' pointer is stored in 'fuse_req' which allows the
callback to interpret the output arguments decoded from the reply.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c
fs/fuse/fuse_i.h

index 29723e1..a52a738 100644 (file)
@@ -626,6 +626,51 @@ bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req)
        return queued;
 }
 
+static void fuse_simple_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+       struct fuse_args *args = req->args;
+       int err = req->out.h.error;
+
+       if (!err && args->out_argvar) {
+               BUG_ON(args->out_numargs == 0);
+               args->out_args[args->out_numargs - 1].size =
+                       req->out.args[args->out_numargs - 1].size;
+       }
+       req->args->end(fc, req->args, req->out.h.error);
+}
+
+int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args,
+                           gfp_t gfp_flags)
+{
+       struct fuse_req *req;
+
+       if (args->force) {
+               WARN_ON(!args->nocreds);
+               req = __fuse_request_alloc(0, gfp_flags);
+               if (!req)
+                       return -ENOMEM;
+               __set_bit(FR_BACKGROUND, &req->flags);
+       } else {
+               WARN_ON(args->nocreds);
+               req = __fuse_get_req(fc, 0, true);
+               if (IS_ERR(req))
+                       return PTR_ERR(req);
+       }
+
+       fuse_args_to_req(req, args);
+
+       req->args = args;
+       req->end = fuse_simple_end;
+
+       if (!fuse_request_queue_background(fc, req)) {
+               fuse_put_request(fc, req);
+               return -ENOTCONN;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fuse_simple_background);
+
 void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 {
        WARN_ON(!req->end);
index b62a3e3..8f46c55 100644 (file)
@@ -301,6 +301,7 @@ struct fuse_args {
        bool page_replace:1;
        struct fuse_in_arg in_args[3];
        struct fuse_arg out_args[2];
+       void (*end)(struct fuse_conn *fc, struct fuse_args *args, int error);
 };
 
 struct fuse_args_pages {
@@ -381,6 +382,9 @@ struct fuse_req {
        /** Entry on the interrupts list  */
        struct list_head intr_entry;
 
+       /* Input/output arguments */
+       struct fuse_args *args;
+
        /** refcount */
        refcount_t count;
 
@@ -948,6 +952,8 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req);
  * Simple request sending that does request allocation and freeing
  */
 ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args);
+int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args,
+                          gfp_t gfp_flags);
 
 /**
  * Send a request in the background