mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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:
commit
c103b21c20
@ -415,7 +415,7 @@ err_unlock:
|
||||
err_region:
|
||||
unregister_chrdev_region(devt, 1);
|
||||
err:
|
||||
fuse_conn_kill(fc);
|
||||
fuse_abort_conn(fc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
534
fs/fuse/dir.c
534
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);
|
||||
FUSE_ARGS(args);
|
||||
|
||||
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);
|
||||
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);
|
||||
FUSE_ARGS(args);
|
||||
|
||||
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);
|
||||
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;
|
||||
|
228
fs/fuse/file.c
228
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)
|
||||
@ -89,37 +81,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 +97,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 +261,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
|
||||
@ -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 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;
|
||||
|
||||
@ -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))
|
||||
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;
|
||||
@ -2156,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);
|
||||
|
||||
@ -2209,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;
|
||||
@ -2223,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;
|
||||
}
|
||||
|
||||
@ -2283,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;
|
||||
@ -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)
|
||||
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;
|
||||
|
||||
@ -2776,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)
|
||||
@ -2794,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;
|
||||
@ -2949,10 +2884,10 @@ 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;
|
||||
struct fuse_req *req;
|
||||
FUSE_ARGS(args);
|
||||
struct fuse_fallocate_in inarg = {
|
||||
.fh = ff->fh,
|
||||
.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))
|
||||
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;
|
||||
|
||||
|
@ -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 */
|
||||
@ -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,
|
||||
@ -305,11 +324,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;
|
||||
@ -324,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 */
|
||||
@ -753,15 +768,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
|
||||
*/
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -804,8 +815,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
|
||||
*/
|
||||
|
@ -376,28 +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);
|
||||
wake_up_all(&fc->reserved_req_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);
|
||||
@ -425,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;
|
||||
|
||||
@ -434,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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user