Skip to content

Commit 72227ea

Browse files
author
Miklos Szeredi
committed
fuse: convert to fileattr
Since fuse just passes ioctl args through to/from server, converting to the fileattr API is more involved, than most other filesystems. Both .fileattr_set() and .fileattr_get() need to obtain an open file to operate on. The simplest way is with the following sequence: FUSE_OPEN FUSE_IOCTL FUSE_RELEASE If this turns out to be a performance problem, it could be optimized for the case when there's already a file (any file) open for the inode. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent b9d54c6 commit 72227ea

3 files changed

Lines changed: 141 additions & 10 deletions

File tree

fs/fuse/dir.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,8 @@ static const struct inode_operations fuse_dir_inode_operations = {
18661866
.listxattr = fuse_listxattr,
18671867
.get_acl = fuse_get_acl,
18681868
.set_acl = fuse_set_acl,
1869+
.fileattr_get = fuse_fileattr_get,
1870+
.fileattr_set = fuse_fileattr_set,
18691871
};
18701872

18711873
static const struct file_operations fuse_dir_operations = {
@@ -1886,6 +1888,8 @@ static const struct inode_operations fuse_common_inode_operations = {
18861888
.listxattr = fuse_listxattr,
18871889
.get_acl = fuse_get_acl,
18881890
.set_acl = fuse_set_acl,
1891+
.fileattr_get = fuse_fileattr_get,
1892+
.fileattr_set = fuse_fileattr_set,
18891893
};
18901894

18911895
static const struct inode_operations fuse_symlink_inode_operations = {

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,9 @@ void fuse_dax_cancel_work(struct fuse_conn *fc);
12411241
long fuse_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
12421242
long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
12431243
unsigned long arg);
1244+
int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa);
1245+
int fuse_fileattr_set(struct user_namespace *mnt_userns,
1246+
struct dentry *dentry, struct fileattr *fa);
12441247

12451248
/* file.c */
12461249

fs/fuse/ioctl.c

Lines changed: 134 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
196196
struct iovec *iov = iov_page;
197197

198198
iov->iov_base = (void __user *)arg;
199-
200-
switch (cmd) {
201-
case FS_IOC_GETFLAGS:
202-
case FS_IOC_SETFLAGS:
203-
iov->iov_len = sizeof(int);
204-
break;
205-
default:
206-
iov->iov_len = _IOC_SIZE(cmd);
207-
break;
208-
}
199+
iov->iov_len = _IOC_SIZE(cmd);
209200

