[PATCH] erofs: reuse xattr metabuf across init and iterators

Jia Zhu posted 1 patch 4 days, 20 hours ago
fs/erofs/xattr.c | 76 ++++++++++++++++++++++++++++--------------------
1 file changed, 44 insertions(+), 32 deletions(-)
[PATCH] erofs: reuse xattr metabuf across init and iterators
Posted by Jia Zhu 4 days, 20 hours ago
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)