summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2019-09-10 16:04:10 +0300
committerMiklos Szeredi <mszeredi@redhat.com>2019-09-10 17:29:49 +0300
commit1259728731a7902c4965952c55fa16014b4fd0e7 (patch)
tree3821ca6b5e930157a48fa2ca0948a9e7d7fa7fcc
parent338f2e3f3341a9a844331b1bcb159e68638d5eef (diff)
downloadlinux-1259728731a7902c4965952c55fa16014b4fd0e7.tar.xz
fuse: add simple background helper
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>
-rw-r--r--fs/fuse/dev.c45
-rw-r--r--fs/fuse/fuse_i.h6
2 files changed, 51 insertions, 0 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 29723e143666..a52a7380baa4 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -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);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b62a3e37ea4c..8f46c5549e57 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -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