Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse update from Miklos Szeredi:
 "The first part makes sure we don't hold up umount with pending async
  requests.  In addition to being a cleanup, this is a small behavioral
  change (for the better) and unlikely to break anything.

  The second part prepares for a cleanup of the fuse device I/O code by
  adding a helper for simple request submission, with some savings in
  line numbers already realized"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: use file_inode() in fuse_file_fallocate()
  fuse: introduce fuse_simple_request() helper
  fuse: reduce max out args
  fuse: hold inode instead of path after release
  fuse: flush requests on umount
  fuse: don't wake up reserved req in fuse_conn_kill()
This commit is contained in:
Linus Torvalds 2014-12-17 09:41:32 -08:00
commit c103b21c20
6 changed files with 356 additions and 521 deletions

View File

@ -415,7 +415,7 @@ err_unlock:
err_region: err_region:
unregister_chrdev_region(devt, 1); unregister_chrdev_region(devt, 1);
err: err:
fuse_conn_kill(fc); fuse_abort_conn(fc);
goto out; goto out;
} }

View File

@ -511,6 +511,35 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
} }
EXPORT_SYMBOL_GPL(fuse_request_send); 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, static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
struct fuse_req *req) struct fuse_req *req)
{ {

View File

@ -145,22 +145,22 @@ static void fuse_invalidate_entry(struct dentry *entry)
fuse_invalidate_entry_cache(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, u64 nodeid, struct qstr *name,
struct fuse_entry_out *outarg) struct fuse_entry_out *outarg)
{ {
memset(outarg, 0, sizeof(struct fuse_entry_out)); memset(outarg, 0, sizeof(struct fuse_entry_out));
req->in.h.opcode = FUSE_LOOKUP; args->in.h.opcode = FUSE_LOOKUP;
req->in.h.nodeid = nodeid; args->in.h.nodeid = nodeid;
req->in.numargs = 1; args->in.numargs = 1;
req->in.args[0].size = name->len + 1; args->in.args[0].size = name->len + 1;
req->in.args[0].value = name->name; args->in.args[0].value = name->name;
req->out.numargs = 1; args->out.numargs = 1;
if (fc->minor < 9) 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 else
req->out.args[0].size = sizeof(struct fuse_entry_out); args->out.args[0].size = sizeof(struct fuse_entry_out);
req->out.args[0].value = outarg; args->out.args[0].value = outarg;
} }
u64 fuse_get_attr_version(struct fuse_conn *fc) 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; goto invalid;
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
(flags & LOOKUP_REVAL)) { (flags & LOOKUP_REVAL)) {
int err;
struct fuse_entry_out outarg; struct fuse_entry_out outarg;
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_forget_link *forget; struct fuse_forget_link *forget;
u64 attr_version; u64 attr_version;
@ -215,31 +214,23 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
goto out; goto out;
fc = get_fuse_conn(inode); 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(); forget = fuse_alloc_forget();
if (!forget) { ret = -ENOMEM;
fuse_put_request(fc, req); if (!forget)
ret = -ENOMEM;
goto out; goto out;
}
attr_version = fuse_get_attr_version(fc); attr_version = fuse_get_attr_version(fc);
parent = dget_parent(entry); 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); &entry->d_name, &outarg);
fuse_request_send(fc, req); ret = fuse_simple_request(fc, &args);
dput(parent); dput(parent);
err = req->out.h.error;
fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT */ /* Zero nodeid is same as -ENOENT */
if (!err && !outarg.nodeid) if (!ret && !outarg.nodeid)
err = -ENOENT; ret = -ENOENT;
if (!err) { if (!ret) {
fi = get_fuse_inode(inode); fi = get_fuse_inode(inode);
if (outarg.nodeid != get_node_id(inode)) { if (outarg.nodeid != get_node_id(inode)) {
fuse_queue_forget(fc, forget, outarg.nodeid, 1); 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); spin_unlock(&fc->lock);
} }
kfree(forget); 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; goto invalid;
fuse_change_attributes(inode, &outarg.attr, 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_entry_out *outarg, struct inode **inode)
{ {
struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_conn *fc = get_fuse_conn_super(sb);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_forget_link *forget; struct fuse_forget_link *forget;
u64 attr_version; u64 attr_version;
int err; 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) if (name->len > FUSE_NAME_MAX)
goto out; goto out;
req = fuse_get_req_nopages(fc);
err = PTR_ERR(req);
if (IS_ERR(req))
goto out;
forget = fuse_alloc_forget(); forget = fuse_alloc_forget();
err = -ENOMEM; err = -ENOMEM;
if (!forget) { if (!forget)
fuse_put_request(fc, req);
goto out; goto out;
}
attr_version = fuse_get_attr_version(fc); attr_version = fuse_get_attr_version(fc);
fuse_lookup_init(fc, req, nodeid, name, outarg); fuse_lookup_init(fc, &args, nodeid, name, outarg);
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT, but with valid timeout */ /* Zero nodeid is same as -ENOENT, but with valid timeout */
if (err || !outarg->nodeid) if (err || !outarg->nodeid)
goto out_put_forget; goto out_put_forget;
@ -405,7 +390,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
int err; int err;
struct inode *inode; struct inode *inode;
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_forget_link *forget; struct fuse_forget_link *forget;
struct fuse_create_in inarg; struct fuse_create_in inarg;
struct fuse_open_out outopen; struct fuse_open_out outopen;
@ -420,15 +405,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
if (!forget) if (!forget)
goto out_err; goto out_err;
req = fuse_get_req_nopages(fc);
err = PTR_ERR(req);
if (IS_ERR(req))
goto out_put_forget_req;
err = -ENOMEM; err = -ENOMEM;
ff = fuse_file_alloc(fc); ff = fuse_file_alloc(fc);
if (!ff) if (!ff)
goto out_put_request; goto out_put_forget_req;
if (!fc->dont_mask) if (!fc->dont_mask)
mode &= ~current_umask(); mode &= ~current_umask();
@ -439,24 +419,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
inarg.flags = flags; inarg.flags = flags;
inarg.mode = mode; inarg.mode = mode;
inarg.umask = current_umask(); inarg.umask = current_umask();
req->in.h.opcode = FUSE_CREATE; args.in.h.opcode = FUSE_CREATE;
req->in.h.nodeid = get_node_id(dir); args.in.h.nodeid = get_node_id(dir);
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : args.in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
sizeof(inarg); sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = entry->d_name.len + 1; args.in.args[1].size = entry->d_name.len + 1;
req->in.args[1].value = entry->d_name.name; args.in.args[1].value = entry->d_name.name;
req->out.numargs = 2; args.out.numargs = 2;
if (fc->minor < 9) 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 else
req->out.args[0].size = sizeof(outentry); args.out.args[0].size = sizeof(outentry);
req->out.args[0].value = &outentry; args.out.args[0].value = &outentry;
req->out.args[1].size = sizeof(outopen); args.out.args[1].size = sizeof(outopen);
req->out.args[1].value = &outopen; args.out.args[1].value = &outopen;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
if (err) if (err)
goto out_free_ff; 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)) if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
goto out_free_ff; goto out_free_ff;
fuse_put_request(fc, req);
ff->fh = outopen.fh; ff->fh = outopen.fh;
ff->nodeid = outentry.nodeid; ff->nodeid = outentry.nodeid;
ff->open_flags = outopen.open_flags; ff->open_flags = outopen.open_flags;
@ -492,8 +470,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
out_free_ff: out_free_ff:
fuse_file_free(ff); fuse_file_free(ff);
out_put_request:
fuse_put_request(fc, req);
out_put_forget_req: out_put_forget_req:
kfree(forget); kfree(forget);
out_err: out_err:
@ -547,7 +523,7 @@ no_open:
/* /*
* Code shared between mknod, mkdir, symlink and link * 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, struct inode *dir, struct dentry *entry,
umode_t mode) 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; struct fuse_forget_link *forget;
forget = fuse_alloc_forget(); forget = fuse_alloc_forget();
if (!forget) { if (!forget)
fuse_put_request(fc, req);
return -ENOMEM; return -ENOMEM;
}
memset(&outarg, 0, sizeof(outarg)); memset(&outarg, 0, sizeof(outarg));
req->in.h.nodeid = get_node_id(dir); args->in.h.nodeid = get_node_id(dir);
req->out.numargs = 1; args->out.numargs = 1;
if (fc->minor < 9) 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 else
req->out.args[0].size = sizeof(outarg); args->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; args->out.args[0].value = &outarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err) if (err)
goto out_put_forget_req; 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_mknod_in inarg;
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
if (!fc->dont_mask) if (!fc->dont_mask)
mode &= ~current_umask(); mode &= ~current_umask();
@ -620,14 +590,14 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
inarg.mode = mode; inarg.mode = mode;
inarg.rdev = new_encode_dev(rdev); inarg.rdev = new_encode_dev(rdev);
inarg.umask = current_umask(); inarg.umask = current_umask();
req->in.h.opcode = FUSE_MKNOD; args.in.h.opcode = FUSE_MKNOD;
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : args.in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
sizeof(inarg); sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = entry->d_name.len + 1; args.in.args[1].size = entry->d_name.len + 1;
req->in.args[1].value = entry->d_name.name; args.in.args[1].value = entry->d_name.name;
return create_new_entry(fc, req, dir, entry, mode); return create_new_entry(fc, &args, dir, entry, mode);
} }
static int fuse_create(struct inode *dir, struct dentry *entry, umode_t 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_mkdir_in inarg;
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
if (!fc->dont_mask) if (!fc->dont_mask)
mode &= ~current_umask(); 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)); memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode; inarg.mode = mode;
inarg.umask = current_umask(); inarg.umask = current_umask();
req->in.h.opcode = FUSE_MKDIR; args.in.h.opcode = FUSE_MKDIR;
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = entry->d_name.len + 1; args.in.args[1].size = entry->d_name.len + 1;
req->in.args[1].value = entry->d_name.name; args.in.args[1].value = entry->d_name.name;
return create_new_entry(fc, req, dir, entry, S_IFDIR); return create_new_entry(fc, &args, dir, entry, S_IFDIR);
} }
static int fuse_symlink(struct inode *dir, struct dentry *entry, 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); struct fuse_conn *fc = get_fuse_conn(dir);
unsigned len = strlen(link) + 1; unsigned len = strlen(link) + 1;
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
req->in.h.opcode = FUSE_SYMLINK; args.in.h.opcode = FUSE_SYMLINK;
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = entry->d_name.len + 1; args.in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name; args.in.args[0].value = entry->d_name.name;
req->in.args[1].size = len; args.in.args[1].size = len;
req->in.args[1].value = link; args.in.args[1].value = link;
return create_new_entry(fc, req, dir, entry, S_IFLNK); return create_new_entry(fc, &args, dir, entry, S_IFLNK);
} }
static inline void fuse_update_ctime(struct inode *inode) 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; int err;
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
req->in.h.opcode = FUSE_UNLINK; args.in.h.opcode = FUSE_UNLINK;
req->in.h.nodeid = get_node_id(dir); args.in.h.nodeid = get_node_id(dir);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1; args.in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name; args.in.args[0].value = entry->d_name.name;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (!err) { if (!err) {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
struct fuse_inode *fi = get_fuse_inode(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; int err;
struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
req->in.h.opcode = FUSE_RMDIR; args.in.h.opcode = FUSE_RMDIR;
req->in.h.nodeid = get_node_id(dir); args.in.h.nodeid = get_node_id(dir);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1; args.in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name; args.in.args[0].value = entry->d_name.name;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (!err) { if (!err) {
clear_nlink(entry->d_inode); clear_nlink(entry->d_inode);
fuse_invalidate_attr(dir); fuse_invalidate_attr(dir);
@ -757,27 +715,21 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
int err; int err;
struct fuse_rename2_in inarg; struct fuse_rename2_in inarg;
struct fuse_conn *fc = get_fuse_conn(olddir); struct fuse_conn *fc = get_fuse_conn(olddir);
struct fuse_req *req; FUSE_ARGS(args);
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, argsize); memset(&inarg, 0, argsize);
inarg.newdir = get_node_id(newdir); inarg.newdir = get_node_id(newdir);
inarg.flags = flags; inarg.flags = flags;
req->in.h.opcode = opcode; args.in.h.opcode = opcode;
req->in.h.nodeid = get_node_id(olddir); args.in.h.nodeid = get_node_id(olddir);
req->in.numargs = 3; args.in.numargs = 3;
req->in.args[0].size = argsize; args.in.args[0].size = argsize;
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = oldent->d_name.len + 1; args.in.args[1].size = oldent->d_name.len + 1;
req->in.args[1].value = oldent->d_name.name; args.in.args[1].value = oldent->d_name.name;
req->in.args[2].size = newent->d_name.len + 1; args.in.args[2].size = newent->d_name.len + 1;
req->in.args[2].value = newent->d_name.name; args.in.args[2].value = newent->d_name.name;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (!err) { if (!err) {
/* ctime changes */ /* ctime changes */
fuse_invalidate_attr(oldent->d_inode); 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 fuse_link_in inarg;
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.oldnodeid = get_node_id(inode); inarg.oldnodeid = get_node_id(inode);
req->in.h.opcode = FUSE_LINK; args.in.h.opcode = FUSE_LINK;
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = newent->d_name.len + 1; args.in.args[1].size = newent->d_name.len + 1;
req->in.args[1].value = newent->d_name.name; args.in.args[1].value = newent->d_name.name;
err = create_new_entry(fc, req, newdir, newent, inode->i_mode); err = create_new_entry(fc, &args, newdir, newent, inode->i_mode);
/* Contrary to "normal" filesystems it can happen that link /* Contrary to "normal" filesystems it can happen that link
makes two "logical" inodes point to the same "physical" makes two "logical" inodes point to the same "physical"
inode. We invalidate the attributes of the old one, so it 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_getattr_in inarg;
struct fuse_attr_out outarg; struct fuse_attr_out outarg;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
u64 attr_version; u64 attr_version;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
attr_version = fuse_get_attr_version(fc); attr_version = fuse_get_attr_version(fc);
memset(&inarg, 0, sizeof(inarg)); 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.getattr_flags |= FUSE_GETATTR_FH;
inarg.fh = ff->fh; inarg.fh = ff->fh;
} }
req->in.h.opcode = FUSE_GETATTR; args.in.h.opcode = FUSE_GETATTR;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->out.numargs = 1; args.out.numargs = 1;
if (fc->minor < 9) 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 else
req->out.args[0].size = sizeof(outarg); args.out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; args.out.args[0].value = &outarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (!err) { if (!err) {
if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode); 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) static int fuse_access(struct inode *inode, int mask)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_access_in inarg; struct fuse_access_in inarg;
int err; int err;
@ -1111,20 +1055,14 @@ static int fuse_access(struct inode *inode, int mask)
if (fc->no_access) if (fc->no_access)
return 0; return 0;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC);
req->in.h.opcode = FUSE_ACCESS; args.in.h.opcode = FUSE_ACCESS;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_access = 1; fc->no_access = 1;
err = 0; err = 0;
@ -1445,31 +1383,27 @@ static char *read_link(struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_req_nopages(fc); FUSE_ARGS(args);
char *link; char *link;
ssize_t ret;
if (IS_ERR(req))
return ERR_CAST(req);
link = (char *) __get_free_page(GFP_KERNEL); link = (char *) __get_free_page(GFP_KERNEL);
if (!link) { if (!link)
link = ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
goto out;
} args.in.h.opcode = FUSE_READLINK;
req->in.h.opcode = FUSE_READLINK; args.in.h.nodeid = get_node_id(inode);
req->in.h.nodeid = get_node_id(inode); args.out.argvar = 1;
req->out.argvar = 1; args.out.numargs = 1;
req->out.numargs = 1; args.out.args[0].size = PAGE_SIZE - 1;
req->out.args[0].size = PAGE_SIZE - 1; args.out.args[0].value = link;
req->out.args[0].value = link; ret = fuse_simple_request(fc, &args);
fuse_request_send(fc, req); if (ret < 0) {
if (req->out.h.error) {
free_page((unsigned long) link); free_page((unsigned long) link);
link = ERR_PTR(req->out.h.error); link = ERR_PTR(ret);
} else } else {
link[req->out.args[0].size] = '\0'; link[ret] = '\0';
out: }
fuse_put_request(fc, req);
fuse_invalidate_atime(inode); fuse_invalidate_atime(inode);
return link; return link;
} }
@ -1629,22 +1563,22 @@ void fuse_release_nowrite(struct inode *inode)
spin_unlock(&fc->lock); 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 inode *inode,
struct fuse_setattr_in *inarg_p, struct fuse_setattr_in *inarg_p,
struct fuse_attr_out *outarg_p) struct fuse_attr_out *outarg_p)
{ {
req->in.h.opcode = FUSE_SETATTR; args->in.h.opcode = FUSE_SETATTR;
req->in.h.nodeid = get_node_id(inode); args->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args->in.numargs = 1;
req->in.args[0].size = sizeof(*inarg_p); args->in.args[0].size = sizeof(*inarg_p);
req->in.args[0].value = inarg_p; args->in.args[0].value = inarg_p;
req->out.numargs = 1; args->out.numargs = 1;
if (fc->minor < 9) 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 else
req->out.args[0].size = sizeof(*outarg_p); args->out.args[0].size = sizeof(*outarg_p);
req->out.args[0].value = 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) int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_setattr_in inarg; struct fuse_setattr_in inarg;
struct fuse_attr_out outarg; 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(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg)); 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.valid |= FATTR_FH;
inarg.fh = ff->fh; inarg.fh = ff->fh;
} }
fuse_setattr_fill(fc, req, inode, &inarg, &outarg); fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);
fuse_request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
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_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_setattr_in inarg; struct fuse_setattr_in inarg;
struct fuse_attr_out outarg; struct fuse_attr_out outarg;
bool is_truncate = false; bool is_truncate = false;
@ -1723,10 +1649,6 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
if (attr->ia_valid & ATTR_SIZE) if (attr->ia_valid & ATTR_SIZE)
is_truncate = true; is_truncate = true;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
if (is_truncate) { if (is_truncate) {
fuse_set_nowrite(inode); fuse_set_nowrite(inode);
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); 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.valid |= FATTR_LOCKOWNER;
inarg.lock_owner = fuse_lock_owner_id(fc, current->files); inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
} }
fuse_setattr_fill(fc, req, inode, &inarg, &outarg); fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err) { if (err) {
if (err == -EINTR) if (err == -EINTR)
fuse_invalidate_attr(inode); 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 inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_setxattr_in inarg; struct fuse_setxattr_in inarg;
int err; int err;
if (fc->no_setxattr) if (fc->no_setxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.size = size; inarg.size = size;
inarg.flags = flags; inarg.flags = flags;
req->in.h.opcode = FUSE_SETXATTR; args.in.h.opcode = FUSE_SETXATTR;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 3; args.in.numargs = 3;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = strlen(name) + 1; args.in.args[1].size = strlen(name) + 1;
req->in.args[1].value = name; args.in.args[1].value = name;
req->in.args[2].size = size; args.in.args[2].size = size;
req->in.args[2].value = value; args.in.args[2].value = value;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_setxattr = 1; fc->no_setxattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
@ -1879,7 +1793,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
{ {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_getxattr_in inarg; struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg; struct fuse_getxattr_out outarg;
ssize_t ret; ssize_t ret;
@ -1887,40 +1801,32 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
if (fc->no_getxattr) if (fc->no_getxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.size = size; inarg.size = size;
req->in.h.opcode = FUSE_GETXATTR; args.in.h.opcode = FUSE_GETXATTR;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 2; args.in.numargs = 2;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->in.args[1].size = strlen(name) + 1; args.in.args[1].size = strlen(name) + 1;
req->in.args[1].value = name; args.in.args[1].value = name;
/* This is really two different operations rolled into one */ /* This is really two different operations rolled into one */
req->out.numargs = 1; args.out.numargs = 1;
if (size) { if (size) {
req->out.argvar = 1; args.out.argvar = 1;
req->out.args[0].size = size; args.out.args[0].size = size;
req->out.args[0].value = value; args.out.args[0].value = value;
} else { } else {
req->out.args[0].size = sizeof(outarg); args.out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; args.out.args[0].value = &outarg;
} }
fuse_request_send(fc, req); ret = fuse_simple_request(fc, &args);
ret = req->out.h.error; if (!ret && !size)
if (!ret) ret = outarg.size;
ret = size ? req->out.args[0].size : outarg.size; if (ret == -ENOSYS) {
else { fc->no_getxattr = 1;
if (ret == -ENOSYS) { ret = -EOPNOTSUPP;
fc->no_getxattr = 1;
ret = -EOPNOTSUPP;
}
} }
fuse_put_request(fc, req);
return ret; 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 inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_getxattr_in inarg; struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg; struct fuse_getxattr_out outarg;
ssize_t ret; ssize_t ret;
@ -1939,38 +1845,30 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
if (fc->no_listxattr) if (fc->no_listxattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.size = size; inarg.size = size;
req->in.h.opcode = FUSE_LISTXATTR; args.in.h.opcode = FUSE_LISTXATTR;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
/* This is really two different operations rolled into one */ /* This is really two different operations rolled into one */
req->out.numargs = 1; args.out.numargs = 1;
if (size) { if (size) {
req->out.argvar = 1; args.out.argvar = 1;
req->out.args[0].size = size; args.out.args[0].size = size;
req->out.args[0].value = list; args.out.args[0].value = list;
} else { } else {
req->out.args[0].size = sizeof(outarg); args.out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; args.out.args[0].value = &outarg;
} }
fuse_request_send(fc, req); ret = fuse_simple_request(fc, &args);
ret = req->out.h.error; if (!ret && !size)
if (!ret) ret = outarg.size;
ret = size ? req->out.args[0].size : outarg.size; if (ret == -ENOSYS) {
else { fc->no_listxattr = 1;
if (ret == -ENOSYS) { ret = -EOPNOTSUPP;
fc->no_listxattr = 1;
ret = -EOPNOTSUPP;
}
} }
fuse_put_request(fc, req);
return ret; return ret;
} }
@ -1978,24 +1876,18 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
{ {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
int err; int err;
if (fc->no_removexattr) if (fc->no_removexattr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
req = fuse_get_req_nopages(fc); args.in.h.opcode = FUSE_REMOVEXATTR;
if (IS_ERR(req)) args.in.h.nodeid = get_node_id(inode);
return PTR_ERR(req); args.in.numargs = 1;
args.in.args[0].size = strlen(name) + 1;
req->in.h.opcode = FUSE_REMOVEXATTR; args.in.args[0].value = name;
req->in.h.nodeid = get_node_id(inode); err = fuse_simple_request(fc, &args);
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);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_removexattr = 1; fc->no_removexattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;

View File

@ -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) int opcode, struct fuse_open_out *outargp)
{ {
struct fuse_open_in inarg; struct fuse_open_in inarg;
struct fuse_req *req; FUSE_ARGS(args);
int err;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
if (!fc->atomic_o_trunc) if (!fc->atomic_o_trunc)
inarg.flags &= ~O_TRUNC; inarg.flags &= ~O_TRUNC;
req->in.h.opcode = opcode; args.in.h.opcode = opcode;
req->in.h.nodeid = nodeid; args.in.h.nodeid = nodeid;
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->out.numargs = 1; args.out.numargs = 1;
req->out.args[0].size = sizeof(*outargp); args.out.args[0].size = sizeof(*outargp);
req->out.args[0].value = outargp; args.out.args[0].value = outargp;
fuse_request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
return err; return fuse_simple_request(fc, &args);
} }
struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
@ -89,37 +81,9 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff)
return 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) static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
{ {
if (fc->destroy_req) { iput(req->misc.release.inode);
/*
* 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);
}
} }
static void fuse_file_put(struct fuse_file *ff, bool sync) static void fuse_file_put(struct fuse_file *ff, bool sync)
@ -133,12 +97,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
* implement 'open' * implement 'open'
*/ */
req->background = 0; req->background = 0;
path_put(&req->misc.release.path); iput(req->misc.release.inode);
fuse_put_request(ff->fc, req); fuse_put_request(ff->fc, req);
} else if (sync) { } else if (sync) {
req->background = 0; req->background = 0;
fuse_request_send(ff->fc, req); fuse_request_send(ff->fc, req);
path_put(&req->misc.release.path); iput(req->misc.release.inode);
fuse_put_request(ff->fc, req); fuse_put_request(ff->fc, req);
} else { } else {
req->end = fuse_release_end; req->end = fuse_release_end;
@ -297,9 +261,8 @@ void fuse_release_common(struct file *file, int opcode)
inarg->lock_owner = fuse_lock_owner_id(ff->fc, inarg->lock_owner = fuse_lock_owner_id(ff->fc,
(fl_owner_t) file); (fl_owner_t) file);
} }
/* Hold vfsmount and dentry until release is finished */ /* Hold inode until release is finished */
path_get(&file->f_path); req->misc.release.inode = igrab(file_inode(file));
req->misc.release.path = file->f_path;
/* /*
* Normally this will send the RELEASE request, however if * Normally this will send the RELEASE request, however if
@ -480,7 +443,7 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_fsync_in inarg; struct fuse_fsync_in inarg;
int err; int err;
@ -506,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)) if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
goto out; goto out;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto out;
}
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.fh = ff->fh; inarg.fh = ff->fh;
inarg.fsync_flags = datasync ? 1 : 0; inarg.fsync_flags = datasync ? 1 : 0;
req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC; args.in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
if (isdir) if (isdir)
fc->no_fsyncdir = 1; fc->no_fsyncdir = 1;
@ -2156,49 +2111,44 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
return 0; 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, 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 inode *inode = file_inode(file);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data; struct fuse_file *ff = file->private_data;
struct fuse_lk_in *arg = &req->misc.lk_in;
arg->fh = ff->fh; memset(inarg, 0, sizeof(*inarg));
arg->owner = fuse_lock_owner_id(fc, fl->fl_owner); inarg->fh = ff->fh;
arg->lk.start = fl->fl_start; inarg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
arg->lk.end = fl->fl_end; inarg->lk.start = fl->fl_start;
arg->lk.type = fl->fl_type; inarg->lk.end = fl->fl_end;
arg->lk.pid = pid; inarg->lk.type = fl->fl_type;
inarg->lk.pid = pid;
if (flock) if (flock)
arg->lk_flags |= FUSE_LK_FLOCK; inarg->lk_flags |= FUSE_LK_FLOCK;
req->in.h.opcode = opcode; args->in.h.opcode = opcode;
req->in.h.nodeid = get_node_id(inode); args->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args->in.numargs = 1;
req->in.args[0].size = sizeof(*arg); args->in.args[0].size = sizeof(*inarg);
req->in.args[0].value = arg; args->in.args[0].value = inarg;
} }
static int fuse_getlk(struct file *file, struct file_lock *fl) static int fuse_getlk(struct file *file, struct file_lock *fl)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct fuse_conn *fc = get_fuse_conn(inode); 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; struct fuse_lk_out outarg;
int err; int err;
req = fuse_get_req_nopages(fc); fuse_lk_fill(&args, file, fl, FUSE_GETLK, 0, 0, &inarg);
if (IS_ERR(req)) args.out.numargs = 1;
return PTR_ERR(req); args.out.args[0].size = sizeof(outarg);
args.out.args[0].value = &outarg;
fuse_lk_fill(req, file, fl, FUSE_GETLK, 0, 0); err = fuse_simple_request(fc, &args);
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);
if (!err) if (!err)
err = convert_fuse_file_lock(&outarg.lk, fl); err = convert_fuse_file_lock(&outarg.lk, fl);
@ -2209,7 +2159,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct fuse_conn *fc = get_fuse_conn(inode); 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; int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0; pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
int err; int err;
@ -2223,17 +2174,13 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
if (fl->fl_flags & FL_CLOSE) if (fl->fl_flags & FL_CLOSE)
return 0; return 0;
req = fuse_get_req_nopages(fc); fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg);
if (IS_ERR(req)) err = fuse_simple_request(fc, &args);
return PTR_ERR(req);
fuse_lk_fill(req, file, fl, opcode, pid, flock);
fuse_request_send(fc, req);
err = req->out.h.error;
/* locking is restartable */ /* locking is restartable */
if (err == -EINTR) if (err == -EINTR)
err = -ERESTARTSYS; err = -ERESTARTSYS;
fuse_put_request(fc, req);
return err; return err;
} }
@ -2283,7 +2230,7 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_bmap_in inarg; struct fuse_bmap_in inarg;
struct fuse_bmap_out outarg; struct fuse_bmap_out outarg;
int err; int err;
@ -2291,24 +2238,18 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
if (!inode->i_sb->s_bdev || fc->no_bmap) if (!inode->i_sb->s_bdev || fc->no_bmap)
return 0; return 0;
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return 0;
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.block = block; inarg.block = block;
inarg.blocksize = inode->i_sb->s_blocksize; inarg.blocksize = inode->i_sb->s_blocksize;
req->in.h.opcode = FUSE_BMAP; args.in.h.opcode = FUSE_BMAP;
req->in.h.nodeid = get_node_id(inode); args.in.h.nodeid = get_node_id(inode);
req->in.numargs = 1; args.in.numargs = 1;
req->in.args[0].size = sizeof(inarg); args.in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; args.in.args[0].value = &inarg;
req->out.numargs = 1; args.out.numargs = 1;
req->out.args[0].size = sizeof(outarg); args.out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; args.out.args[0].value = &outarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) if (err == -ENOSYS)
fc->no_bmap = 1; fc->no_bmap = 1;
@ -2776,7 +2717,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait)
struct fuse_conn *fc = ff->fc; struct fuse_conn *fc = ff->fc;
struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh };
struct fuse_poll_out outarg; struct fuse_poll_out outarg;
struct fuse_req *req; FUSE_ARGS(args);
int err; int err;
if (fc->no_poll) if (fc->no_poll)
@ -2794,21 +2735,15 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait)
fuse_register_polled_file(fc, ff); fuse_register_polled_file(fc, ff);
} }
req = fuse_get_req_nopages(fc); args.in.h.opcode = FUSE_POLL;
if (IS_ERR(req)) args.in.h.nodeid = ff->nodeid;
return POLLERR; args.in.numargs = 1;
args.in.args[0].size = sizeof(inarg);
req->in.h.opcode = FUSE_POLL; args.in.args[0].value = &inarg;
req->in.h.nodeid = ff->nodeid; args.out.numargs = 1;
req->in.numargs = 1; args.out.args[0].size = sizeof(outarg);
req->in.args[0].size = sizeof(inarg); args.out.args[0].value = &outarg;
req->in.args[0].value = &inarg; err = fuse_simple_request(fc, &args);
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);
if (!err) if (!err)
return outarg.revents; return outarg.revents;
@ -2949,10 +2884,10 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
loff_t length) loff_t length)
{ {
struct fuse_file *ff = file->private_data; 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_inode *fi = get_fuse_inode(inode);
struct fuse_conn *fc = ff->fc; struct fuse_conn *fc = ff->fc;
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_fallocate_in inarg = { struct fuse_fallocate_in inarg = {
.fh = ff->fh, .fh = ff->fh,
.offset = offset, .offset = offset,
@ -2985,25 +2920,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
if (!(mode & FALLOC_FL_KEEP_SIZE)) if (!(mode & FALLOC_FL_KEEP_SIZE))
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
req = fuse_get_req_nopages(fc); args.in.h.opcode = FUSE_FALLOCATE;
if (IS_ERR(req)) { args.in.h.nodeid = ff->nodeid;
err = PTR_ERR(req); args.in.numargs = 1;
goto out; args.in.args[0].size = sizeof(inarg);
} args.in.args[0].value = &inarg;
err = fuse_simple_request(fc, &args);
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;
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_fallocate = 1; fc->no_fallocate = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
} }
fuse_put_request(fc, req);
if (err) if (err)
goto out; goto out;

View File

@ -213,7 +213,7 @@ struct fuse_out {
unsigned numargs; unsigned numargs;
/** Array of arguments */ /** Array of arguments */
struct fuse_arg args[3]; struct fuse_arg args[2];
}; };
/** FUSE page descriptor */ /** FUSE page descriptor */
@ -222,6 +222,25 @@ struct fuse_page_desc {
unsigned int offset; 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 */ /** The request state */
enum fuse_req_state { enum fuse_req_state {
FUSE_REQ_INIT = 0, FUSE_REQ_INIT = 0,
@ -305,11 +324,8 @@ struct fuse_req {
/** Data for asynchronous requests */ /** Data for asynchronous requests */
union { union {
struct { struct {
union { struct fuse_release_in in;
struct fuse_release_in in; struct inode *inode;
struct work_struct work;
};
struct path path;
} release; } release;
struct fuse_init_in init_in; struct fuse_init_in init_in;
struct fuse_init_out init_out; struct fuse_init_out init_out;
@ -324,7 +340,6 @@ struct fuse_req {
struct fuse_req *next; struct fuse_req *next;
} write; } write;
struct fuse_notify_retrieve_in retrieve_in; struct fuse_notify_retrieve_in retrieve_in;
struct fuse_lk_in lk_in;
} misc; } misc;
/** page vector */ /** page vector */
@ -753,15 +768,6 @@ struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc,
*/ */
void __fuse_get_request(struct fuse_req *req); 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 * Gets a requests for a file operation, always succeeds
*/ */
@ -779,6 +785,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); 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 * Send a request in the background
*/ */
@ -804,8 +815,6 @@ void fuse_invalidate_atime(struct inode *inode);
*/ */
struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
void fuse_conn_kill(struct fuse_conn *fc);
/** /**
* Initialize fuse_conn * Initialize fuse_conn
*/ */

View File

@ -376,28 +376,13 @@ static void fuse_bdi_destroy(struct fuse_conn *fc)
bdi_destroy(&fc->bdi); 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);
wake_up_all(&fc->reserved_req_waitq);
}
EXPORT_SYMBOL_GPL(fuse_conn_kill);
static void fuse_put_super(struct super_block *sb) static void fuse_put_super(struct super_block *sb)
{ {
struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_conn *fc = get_fuse_conn_super(sb);
fuse_send_destroy(fc); fuse_send_destroy(fc);
fuse_conn_kill(fc); fuse_abort_conn(fc);
mutex_lock(&fuse_mutex); mutex_lock(&fuse_mutex);
list_del(&fc->entry); list_del(&fc->entry);
fuse_ctl_remove_conn(fc); fuse_ctl_remove_conn(fc);
@ -425,7 +410,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_conn *fc = get_fuse_conn_super(sb);
struct fuse_req *req; FUSE_ARGS(args);
struct fuse_statfs_out outarg; struct fuse_statfs_out outarg;
int err; int err;
@ -434,23 +419,17 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0; return 0;
} }
req = fuse_get_req_nopages(fc);
if (IS_ERR(req))
return PTR_ERR(req);
memset(&outarg, 0, sizeof(outarg)); memset(&outarg, 0, sizeof(outarg));
req->in.numargs = 0; args.in.numargs = 0;
req->in.h.opcode = FUSE_STATFS; args.in.h.opcode = FUSE_STATFS;
req->in.h.nodeid = get_node_id(dentry->d_inode); args.in.h.nodeid = get_node_id(dentry->d_inode);
req->out.numargs = 1; args.out.numargs = 1;
req->out.args[0].size = args.out.args[0].size =
fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
req->out.args[0].value = &outarg; args.out.args[0].value = &outarg;
fuse_request_send(fc, req); err = fuse_simple_request(fc, &args);
err = req->out.h.error;
if (!err) if (!err)
convert_fuse_statfs(buf, &outarg.st); convert_fuse_statfs(buf, &outarg.st);
fuse_put_request(fc, req);
return err; return err;
} }