210201
if (_IOC_DIR(cmd) & _IOC_WRITE) {
211202
in_iov = iov;
@@ -364,3 +355,136 @@ long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
364355
{
365356
return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
366357
}
358+
359+
static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff,
360+
unsigned int cmd, void *ptr, size_t size)
361+
{
362+
struct fuse_mount *fm = ff->fm;
363+
struct fuse_ioctl_in inarg;
364+
struct fuse_ioctl_out outarg;
365+
FUSE_ARGS(args);
366+
int err;
367+
368+
memset(&inarg, 0, sizeof(inarg));
369+
inarg.fh = ff->fh;
370+
inarg.cmd = cmd;
371+
372+
#if BITS_PER_LONG == 32
373+
inarg.flags |= FUSE_IOCTL_32BIT;
374+
#endif
375+
if (S_ISDIR(inode->i_mode))
376+
inarg.flags |= FUSE_IOCTL_DIR;
377+
378+
if (_IOC_DIR(cmd) & _IOC_READ)
379+
inarg.out_size = size;
380+
if (_IOC_DIR(cmd) & _IOC_WRITE)
381+
inarg.in_size = size;
382+
383+
args.opcode = FUSE_IOCTL;
384+
args.nodeid = ff->nodeid;
385+
args.in_numargs = 2;
386+
args.in_args[0].size = sizeof(inarg);
387+
args.in_args[0].value = &inarg;
388+
args.in_args[1].size = inarg.in_size;
389+
args.in_args[1].value = ptr;
390+
args.out_numargs = 2;
391+
args.out_args[0].size = sizeof(outarg);
392+
args.out_args[0].value = &outarg;
393+
args.out_args[1].size = inarg.out_size;
394+
args.out_args[1].value = ptr;
395+
396+
err = fuse_simple_request(fm, &args);
397+
if (!err && outarg.flags & FUSE_IOCTL_RETRY)
398+
err = -EIO;
399+
400+
return err;
401+
}
402+
403+
static struct fuse_file *fuse_priv_ioctl_prepare(struct inode *inode)
404+
{
405+
struct fuse_mount *fm = get_fuse_mount(inode);
406+
bool isdir = S_ISDIR(inode->i_mode);
407+
408+
if (!S_ISREG(inode->i_mode) && !isdir)
409+
return ERR_PTR(-ENOTTY);
410+
411+
return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir);
412+
}
413+
414+
static void fuse_priv_ioctl_cleanup(struct inode *inode, struct fuse_file *ff)
415+
{
416+
fuse_file_release(inode, ff, O_RDONLY, NULL, S_ISDIR(inode->i_mode));
417+
}
418+
419+
int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa)
420+
{
421+
struct inode *inode = d_inode(dentry);
422+
struct fuse_file *ff;
423+
unsigned int flags;
424+
struct fsxattr xfa;
425+
int err;
426+
427+
ff = fuse_priv_ioctl_prepare(inode);
428+
if (IS_ERR(ff))
429+
return PTR_ERR(ff);
430+
431+
if (fa->flags_valid) {
432+
err = fuse_priv_ioctl(inode, ff, FS_IOC_GETFLAGS,
433+
&flags, sizeof(flags));
434+
if (err)
435+
goto cleanup;
436+
437+
fileattr_fill_flags(fa, flags);
438+
} else {
439+
err = fuse_priv_ioctl(inode, ff, FS_IOC_FSGETXATTR,
440+
&xfa, sizeof(xfa));
441+
if (err)
442+
goto cleanup;
443+
444+
fileattr_fill_xflags(fa, xfa.fsx_xflags);
445+
fa->fsx_extsize = xfa.fsx_extsize;
446+
fa->fsx_nextents = xfa.fsx_nextents;
447+
fa->fsx_projid = xfa.fsx_projid;
448+
fa->fsx_cowextsize = xfa.fsx_cowextsize;
449+
}
450+
cleanup:
451+
fuse_priv_ioctl_cleanup(inode, ff);
452+
453+
return err;
454+
}
455+
456+
int fuse_fileattr_set(struct user_namespace *mnt_userns,
457+
struct dentry *dentry, struct fileattr *fa)
458+
{
459+
struct inode *inode = d_inode(dentry);
460+
struct fuse_file *ff;
461+
unsigned int flags = fa->flags;
462+
struct fsxattr xfa;
463+
int err;
464+
465+
ff = fuse_priv_ioctl_prepare(inode);
466+
if (IS_ERR(ff))
467+
return PTR_ERR(ff);
468+
469+
if (fa->flags_valid) {
470+
err = fuse_priv_ioctl(inode, ff, FS_IOC_SETFLAGS,
471+
&flags, sizeof(flags));
472+
if (err)
473+
goto cleanup;
474+
} else {
475+
memset(&xfa, 0, sizeof(xfa));
476+
xfa.fsx_xflags = fa->fsx_xflags;
477+
xfa.fsx_extsize = fa->fsx_extsize;
478+
xfa.fsx_nextents = fa->fsx_nextents;
479+
xfa.fsx_projid = fa->fsx_projid;
480+
xfa.fsx_cowextsize = fa->fsx_cowextsize;
481+
482+
err = fuse_priv_ioctl(inode, ff, FS_IOC_FSSETXATTR,
483+
&xfa, sizeof(xfa));
484+
}
485+
486+
cleanup:
487+
fuse_priv_ioctl_cleanup(inode, ff);
488+
489+
return err;
490+
}

0 commit comments

Comments
 (0)