Skip to content

Commit

Permalink
fuse: Use generic xattr ops
Browse files Browse the repository at this point in the history
In preparation for posix acl support, rework fuse to use xattr handlers and
the generic setxattr/getxattr/listxattr callbacks.  Split the xattr code
out into it's own file, and promote symbols to module-global scope as
needed.

Functionally these changes have no impact, as fuse still uses a single
handler for all xattrs which uses the old callbacks.

Signed-off-by: Seth Forshee <[email protected]>
Signed-off-by: Miklos Szeredi <[email protected]>
  • Loading branch information
Seth Forshee authored and Miklos Szeredi committed Oct 1, 2016
1 parent cb3ae6d commit 703c736
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 176 deletions.
2 changes: 1 addition & 1 deletion fs/fuse/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o

fuse-objs := dev.o dir.o file.o inode.o control.o
fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o
186 changes: 11 additions & 175 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/xattr.h>

static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
{
Expand Down Expand Up @@ -634,7 +635,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
return create_new_entry(fc, &args, dir, entry, S_IFLNK);
}

static inline void fuse_update_ctime(struct inode *inode)
void fuse_update_ctime(struct inode *inode)
{
if (!IS_NOCMTIME(inode)) {
inode->i_ctime = current_fs_time(inode->i_sb);
Expand Down Expand Up @@ -1724,171 +1725,6 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
return fuse_update_attributes(inode, stat, NULL, NULL);
}

static int fuse_setxattr(struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
{
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
struct fuse_setxattr_in inarg;
int err;

if (fc->no_setxattr)
return -EOPNOTSUPP;

memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
inarg.flags = flags;
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;
}
if (!err) {
fuse_invalidate_attr(inode);
fuse_update_ctime(inode);
}
return err;
}

static ssize_t fuse_getxattr(struct dentry *entry, struct inode *inode,
const char *name, void *value, size_t size)
{
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;

if (fc->no_getxattr)
return -EOPNOTSUPP;

memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
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 */
args.out.numargs = 1;
if (size) {
args.out.argvar = 1;
args.out.args[0].size = size;
args.out.args[0].value = value;
} else {
args.out.args[0].size = sizeof(outarg);
args.out.args[0].value = &outarg;
}
ret = fuse_simple_request(fc, &args);
if (!ret && !size)
ret = outarg.size;
if (ret == -ENOSYS) {
fc->no_getxattr = 1;
ret = -EOPNOTSUPP;
}
return ret;
}

static int fuse_verify_xattr_list(char *list, size_t size)
{
size_t origsize = size;

while (size) {
size_t thislen = strnlen(list, size);

if (!thislen || thislen == size)
return -EIO;

size -= thislen + 1;
list += thislen + 1;
}

return origsize;
}

static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
{
struct inode *inode = d_inode(entry);
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;

if (!fuse_allow_current_process(fc))
return -EACCES;

if (fc->no_listxattr)
return -EOPNOTSUPP;

memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
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 */
args.out.numargs = 1;
if (size) {
args.out.argvar = 1;
args.out.args[0].size = size;
args.out.args[0].value = list;
} else {
args.out.args[0].size = sizeof(outarg);
args.out.args[0].value = &outarg;
}
ret = fuse_simple_request(fc, &args);
if (!ret && !size)
ret = outarg.size;
if (ret > 0 && size)
ret = fuse_verify_xattr_list(list, ret);
if (ret == -ENOSYS) {
fc->no_listxattr = 1;
ret = -EOPNOTSUPP;
}
return ret;
}

static int fuse_removexattr(struct dentry *entry, const char *name)
{
struct inode *inode = d_inode(entry);
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
int err;

if (fc->no_removexattr)
return -EOPNOTSUPP;

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;
}
if (!err) {
fuse_invalidate_attr(inode);
fuse_update_ctime(inode);
}
return err;
}

static const struct inode_operations fuse_dir_inode_operations = {
.lookup = fuse_lookup,
.mkdir = fuse_mkdir,
Expand All @@ -1903,10 +1739,10 @@ static const struct inode_operations fuse_dir_inode_operations = {
.mknod = fuse_mknod,
.permission = fuse_permission,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
.removexattr = generic_removexattr,
};

static const struct file_operations fuse_dir_operations = {
Expand All @@ -1924,21 +1760,21 @@ static const struct inode_operations fuse_common_inode_operations = {
.setattr = fuse_setattr,
.permission = fuse_permission,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
.removexattr = generic_removexattr,
};

static const struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr,
.get_link = fuse_get_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
.removexattr = generic_removexattr,
};

void fuse_init_common(struct inode *inode)
Expand Down
5 changes: 5 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,8 @@ int fuse_allow_current_process(struct fuse_conn *fc);

u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);

void fuse_update_ctime(struct inode *inode);

int fuse_update_attributes(struct inode *inode, struct kstat *stat,
struct file *file, bool *refreshed);

Expand Down Expand Up @@ -966,4 +968,7 @@ void fuse_set_initialized(struct fuse_conn *fc);
void fuse_unlock_inode(struct inode *inode);
void fuse_lock_inode(struct inode *inode);

ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size);
extern const struct xattr_handler *fuse_xattr_handlers[];

#endif /* _FS_FUSE_I_H */
1 change: 1 addition & 0 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
}
sb->s_magic = FUSE_SUPER_MAGIC;
sb->s_op = &fuse_super_operations;
sb->s_xattr = fuse_xattr_handlers;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_time_gran = 1;
sb->s_export_op = &fuse_export_operations;
Expand Down
Loading

0 comments on commit 703c736

Please sign in to comment.