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)
