fs/erofs/xattr.c | 76 ++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 32 deletions(-)
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 <zhujia.zj@bytedance.com>
---
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)
© 2016 - 2026 Red Hat, Inc.