reiserfs: fix extended attributes on the root directory
authorJeff Mahoney <jeffm@suse.com>
Thu, 24 Oct 2019 14:31:27 +0000 (10:31 -0400)
committerJan Kara <jack@suse.cz>
Thu, 31 Oct 2019 14:39:24 +0000 (15:39 +0100)
Since commit d0a5b995a308 (vfs: Add IOP_XATTR inode operations flag)
extended attributes haven't worked on the root directory in reiserfs.

This is due to reiserfs conditionally setting the sb->s_xattrs handler
array depending on whether it located or create the internal privroot
directory.  It necessarily does this after the root inode is already
read in.  The IOP_XATTR flag is set during inode initialization, so
it never gets set on the root directory.

This commit unconditionally assigns sb->s_xattrs and clears IOP_XATTR on
internal inodes.  The old return values due to the conditional assignment
are handled via open_xa_root, which now returns EOPNOTSUPP as the VFS
would have done.

Link: https://lore.kernel.org/r/20191024143127.17509-1-jeffm@suse.com
CC: stable@vger.kernel.org
Fixes: d0a5b995a308 ("vfs: Add IOP_XATTR inode operations flag")
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/reiserfs/reiserfs.h
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c

index 132ec4406ed00733947e9ba8c2fc770de08ec749..6419e6dacc394dd0e3290a4fefe6af35b06039b2 100644 (file)
@@ -2097,6 +2097,15 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                goto out_inserted_sd;
        }
 
+       /*
+        * Mark it private if we're creating the privroot
+        * or something under it.
+        */
+       if (IS_PRIVATE(dir) || dentry == REISERFS_SB(sb)->priv_root) {
+               inode->i_flags |= S_PRIVATE;
+               inode->i_opflags &= ~IOP_XATTR;
+       }
+
        if (reiserfs_posixacl(inode->i_sb)) {
                reiserfs_write_unlock(inode->i_sb);
                retval = reiserfs_inherit_default_acl(th, dir, dentry, inode);
@@ -2111,8 +2120,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                reiserfs_warning(inode->i_sb, "jdm-13090",
                                 "ACLs aren't enabled in the fs, "
                                 "but vfs thinks they are!");
-       } else if (IS_PRIVATE(dir))
-               inode->i_flags |= S_PRIVATE;
+       }
 
        if (security->name) {
                reiserfs_write_unlock(inode->i_sb);
index 97f3fc4fdd79e8b1b1fa2ad3be41a394742780ee..959a066b7bb07f63e111a5990fa9b824ed83da43 100644 (file)
@@ -377,10 +377,13 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
 
                /*
                 * Propagate the private flag so we know we're
-                * in the priv tree
+                * in the priv tree.  Also clear IOP_XATTR
+                * since we don't have xattrs on xattr files.
                 */
-               if (IS_PRIVATE(dir))
+               if (IS_PRIVATE(dir)) {
                        inode->i_flags |= S_PRIVATE;
+                       inode->i_opflags &= ~IOP_XATTR;
+               }
        }
        reiserfs_write_unlock(dir->i_sb);
        if (retval == IO_ERROR) {
index e5ca9ed79e54cda20606497abffa76470011d31d..726580114d55659d686d1f3c6d945486fadeb9f7 100644 (file)
@@ -1168,6 +1168,8 @@ static inline int bmap_would_wrap(unsigned bmap_nr)
        return bmap_nr > ((1LL << 16) - 1);
 }
 
