From 0c4dd4ba1426c599072511dcf95a15ee5e12725b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 09:49:04 +0100 Subject: fuse: don't wake up reserved req in fuse_conn_kill() Waking up reserved_req_waitq from fuse_conn_kill() doesn't make sense since we aren't chaging ff->reserved_req here, which is what this waitqueue signals. Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 03246cd..15653a0 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -387,7 +387,6 @@ void fuse_conn_kill(struct fuse_conn *fc) kill_fasync(&fc->fasync, SIGIO, POLL_IN); wake_up_all(&fc->waitq); wake_up_all(&fc->blocked_waitq); - wake_up_all(&fc->reserved_req_waitq); } EXPORT_SYMBOL_GPL(fuse_conn_kill); -- cgit v0.10.2 From 580640ba5d331eb5631a5de46941c98f5ed90886 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 09:49:04 +0100 Subject: fuse: flush requests on umount Use fuse_abort_conn() instead of fuse_conn_kill() in fuse_put_super(). This flushes and aborts requests still on any queues. But since we've already reset fc->connected, those requests would not be useful anyway and would be flushed when the fuse device is closed. Next patches will rely on requests being flushed before the superblock is destroyed. Use fuse_abort_conn() in cuse_process_init_reply() too, since it makes no difference there, and we can get rid of fuse_conn_kill(). Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 966ace8..28d0c7ab 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -415,7 +415,7 @@ err_unlock: err_region: unregister_chrdev_region(devt, 1); err: - fuse_conn_kill(fc); + fuse_abort_conn(fc); goto out; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e8e47a6..fbc63ab 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -804,8 +804,6 @@ void fuse_invalidate_atime(struct inode *inode); */ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); -void fuse_conn_kill(struct fuse_conn *fc); - /** * Initialize fuse_conn */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 15653a0..616a791 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -376,27 +376,13 @@ static void fuse_bdi_destroy(struct fuse_conn *fc) bdi_destroy(&fc->bdi); } -void fuse_conn_kill(struct fuse_conn *fc) -{ - spin_lock(&fc->lock); - fc->connected = 0; - fc->blocked = 0; - fc->initialized = 1; - spin_unlock(&fc->lock); - /* Flush all readers on this fs */ - kill_fasync(&fc->fasync, SIGIO, POLL_IN); - wake_up_all(&fc->waitq); - wake_up_all(&fc->blocked_waitq); -} -EXPORT_SYMBOL_GPL(fuse_conn_kill); - static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); fuse_send_destroy(fc); - fuse_conn_kill(fc); + fuse_abort_conn(fc); mutex_lock(&fuse_mutex); list_del(&fc->entry); fuse_ctl_remove_conn(fc); -- cgit v0.10.2 From baebccbe997d5023289e0fc9b4d0d71c6fc17a79 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 09:49:04 +0100 Subject: fuse: hold inode instead of path after release path_put() in release could trigger a DESTROY request in fuseblk. The possible deadlock was worked around by doing the path_put() with schedule_work(). This complexity isn't needed if we just hold the inode instead of the path. Since we now flush all requests before destroying the super block we can be sure that all held inodes will be dropped. Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/file.c b/fs/fuse/file.c index caa8d95..2d4ae68 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -89,37 +89,9 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff) return ff; } -static void fuse_release_async(struct work_struct *work) -{ - struct fuse_req *req; - struct fuse_conn *fc; - struct path path; - - req = container_of(work, struct fuse_req, misc.release.work); - path = req->misc.release.path; - fc = get_fuse_conn(path.dentry->d_inode); - - fuse_put_request(fc, req); - path_put(&path); -} - static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) { - if (fc->destroy_req) { - /* - * If this is a fuseblk mount, then it's possible that - * releasing the path will result in releasing the - * super block and sending the DESTROY request. If - * the server is single threaded, this would hang. - * For this reason do the path_put() in a separate - * thread. - */ - atomic_inc(&req->count); - INIT_WORK(&req->misc.release.work, fuse_release_async); - schedule_work(&req->misc.release.work); - } else { - path_put(&req->misc.release.path); - } + iput(req->misc.release.inode); } static void fuse_file_put(struct fuse_file *ff, bool sync) @@ -133,12 +105,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) * implement 'open' */ req->background = 0; - path_put(&req->misc.release.path); + iput(req->misc.release.inode); fuse_put_request(ff->fc, req); } else if (sync) { req->background = 0; fuse_request_send(ff->fc, req); - path_put(&req->misc.release.path); + iput(req->misc.release.inode); fuse_put_request(ff->fc, req); } else { req->end = fuse_release_end; @@ -297,9 +269,8 @@ void fuse_release_common(struct file *file, int opcode) inarg->lock_owner = fuse_lock_owner_id(ff->fc, (fl_owner_t) file); } - /* Hold vfsmount and dentry until release is finished */ - path_get(&file->f_path); - req->misc.release.path = file->f_path; + /* Hold inode until release is finished */ + req->misc.release.inode = igrab(file_inode(file)); /* * Normally this will send the RELEASE request, however if diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index fbc63ab..416fee2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -305,11 +305,8 @@ struct fuse_req { /** Data for asynchronous requests */ union { struct { - union { - struct fuse_release_in in; - struct work_struct work; - }; - struct path path; + struct fuse_release_in in; + struct inode *inode; } release; struct fuse_init_in init_in; struct fuse_init_out init_out; -- cgit v0.10.2 From f704dcb538eb80b7f5b26281a79b8e29a8e24d62 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 09:49:05 +0100 Subject: fuse: reduce max out args The third out-arg is never actually used. Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 416fee2..351c098 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -213,7 +213,7 @@ struct fuse_out { unsigned numargs; /** Array of arguments */ - struct fuse_arg args[3]; + struct fuse_arg args[2]; }; /** FUSE page descriptor */ -- cgit v0.10.2 From 7078187a795f862465325bcadf3070867c0cb5f8 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 09:49:05 +0100 Subject: fuse: introduce fuse_simple_request() helper The following pattern is repeated many times: req = fuse_get_req_nopages(fc); /* Initialize req->(in|out).args */ fuse_request_send(fc, req); err = req->out.h.error; fuse_put_request(req); Create a new replacement helper: /* Initialize args */ err = fuse_simple_request(fc, &args); In addition to reducing the code size, this will ease moving from the complex arg-based to a simpler page-based I/O on the fuse device. Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ca88731..ba11079 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -511,6 +511,35 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) } EXPORT_SYMBOL_GPL(fuse_request_send); +ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) +{ + struct fuse_req *req; + ssize_t ret; + + req = fuse_get_req(fc, 0); + if (IS_ERR(req)) + return PTR_ERR(req); + + req->in.h.opcode = args->in.h.opcode; + req->in.h.nodeid = args->in.h.nodeid; + req->in.numargs = args->in.numargs; + memcpy(req->in.args, args->in.args, + args->in.numargs * sizeof(struct fuse_in_arg)); + req->out.argvar = args->out.argvar; + req->out.numargs = args->out.numargs; + memcpy(req->out.args, args->out.args, + args->out.numargs * sizeof(struct fuse_arg)); + fuse_request_send(fc, req); + ret = req->out.h.error; + if (!ret && args->out.argvar) { + BUG_ON(args->out.numargs != 1); + ret = req->out.args[0].size; + } + fuse_put_request(fc, req); + + return ret; +} + static void fuse_request_send_nowait_locked(struct fuse_conn *fc, struct fuse_req *req) { diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index dbab798..f7ae3f58 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -145,22 +145,22 @@ static void fuse_invalidate_entry(struct dentry *entry) fuse_invalidate_entry_cache(entry); } -static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_req *req, +static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, u64 nodeid, struct qstr *name, struct fuse_entry_out *outarg) { memset(outarg, 0, sizeof(struct fuse_entry_out)); - req->in.h.opcode = FUSE_LOOKUP; - req->in.h.nodeid = nodeid; - req->in.numargs = 1; - req->in.args[0].size = name->len + 1; - req->in.args[0].value = name->name; - req->out.numargs = 1; + args->in.h.opcode = FUSE_LOOKUP; + args->in.h.nodeid = nodeid; + args->in.numargs = 1; + args->in.args[0].size = name->len + 1; + args->in.args[0].value = name->name; + args->out.numargs = 1; if (fc->minor < 9) - req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; else - req->out.args[0].size = sizeof(struct fuse_entry_out); - req->out.args[0].value = outarg; + args->out.args[0].size = sizeof(struct fuse_entry_out); + args->out.args[0].value = outarg; } u64 fuse_get_attr_version(struct fuse_conn *fc) @@ -200,9 +200,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) goto invalid; else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || (flags & LOOKUP_REVAL)) { - int err; struct fuse_entry_out outarg; - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_forget_link *forget; u64 attr_version; @@ -215,31 +214,23 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) goto out; fc = get_fuse_conn(inode); - req = fuse_get_req_nopages(fc); - ret = PTR_ERR(req); - if (IS_ERR(req)) - goto out; forget = fuse_alloc_forget(); - if (!forget) { - fuse_put_request(fc, req); - ret = -ENOMEM; + ret = -ENOMEM; + if (!forget) goto out; - } attr_version = fuse_get_attr_version(fc); parent = dget_parent(entry); - fuse_lookup_init(fc, req, get_node_id(parent->d_inode), + fuse_lookup_init(fc, &args, get_node_id(parent->d_inode), &entry->d_name, &outarg); - fuse_request_send(fc, req); + ret = fuse_simple_request(fc, &args); dput(parent); - err = req->out.h.error; - fuse_put_request(fc, req); /* Zero nodeid is same as -ENOENT */ - if (!err && !outarg.nodeid) - err = -ENOENT; - if (!err) { + if (!ret && !outarg.nodeid) + ret = -ENOENT; + if (!ret) { fi = get_fuse_inode(inode); if (outarg.nodeid != get_node_id(inode)) { fuse_queue_forget(fc, forget, outarg.nodeid, 1); @@ -250,7 +241,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) spin_unlock(&fc->lock); } kfree(forget); - if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) + if (ret == -ENOMEM) + goto out; + if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) goto invalid; fuse_change_attributes(inode, &outarg.attr, @@ -296,7 +289,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, struct fuse_entry_out *outarg, struct inode **inode) { struct fuse_conn *fc = get_fuse_conn_super(sb); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_forget_link *forget; u64 attr_version; int err; @@ -306,24 +299,16 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, if (name->len > FUSE_NAME_MAX) goto out; - req = fuse_get_req_nopages(fc); - err = PTR_ERR(req); - if (IS_ERR(req)) - goto out; forget = fuse_alloc_forget(); err = -ENOMEM; - if (!forget) { - fuse_put_request(fc, req); + if (!forget) goto out; - } attr_version = fuse_get_attr_version(fc); - fuse_lookup_init(fc, req, nodeid, name, outarg); - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + fuse_lookup_init(fc, &args, nodeid, name, outarg); + err = fuse_simple_request(fc, &args); /* Zero nodeid is same as -ENOENT, but with valid timeout */ if (err || !outarg->nodeid) goto out_put_forget; @@ -405,7 +390,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int err; struct inode *inode; struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_forget_link *forget; struct fuse_create_in inarg; struct fuse_open_out outopen; @@ -420,15 +405,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, if (!forget) goto out_err; - req = fuse_get_req_nopages(fc); - err = PTR_ERR(req); - if (IS_ERR(req)) - goto out_put_forget_req; - err = -ENOMEM; ff = fuse_file_alloc(fc); if (!ff) - goto out_put_request; + goto out_put_forget_req; if (!fc->dont_mask) mode &= ~current_umask(); @@ -439,24 +419,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, inarg.flags = flags; inarg.mode = mode; inarg.umask = current_umask(); - req->in.h.opcode = FUSE_CREATE; - req->in.h.nodeid = get_node_id(dir); - req->in.numargs = 2; - req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : + args.in.h.opcode = FUSE_CREATE; + args.in.h.nodeid = get_node_id(dir); + args.in.numargs = 2; + args.in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = entry->d_name.len + 1; - req->in.args[1].value = entry->d_name.name; - req->out.numargs = 2; + args.in.args[0].value = &inarg; + args.in.args[1].size = entry->d_name.len + 1; + args.in.args[1].value = entry->d_name.name; + args.out.numargs = 2; if (fc->minor < 9) - req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + args.out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; else - req->out.args[0].size = sizeof(outentry); - req->out.args[0].value = &outentry; - req->out.args[1].size = sizeof(outopen); - req->out.args[1].value = &outopen; - fuse_request_send(fc, req); - err = req->out.h.error; + args.out.args[0].size = sizeof(outentry); + args.out.args[0].value = &outentry; + args.out.args[1].size = sizeof(outopen); + args.out.args[1].value = &outopen; + err = fuse_simple_request(fc, &args); if (err) goto out_free_ff; @@ -464,7 +443,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) goto out_free_ff; - fuse_put_request(fc, req); ff->fh = outopen.fh; ff->nodeid = outentry.nodeid; ff->open_flags = outopen.open_flags; @@ -492,8 +470,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, out_free_ff: fuse_file_free(ff); -out_put_request: - fuse_put_request(fc, req); out_put_forget_req: kfree(forget); out_err: @@ -547,7 +523,7 @@ no_open: /* * Code shared between mknod, mkdir, symlink and link */ -static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, +static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, struct inode *dir, struct dentry *entry, umode_t mode) { @@ -557,22 +533,18 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct fuse_forget_link *forget; forget = fuse_alloc_forget(); - if (!forget) { - fuse_put_request(fc, req); + if (!forget) return -ENOMEM; - } memset(&outarg, 0, sizeof(outarg)); - req->in.h.nodeid = get_node_id(dir); - req->out.numargs = 1; + args->in.h.nodeid = get_node_id(dir); + args->out.numargs = 1; if (fc->minor < 9) - req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; + args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; else - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args->out.args[0].size = sizeof(outarg); + args->out.args[0].value = &outarg; + err = fuse_simple_request(fc, args); if (err) goto out_put_forget_req; @@ -609,9 +581,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, { struct fuse_mknod_in inarg; struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); if (!fc->dont_mask) mode &= ~current_umask(); @@ -620,14 +590,14 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, inarg.mode = mode; inarg.rdev = new_encode_dev(rdev); inarg.umask = current_umask(); - req->in.h.opcode = FUSE_MKNOD; - req->in.numargs = 2; - req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : + args.in.h.opcode = FUSE_MKNOD; + args.in.numargs = 2; + args.in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = entry->d_name.len + 1; - req->in.args[1].value = entry->d_name.name; - return create_new_entry(fc, req, dir, entry, mode); + args.in.args[0].value = &inarg; + args.in.args[1].size = entry->d_name.len + 1; + args.in.args[1].value = entry->d_name.name; + return create_new_entry(fc, &args, dir, entry, mode); } static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, @@ -640,9 +610,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) { struct fuse_mkdir_in inarg; struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); if (!fc->dont_mask) mode &= ~current_umask(); @@ -650,13 +618,13 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; inarg.umask = current_umask(); - req->in.h.opcode = FUSE_MKDIR; - req->in.numargs = 2; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = entry->d_name.len + 1; - req->in.args[1].value = entry->d_name.name; - return create_new_entry(fc, req, dir, entry, S_IFDIR); + args.in.h.opcode = FUSE_MKDIR; + args.in.numargs = 2; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.in.args[1].size = entry->d_name.len + 1; + args.in.args[1].value = entry->d_name.name; + return create_new_entry(fc, &args, dir, entry, S_IFDIR); } static int fuse_symlink(struct inode *dir, struct dentry *entry, @@ -664,17 +632,15 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, { struct fuse_conn *fc = get_fuse_conn(dir); unsigned len = strlen(link) + 1; - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); - req->in.h.opcode = FUSE_SYMLINK; - req->in.numargs = 2; - req->in.args[0].size = entry->d_name.len + 1; - req->in.args[0].value = entry->d_name.name; - req->in.args[1].size = len; - req->in.args[1].value = link; - return create_new_entry(fc, req, dir, entry, S_IFLNK); + args.in.h.opcode = FUSE_SYMLINK; + args.in.numargs = 2; + args.in.args[0].size = entry->d_name.len + 1; + args.in.args[0].value = entry->d_name.name; + args.in.args[1].size = len; + args.in.args[1].value = link; + return create_new_entry(fc, &args, dir, entry, S_IFLNK); } static inline void fuse_update_ctime(struct inode *inode) @@ -689,18 +655,14 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) { int err; struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - - req->in.h.opcode = FUSE_UNLINK; - req->in.h.nodeid = get_node_id(dir); - req->in.numargs = 1; - req->in.args[0].size = entry->d_name.len + 1; - req->in.args[0].value = entry->d_name.name; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + FUSE_ARGS(args); + + args.in.h.opcode = FUSE_UNLINK; + args.in.h.nodeid = get_node_id(dir); + args.in.numargs = 1; + args.in.args[0].size = entry->d_name.len + 1; + args.in.args[0].value = entry->d_name.name; + err = fuse_simple_request(fc, &args); if (!err) { struct inode *inode = entry->d_inode; struct fuse_inode *fi = get_fuse_inode(inode); @@ -729,18 +691,14 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) { int err; struct fuse_conn *fc = get_fuse_conn(dir); - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - - req->in.h.opcode = FUSE_RMDIR; - req->in.h.nodeid = get_node_id(dir); - req->in.numargs = 1; - req->in.args[0].size = entry->d_name.len + 1; - req->in.args[0].value = entry->d_name.name; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + FUSE_ARGS(args); + + args.in.h.opcode = FUSE_RMDIR; + args.in.h.nodeid = get_node_id(dir); + args.in.numargs = 1; + args.in.args[0].size = entry->d_name.len + 1; + args.in.args[0].value = entry->d_name.name; + err = fuse_simple_request(fc, &args); if (!err) { clear_nlink(entry->d_inode); fuse_invalidate_attr(dir); @@ -757,27 +715,21 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, int err; struct fuse_rename2_in inarg; struct fuse_conn *fc = get_fuse_conn(olddir); - struct fuse_req *req; - - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); memset(&inarg, 0, argsize); inarg.newdir = get_node_id(newdir); inarg.flags = flags; - req->in.h.opcode = opcode; - req->in.h.nodeid = get_node_id(olddir); - req->in.numargs = 3; - req->in.args[0].size = argsize; - req->in.args[0].value = &inarg; - req->in.args[1].size = oldent->d_name.len + 1; - req->in.args[1].value = oldent->d_name.name; - req->in.args[2].size = newent->d_name.len + 1; - req->in.args[2].value = newent->d_name.name; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = opcode; + args.in.h.nodeid = get_node_id(olddir); + args.in.numargs = 3; + args.in.args[0].size = argsize; + args.in.args[0].value = &inarg; + args.in.args[1].size = oldent->d_name.len + 1; + args.in.args[1].value = oldent->d_name.name; + args.in.args[2].size = newent->d_name.len + 1; + args.in.args[2].value = newent->d_name.name; + err = fuse_simple_request(fc, &args); if (!err) { /* ctime changes */ fuse_invalidate_attr(oldent->d_inode); @@ -849,19 +801,17 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, struct fuse_link_in inarg; struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); memset(&inarg, 0, sizeof(inarg)); inarg.oldnodeid = get_node_id(inode); - req->in.h.opcode = FUSE_LINK; - req->in.numargs = 2; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = newent->d_name.len + 1; - req->in.args[1].value = newent->d_name.name; - err = create_new_entry(fc, req, newdir, newent, inode->i_mode); + args.in.h.opcode = FUSE_LINK; + args.in.numargs = 2; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.in.args[1].size = newent->d_name.len + 1; + args.in.args[1].value = newent->d_name.name; + err = create_new_entry(fc, &args, newdir, newent, inode->i_mode); /* Contrary to "normal" filesystems it can happen that link makes two "logical" inodes point to the same "physical" inode. We invalidate the attributes of the old one, so it @@ -929,13 +879,9 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, struct fuse_getattr_in inarg; struct fuse_attr_out outarg; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); u64 attr_version; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - attr_version = fuse_get_attr_version(fc); memset(&inarg, 0, sizeof(inarg)); @@ -947,20 +893,18 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, inarg.getattr_flags |= FUSE_GETATTR_FH; inarg.fh = ff->fh; } - req->in.h.opcode = FUSE_GETATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->out.numargs = 1; + args.in.h.opcode = FUSE_GETATTR; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; if (fc->minor < 9) - req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; + args.out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; else - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); if (!err) { if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { make_bad_inode(inode); @@ -1102,7 +1046,7 @@ int fuse_allow_current_process(struct fuse_conn *fc) static int fuse_access(struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_access_in inarg; int err; @@ -1111,20 +1055,14 @@ static int fuse_access(struct inode *inode, int mask) if (fc->no_access) return 0; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - memset(&inarg, 0, sizeof(inarg)); inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); - req->in.h.opcode = FUSE_ACCESS; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = FUSE_ACCESS; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_access = 1; err = 0; @@ -1445,31 +1383,27 @@ static char *read_link(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_req_nopages(fc); + FUSE_ARGS(args); char *link; - - if (IS_ERR(req)) - return ERR_CAST(req); + ssize_t ret; link = (char *) __get_free_page(GFP_KERNEL); - if (!link) { - link = ERR_PTR(-ENOMEM); - goto out; - } - req->in.h.opcode = FUSE_READLINK; - req->in.h.nodeid = get_node_id(inode); - req->out.argvar = 1; - req->out.numargs = 1; - req->out.args[0].size = PAGE_SIZE - 1; - req->out.args[0].value = link; - fuse_request_send(fc, req); - if (req->out.h.error) { + if (!link) + return ERR_PTR(-ENOMEM); + + args.in.h.opcode = FUSE_READLINK; + args.in.h.nodeid = get_node_id(inode); + args.out.argvar = 1; + args.out.numargs = 1; + args.out.args[0].size = PAGE_SIZE - 1; + args.out.args[0].value = link; + ret = fuse_simple_request(fc, &args); + if (ret < 0) { free_page((unsigned long) link); - link = ERR_PTR(req->out.h.error); - } else - link[req->out.args[0].size] = '\0'; - out: - fuse_put_request(fc, req); + link = ERR_PTR(ret); + } else { + link[ret] = '\0'; + } fuse_invalidate_atime(inode); return link; } @@ -1629,22 +1563,22 @@ void fuse_release_nowrite(struct inode *inode) spin_unlock(&fc->lock); } -static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req, +static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args, struct inode *inode, struct fuse_setattr_in *inarg_p, struct fuse_attr_out *outarg_p) { - req->in.h.opcode = FUSE_SETATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(*inarg_p); - req->in.args[0].value = inarg_p; - req->out.numargs = 1; + args->in.h.opcode = FUSE_SETATTR; + args->in.h.nodeid = get_node_id(inode); + args->in.numargs = 1; + args->in.args[0].size = sizeof(*inarg_p); + args->in.args[0].value = inarg_p; + args->out.numargs = 1; if (fc->minor < 9) - req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; + args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; else - req->out.args[0].size = sizeof(*outarg_p); - req->out.args[0].value = outarg_p; + args->out.args[0].size = sizeof(*outarg_p); + args->out.args[0].value = outarg_p; } /* @@ -1653,14 +1587,9 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req, int fuse_flush_times(struct inode *inode, struct fuse_file *ff) { struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_setattr_in inarg; struct fuse_attr_out outarg; - int err; - - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); memset(&inarg, 0, sizeof(inarg)); memset(&outarg, 0, sizeof(outarg)); @@ -1677,12 +1606,9 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff) inarg.valid |= FATTR_FH; inarg.fh = ff->fh; } - fuse_setattr_fill(fc, req, inode, &inarg, &outarg); - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); - return err; + return fuse_simple_request(fc, &args); } /* @@ -1698,7 +1624,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_setattr_in inarg; struct fuse_attr_out outarg; bool is_truncate = false; @@ -1723,10 +1649,6 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, if (attr->ia_valid & ATTR_SIZE) is_truncate = true; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - if (is_truncate) { fuse_set_nowrite(inode); set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); @@ -1747,10 +1669,8 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, inarg.valid |= FATTR_LOCKOWNER; inarg.lock_owner = fuse_lock_owner_id(fc, current->files); } - fuse_setattr_fill(fc, req, inode, &inarg, &outarg); - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); + err = fuse_simple_request(fc, &args); if (err) { if (err == -EINTR) fuse_invalidate_attr(inode); @@ -1837,32 +1757,26 @@ static int fuse_setxattr(struct dentry *entry, const char *name, { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_setxattr_in inarg; int err; if (fc->no_setxattr) return -EOPNOTSUPP; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - memset(&inarg, 0, sizeof(inarg)); inarg.size = size; inarg.flags = flags; - req->in.h.opcode = FUSE_SETXATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 3; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = strlen(name) + 1; - req->in.args[1].value = name; - req->in.args[2].size = size; - req->in.args[2].value = value; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = FUSE_SETXATTR; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 3; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.in.args[1].size = strlen(name) + 1; + args.in.args[1].value = name; + args.in.args[2].size = size; + args.in.args[2].value = value; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_setxattr = 1; err = -EOPNOTSUPP; @@ -1879,7 +1793,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; ssize_t ret; @@ -1887,40 +1801,32 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, if (fc->no_getxattr) return -EOPNOTSUPP; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - memset(&inarg, 0, sizeof(inarg)); inarg.size = size; - req->in.h.opcode = FUSE_GETXATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 2; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->in.args[1].size = strlen(name) + 1; - req->in.args[1].value = name; + args.in.h.opcode = FUSE_GETXATTR; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 2; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.in.args[1].size = strlen(name) + 1; + args.in.args[1].value = name; /* This is really two different operations rolled into one */ - req->out.numargs = 1; + args.out.numargs = 1; if (size) { - req->out.argvar = 1; - req->out.args[0].size = size; - req->out.args[0].value = value; + args.out.argvar = 1; + args.out.args[0].size = size; + args.out.args[0].value = value; } else { - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; } - fuse_request_send(fc, req); - ret = req->out.h.error; - if (!ret) - ret = size ? req->out.args[0].size : outarg.size; - else { - if (ret == -ENOSYS) { - fc->no_getxattr = 1; - ret = -EOPNOTSUPP; - } + ret = fuse_simple_request(fc, &args); + if (!ret && !size) + ret = outarg.size; + if (ret == -ENOSYS) { + fc->no_getxattr = 1; + ret = -EOPNOTSUPP; } - fuse_put_request(fc, req); return ret; } @@ -1928,7 +1834,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; ssize_t ret; @@ -1939,38 +1845,30 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) if (fc->no_listxattr) return -EOPNOTSUPP; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - memset(&inarg, 0, sizeof(inarg)); inarg.size = size; - req->in.h.opcode = FUSE_LISTXATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; + args.in.h.opcode = FUSE_LISTXATTR; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; /* This is really two different operations rolled into one */ - req->out.numargs = 1; + args.out.numargs = 1; if (size) { - req->out.argvar = 1; - req->out.args[0].size = size; - req->out.args[0].value = list; + args.out.argvar = 1; + args.out.args[0].size = size; + args.out.args[0].value = list; } else { - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; } - fuse_request_send(fc, req); - ret = req->out.h.error; - if (!ret) - ret = size ? req->out.args[0].size : outarg.size; - else { - if (ret == -ENOSYS) { - fc->no_listxattr = 1; - ret = -EOPNOTSUPP; - } + ret = fuse_simple_request(fc, &args); + if (!ret && !size) + ret = outarg.size; + if (ret == -ENOSYS) { + fc->no_listxattr = 1; + ret = -EOPNOTSUPP; } - fuse_put_request(fc, req); return ret; } @@ -1978,24 +1876,18 @@ static int fuse_removexattr(struct dentry *entry, const char *name) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); int err; if (fc->no_removexattr) return -EOPNOTSUPP; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - - req->in.h.opcode = FUSE_REMOVEXATTR; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = strlen(name) + 1; - req->in.args[0].value = name; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = FUSE_REMOVEXATTR; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = strlen(name) + 1; + args.in.args[0].value = name; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_removexattr = 1; err = -EOPNOTSUPP; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2d4ae68..e8729ac 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -24,30 +24,22 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, int opcode, struct fuse_open_out *outargp) { struct fuse_open_in inarg; - struct fuse_req *req; - int err; - - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + FUSE_ARGS(args); memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); if (!fc->atomic_o_trunc) inarg.flags &= ~O_TRUNC; - req->in.h.opcode = opcode; - req->in.h.nodeid = nodeid; - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->out.numargs = 1; - req->out.args[0].size = sizeof(*outargp); - req->out.args[0].value = outargp; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = opcode; + args.in.h.nodeid = nodeid; + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; + args.out.args[0].size = sizeof(*outargp); + args.out.args[0].value = outargp; - return err; + return fuse_simple_request(fc, &args); } struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) @@ -451,7 +443,7 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, struct inode *inode = file->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_fsync_in inarg; int err; @@ -477,23 +469,15 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) goto out; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out; - } - memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; inarg.fsync_flags = datasync ? 1 : 0; - req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { if (isdir) fc->no_fsyncdir = 1; @@ -2127,49 +2111,44 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, return 0; } -static void fuse_lk_fill(struct fuse_req *req, struct file *file, +static void fuse_lk_fill(struct fuse_args *args, struct file *file, const struct file_lock *fl, int opcode, pid_t pid, - int flock) + int flock, struct fuse_lk_in *inarg) { struct inode *inode = file_inode(file); struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; - struct fuse_lk_in *arg = &req->misc.lk_in; - - arg->fh = ff->fh; - arg->owner = fuse_lock_owner_id(fc, fl->fl_owner); - arg->lk.start = fl->fl_start; - arg->lk.end = fl->fl_end; - arg->lk.type = fl->fl_type; - arg->lk.pid = pid; + + memset(inarg, 0, sizeof(*inarg)); + inarg->fh = ff->fh; + inarg->owner = fuse_lock_owner_id(fc, fl->fl_owner); + inarg->lk.start = fl->fl_start; + inarg->lk.end = fl->fl_end; + inarg->lk.type = fl->fl_type; + inarg->lk.pid = pid; if (flock) - arg->lk_flags |= FUSE_LK_FLOCK; - req->in.h.opcode = opcode; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(*arg); - req->in.args[0].value = arg; + inarg->lk_flags |= FUSE_LK_FLOCK; + args->in.h.opcode = opcode; + args->in.h.nodeid = get_node_id(inode); + args->in.numargs = 1; + args->in.args[0].size = sizeof(*inarg); + args->in.args[0].value = inarg; } static int fuse_getlk(struct file *file, struct file_lock *fl) { struct inode *inode = file_inode(file); struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); + struct fuse_lk_in inarg; struct fuse_lk_out outarg; int err; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - - fuse_lk_fill(req, file, fl, FUSE_GETLK, 0, 0); - req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + fuse_lk_fill(&args, file, fl, FUSE_GETLK, 0, 0, &inarg); + args.out.numargs = 1; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); if (!err) err = convert_fuse_file_lock(&outarg.lk, fl); @@ -2180,7 +2159,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) { struct inode *inode = file_inode(file); struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); + struct fuse_lk_in inarg; int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0; int err; @@ -2194,17 +2174,13 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) if (fl->fl_flags & FL_CLOSE) return 0; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); + fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg); + err = fuse_simple_request(fc, &args); - fuse_lk_fill(req, file, fl, opcode, pid, flock); - fuse_request_send(fc, req); - err = req->out.h.error; /* locking is restartable */ if (err == -EINTR) err = -ERESTARTSYS; - fuse_put_request(fc, req); + return err; } @@ -2254,7 +2230,7 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block) { struct inode *inode = mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_bmap_in inarg; struct fuse_bmap_out outarg; int err; @@ -2262,24 +2238,18 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block) if (!inode->i_sb->s_bdev || fc->no_bmap) return 0; - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return 0; - memset(&inarg, 0, sizeof(inarg)); inarg.block = block; inarg.blocksize = inode->i_sb->s_blocksize; - req->in.h.opcode = FUSE_BMAP; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = FUSE_BMAP; + args.in.h.nodeid = get_node_id(inode); + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) fc->no_bmap = 1; @@ -2747,7 +2717,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait) struct fuse_conn *fc = ff->fc; struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; struct fuse_poll_out outarg; - struct fuse_req *req; + FUSE_ARGS(args); int err; if (fc->no_poll) @@ -2765,21 +2735,15 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait) fuse_register_polled_file(fc, ff); } - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return POLLERR; - - req->in.h.opcode = FUSE_POLL; - req->in.h.nodeid = ff->nodeid; - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + args.in.h.opcode = FUSE_POLL; + args.in.h.nodeid = ff->nodeid; + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); if (!err) return outarg.revents; @@ -2923,7 +2887,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, struct inode *inode = file->f_inode; struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = ff->fc; - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_fallocate_in inarg = { .fh = ff->fh, .offset = offset, @@ -2956,25 +2920,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, if (!(mode & FALLOC_FL_KEEP_SIZE)) set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out; - } - - req->in.h.opcode = FUSE_FALLOCATE; - req->in.h.nodeid = ff->nodeid; - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - fuse_request_send(fc, req); - err = req->out.h.error; + args.in.h.opcode = FUSE_FALLOCATE; + args.in.h.nodeid = ff->nodeid; + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + err = fuse_simple_request(fc, &args); if (err == -ENOSYS) { fc->no_fallocate = 1; err = -EOPNOTSUPP; } - fuse_put_request(fc, req); - if (err) goto out; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 351c098..e0fc672 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -222,6 +222,25 @@ struct fuse_page_desc { unsigned int offset; }; +struct fuse_args { + struct { + struct { + uint32_t opcode; + uint64_t nodeid; + } h; + unsigned numargs; + struct fuse_in_arg args[3]; + + } in; + struct { + unsigned argvar:1; + unsigned numargs; + struct fuse_arg args[2]; + } out; +}; + +#define FUSE_ARGS(args) struct fuse_args args = {} + /** The request state */ enum fuse_req_state { FUSE_REQ_INIT = 0, @@ -321,7 +340,6 @@ struct fuse_req { struct fuse_req *next; } write; struct fuse_notify_retrieve_in retrieve_in; - struct fuse_lk_in lk_in; } misc; /** page vector */ @@ -751,15 +769,6 @@ struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc, void __fuse_get_request(struct fuse_req *req); /** - * Get a request, may fail with -ENOMEM, - * useful for callers who doesn't use req->pages[] - */ -static inline struct fuse_req *fuse_get_req_nopages(struct fuse_conn *fc) -{ - return fuse_get_req(fc, 0); -} - -/** * Gets a requests for a file operation, always succeeds */ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, @@ -777,6 +786,11 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); 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); + +/** * Send a request in the background */ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 616a791..6749109 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -410,7 +410,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct fuse_conn *fc = get_fuse_conn_super(sb); - struct fuse_req *req; + FUSE_ARGS(args); struct fuse_statfs_out outarg; int err; @@ -419,23 +419,17 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } - req = fuse_get_req_nopages(fc); - if (IS_ERR(req)) - return PTR_ERR(req); - memset(&outarg, 0, sizeof(outarg)); - req->in.numargs = 0; - req->in.h.opcode = FUSE_STATFS; - req->in.h.nodeid = get_node_id(dentry->d_inode); - req->out.numargs = 1; - req->out.args[0].size = + args.in.numargs = 0; + args.in.h.opcode = FUSE_STATFS; + args.in.h.nodeid = get_node_id(dentry->d_inode); + args.out.numargs = 1; + args.out.args[0].size = fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); - req->out.args[0].value = &outarg; - fuse_request_send(fc, req); - err = req->out.h.error; + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); if (!err) convert_fuse_statfs(buf, &outarg.st); - fuse_put_request(fc, req); return err; } -- cgit v0.10.2 From 1c68271cf1bfe7f3664b6dbf4ffd5fe11130be5c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 12 Dec 2014 10:04:51 +0100 Subject: fuse: use file_inode() in fuse_file_fallocate() Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e8729ac..945bfba 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2884,7 +2884,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, loff_t length) { struct fuse_file *ff = file->private_data; - struct inode *inode = file->f_inode; + struct inode *inode = file_inode(file); struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = ff->fc; FUSE_ARGS(args); -- cgit v0.10.2