diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2019-09-10 16:04:10 +0300 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2019-09-10 17:29:49 +0300 |
commit | 1259728731a7902c4965952c55fa16014b4fd0e7 (patch) | |
tree | 3821ca6b5e930157a48fa2ca0948a9e7d7fa7fcc | |
parent | 338f2e3f3341a9a844331b1bcb159e68638d5eef (diff) | |
download | linux-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.c | 45 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 6 |
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 |