fuse: extend FUSE_SETXATTR request
authorVivek Goyal <vgoyal@redhat.com>
Thu, 25 Mar 2021 15:18:22 +0000 (11:18 -0400)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 14 Apr 2021 08:40:57 +0000 (10:40 +0200)
Fuse client needs to send additional information to file server when it
calls SETXATTR(system.posix_acl_access), so add extra flags field to the
structure.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/acl.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/fuse/xattr.c
include/uapi/linux/fuse.h

index e9c0f91..d31260a 100644 (file)
@@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
                        return ret;
                }
 
-               ret = fuse_setxattr(inode, name, value, size, 0);
+               ret = fuse_setxattr(inode, name, value, size, 0, 0);
                kfree(value);
        } else {
                ret = fuse_removexattr(inode, name);
index e7775d9..979b680 100644 (file)
@@ -668,6 +668,9 @@ struct fuse_conn {
        /** Is setxattr not implemented by fs? */
        unsigned no_setxattr:1;
 
+       /** Does file server support extended setxattr */
+       unsigned setxattr_ext:1;
+
        /** Is getxattr not implemented by fs? */
        unsigned no_getxattr:1;
 
@@ -1171,7 +1174,7 @@ void fuse_unlock_inode(struct inode *inode, bool locked);
 bool fuse_lock_inode(struct inode *inode);
 
 int fuse_setxattr(struct inode *inode, const char *name, const void *value,
-                 size_t size, int flags);
+                 size_t size, int flags, unsigned int extra_flags);
 ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
                      size_t size);
 ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size);
index b0e18b4..06a68cf 100644 (file)
@@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
                                fc->handle_killpriv_v2 = 1;
                                fm->sb->s_flags |= SB_NOSEC;
                        }
+                       if (arg->flags & FUSE_SETXATTR_EXT)
+                               fc->setxattr_ext = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_SIZE;
                        fc->no_lock = 1;
@@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm)
                FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
                FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
                FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
-               FUSE_HANDLE_KILLPRIV_V2;
+               FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT;
 #ifdef CONFIG_FUSE_DAX
        if (fm->fc->dax)
                ia->in.flags |= FUSE_MAP_ALIGNMENT;
index 1a7d7ac..61dfaf7 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/posix_acl_xattr.h>
 
 int fuse_setxattr(struct inode *inode, const char *name, const void *value,
-                 size_t size, int flags)
+                 size_t size, int flags, unsigned int extra_flags)
 {
        struct fuse_mount *fm = get_fuse_mount(inode);
        FUSE_ARGS(args);
@@ -25,10 +25,13 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value,
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
        inarg.flags = flags;
+       inarg.setxattr_flags = extra_flags;
+
        args.opcode = FUSE_SETXATTR;
        args.nodeid = get_node_id(inode);
        args.in_numargs = 3;
-       args.in_args[0].size = sizeof(inarg);
+       args.in_args[0].size = fm->fc->setxattr_ext ?
+               sizeof(inarg) : FUSE_COMPAT_SETXATTR_IN_SIZE;
        args.in_args[0].value = &inarg;
        args.in_args[1].size = strlen(name) + 1;
        args.in_args[1].value = name;
@@ -199,7 +202,7 @@ static int fuse_xattr_set(const struct xattr_handler *handler,
        if (!value)
                return fuse_removexattr(inode, name);
 
-       return fuse_setxattr(inode, name, value, size, flags);
+       return fuse_setxattr(inode, name, value, size, flags, 0);
 }
 
 static bool no_xattr_list(struct dentry *dentry)
index 5444261..390f7b4 100644 (file)
  *  7.33
  *  - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID
  *  - add FUSE_OPEN_KILL_SUIDGID
+ *  - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT
  */
 
 #ifndef _LINUX_FUSE_H
@@ -330,6 +331,7 @@ struct fuse_file_lock {
  *                     does not have CAP_FSETID. Additionally upon
  *                     write/truncate sgid is killed only if file has group
  *                     execute permission. (Same as Linux VFS behavior).
+ * FUSE_SETXATTR_EXT:  Server supports extended struct fuse_setxattr_in
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -360,6 +362,7 @@ struct fuse_file_lock {
 #define FUSE_MAP_ALIGNMENT     (1 << 26)
 #define FUSE_SUBMOUNTS         (1 << 27)
 #define FUSE_HANDLE_KILLPRIV_V2        (1 << 28)
+#define FUSE_SETXATTR_EXT      (1 << 29)
 
 /**
  * CUSE INIT request/reply flags
@@ -681,9 +684,13 @@ struct fuse_fsync_in {
        uint32_t        padding;
 };
 
+#define FUSE_COMPAT_SETXATTR_IN_SIZE 8
+
 struct fuse_setxattr_in {
        uint32_t        size;
        uint32_t        flags;
+       uint32_t        setxattr_flags;
+       uint32_t        padding;
 };
 
 struct fuse_getxattr_in {