+extern const struct xattr_handler *reiserfs_xattr_handlers[];
+
 /*
  * this says about version of key of all items (but stat data) the
  * object consists of
index d69b4ac0ae2f3e3ce3d3a61a09cd3041ba72c9b9..3244037b1286de881e45ae440689118555ee3ec7 100644 (file)
@@ -2049,6 +2049,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        if (replay_only(s))
                goto error_unlocked;
 
+       s->s_xattr = reiserfs_xattr_handlers;
+
        if (bdev_read_only(s->s_bdev) && !sb_rdonly(s)) {
                SWARN(silent, s, "clm-7000",
                      "Detected readonly device, marking FS readonly");
index b5b26d8a192c4ae71d5a958bd4968183f3ca010a..62b40df36c98cb0e890ce3c58845c8af4be7f2bf 100644 (file)
@@ -122,13 +122,13 @@ static struct dentry *open_xa_root(struct super_block *sb, int flags)
        struct dentry *xaroot;
 
        if (d_really_is_negative(privroot))
-               return ERR_PTR(-ENODATA);
+               return ERR_PTR(-EOPNOTSUPP);
 
        inode_lock_nested(d_inode(privroot), I_MUTEX_XATTR);
 
        xaroot = dget(REISERFS_SB(sb)->xattr_root);
        if (!xaroot)
-               xaroot = ERR_PTR(-ENODATA);
+               xaroot = ERR_PTR(-EOPNOTSUPP);
        else if (d_really_is_negative(xaroot)) {
                int err = -ENODATA;
 
@@ -619,6 +619,10 @@ int reiserfs_xattr_set(struct inode *inode, const char *name,
        int error, error2;
        size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size);
 
+       /* Check before we start a transaction and then do nothing. */
+       if (!d_really_is_positive(REISERFS_SB(inode->i_sb)->priv_root))
+               return -EOPNOTSUPP;
+
        if (!(flags & XATTR_REPLACE))
                jbegin_count += reiserfs_xattr_jcreate_nblocks(inode);
 
@@ -841,8 +845,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
        if (d_really_is_negative(dentry))
                return -EINVAL;
 
-       if (!dentry->d_sb->s_xattr ||
-           get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
+       if (get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
        dir = open_xa_dir(d_inode(dentry), XATTR_REPLACE);
@@ -882,6 +885,7 @@ static int create_privroot(struct dentry *dentry)
        }
 
        d_inode(dentry)->i_flags |= S_PRIVATE;
+       d_inode(dentry)->i_opflags &= ~IOP_XATTR;
        reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr "
                      "storage.\n", PRIVROOT_NAME);
 
@@ -895,7 +899,7 @@ static int create_privroot(struct dentry *dentry) { return 0; }
 #endif
 
 /* Actual operations that are exported to VFS-land */
-static const struct xattr_handler *reiserfs_xattr_handlers[] = {
+const struct xattr_handler *reiserfs_xattr_handlers[] = {
 #ifdef CONFIG_REISERFS_FS_XATTR
        &reiserfs_xattr_user_handler,
        &reiserfs_xattr_trusted_handler,
@@ -966,8 +970,10 @@ int reiserfs_lookup_privroot(struct super_block *s)
        if (!IS_ERR(dentry)) {
                REISERFS_SB(s)->priv_root = dentry;
                d_set_d_op(dentry, &xattr_lookup_poison_ops);
-               if (d_really_is_positive(dentry))
+               if (d_really_is_positive(dentry)) {
                        d_inode(dentry)->i_flags |= S_PRIVATE;
+                       d_inode(dentry)->i_opflags &= ~IOP_XATTR;
+               }
        } else
                err = PTR_ERR(dentry);
        inode_unlock(d_inode(s->s_root));
@@ -996,7 +1002,6 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
        }
 
        if (d_really_is_positive(privroot)) {
-               s->s_xattr = reiserfs_xattr_handlers;
                inode_lock(d_inode(privroot));
                if (!REISERFS_SB(s)->xattr_root) {
                        struct dentry *dentry;
index aa9380bac196321a1a3020ace76c0fe27fdda614..05f666794561c8fdfbd44f4df9af8f5288626336 100644 (file)
@@ -320,10 +320,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
         * would be useless since permissions are ignored, and a pain because
         * it introduces locking cycles
         */
-       if (IS_PRIVATE(dir)) {
-               inode->i_flags |= S_PRIVATE;
+       if (IS_PRIVATE(inode))
                goto apply_umask;
-       }
 
        err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
        if (err)