erofs_init_inode_xattrs() used a local metabuf to read the inline xattr
header and shared xattr ids.

getxattr and listxattr then initialized a separate iterator metabuf for
the following inline/shared xattr walk.

Pass the iterator metabuf into erofs_init_inode_xattrs() so initialization
and the inline iterator path share the same metabuf lifetime. The getxattr
and listxattr callers now use a single cleanup exit for their iterator
metabuf.

Drop and reinitialize the metabuf before switching from inline xattrs to
the shared xattr metadata area, since that path may use a different
mapping.

Signed-off-by: Jia Zhu <[email protected]>
---
 fs/erofs/xattr.c | 76 ++++++++++++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 32 deletions(-)

diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c
index df7ea019526d7..f7eb7431b0b81 100644
--- a/fs/erofs/xattr.c
+++ b/fs/erofs/xattr.c
@@ -27,9 +27,8 @@ struct erofs_xattr_iter {
 
 static const char *erofs_xattr_prefix(unsigned int idx, struct dentry *dentry);
 
-static int erofs_init_inode_xattrs(struct inode *inode)
+static int erofs_init_inode_xattrs(struct erofs_buf *buf, struct inode *inode)
 {
-       struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
        struct erofs_inode *vi = EROFS_I(inode);
        struct super_block *sb = inode->i_sb;
        const struct erofs_xattr_ibody_header *ih;
@@ -78,7 +77,7 @@ static int erofs_init_inode_xattrs(struct inode *inode)
        }
 
        pos = erofs_iloc(inode) + vi->inode_isize;
-       ih = erofs_read_metabuf(&buf, sb, pos, erofs_inode_in_metabox(inode));
+       ih = erofs_read_metabuf(buf, sb, pos, erofs_inode_in_metabox(inode));
        if (IS_ERR(ih)) {
                ret = PTR_ERR(ih);
                goto out_unlock;
@@ -101,7 +100,7 @@ static int erofs_init_inode_xattrs(struct inode *inode)
        /* skip the ibody header and read the shared xattr array */
        pos += sizeof(struct erofs_xattr_ibody_header);
        for (i = 0; i < vi->xattr_shared_count; ++i) {
-               xattr_id = erofs_bread(&buf, pos + i * sizeof(__le32), true);
+               xattr_id = erofs_bread(buf, pos + i * sizeof(__le32), true);
                if (IS_ERR(xattr_id)) {
                        kfree(vi->xattr_shared_xattrs);
                        vi->xattr_shared_xattrs = NULL;
@@ -115,7 +114,6 @@ static int erofs_init_inode_xattrs(struct inode *inode)
        smp_mb();
        set_bit(EROFS_I_EA_INITED_BIT, &vi->flags);
 out_unlock:
-       erofs_put_metabuf(&buf);
        clear_and_wake_up_bit(EROFS_I_BL_XATTR_BIT, &vi->flags);
        return ret;
 }
@@ -337,40 +335,48 @@ static int erofs_getxattr(struct inode *inode, int index, 
const char *name,
 {
        int ret;
        unsigned int hashbit;
-       struct erofs_xattr_iter it;
+       struct erofs_xattr_iter it = {
+               .sb = inode->i_sb,
+               .buf = __EROFS_BUF_INITIALIZER,
+               .buffer = buffer,
+               .buffer_size = buffer_size,
+               .buffer_ofs = 0,
+       };
        struct erofs_inode *vi = EROFS_I(inode);
        struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
 
        if (!name)
                return -EINVAL;
 
-       ret = erofs_init_inode_xattrs(inode);
+       ret = erofs_init_inode_xattrs(&it.buf, inode);
        if (ret)
-               return ret;
+               goto out;
 
        /* reserved flag is non-zero if there's any change of on-disk format */
        if (erofs_sb_has_xattr_filter(sbi) && !sbi->xattr_filter_reserved) {
                hashbit = xxh32(name, strlen(name),
                                EROFS_XATTR_FILTER_SEED + index);
                hashbit &= EROFS_XATTR_FILTER_BITS - 1;
-               if (vi->xattr_name_filter & (1U << hashbit))
-                       return -ENODATA;
+               if (vi->xattr_name_filter & (1U << hashbit)) {
+                       ret = -ENODATA;
+                       goto out;
+               }
        }
 
        it.index = index;
        it.name = QSTR(name);
-       if (it.name.len > EROFS_NAME_LEN)
-               return -ERANGE;
-
-       it.sb = inode->i_sb;
-       it.buf = __EROFS_BUF_INITIALIZER;
-       it.buffer = buffer;
-       it.buffer_size = buffer_size;
-       it.buffer_ofs = 0;
+       if (it.name.len > EROFS_NAME_LEN) {
+               ret = -ERANGE;
+               goto out;
+       }
 
        ret = erofs_xattr_iter_inline(&it, inode, true);
-       if (ret == -ENODATA)
+       if (ret == -ENODATA) {
+               erofs_put_metabuf(&it.buf);
+               it.buf = __EROFS_BUF_INITIALIZER;
                ret = erofs_xattr_iter_shared(&it, inode, true);
+       }
+out:
        erofs_put_metabuf(&it.buf);
        return ret ? ret : it.buffer_ofs;
 }
@@ -378,27 +384,33 @@ static int erofs_getxattr(struct inode *inode, int index, 
const char *name,
 ssize_t erofs_listxattr(struct dentry *dentry, char *buffer, size_t 
buffer_size)
 {
        int ret;
-       struct erofs_xattr_iter it;
+       struct erofs_xattr_iter it = {
+               .sb = dentry->d_sb,
+               .buf = __EROFS_BUF_INITIALIZER,
+               .dentry = dentry,
+               .buffer = buffer,
+               .buffer_size = buffer_size,
+               .buffer_ofs = 0,
+       };
        struct inode *inode = d_inode(dentry);
 
-       ret = erofs_init_inode_xattrs(inode);
-       if (ret == -ENODATA)
-               return 0;
+       ret = erofs_init_inode_xattrs(&it.buf, inode);
+       if (ret == -ENODATA) {
+               ret = 0;
+               goto out;
+       }
        if (ret)
-               return ret;
-
-       it.sb = dentry->d_sb;
-       it.buf = __EROFS_BUF_INITIALIZER;
-       it.dentry = dentry;
-       it.buffer = buffer;
-       it.buffer_size = buffer_size;
-       it.buffer_ofs = 0;
+               goto out;
 
        ret = erofs_xattr_iter_inline(&it, inode, false);
-       if (!ret || ret == -ENODATA)
+       if (!ret || ret == -ENODATA) {
+               erofs_put_metabuf(&it.buf);
+               it.buf = __EROFS_BUF_INITIALIZER;
                ret = erofs_xattr_iter_shared(&it, inode, false);
+       }
        if (ret == -ENODATA)
                ret = 0;
+out:
        erofs_put_metabuf(&it.buf);
        return ret ? ret : it.buffer_ofs;
 }
-- 
2.39.5 (Apple Git-154)

Reply via email to