[PATCH] erofs-utils: fix opaque handling for merged dirs in rebuild mode
Gao Xiang <[email protected]> Sat, 25 Jul 2026 10:53:28 +0800
| Newsgroups | org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <[email protected]> |
As cayoub-oai reports, A three-layer opaque-directory case still fails (oldest to newest): L1: dir/old.txt L2: dir/.wh..wh..opq L3: dir/new.txt After converting each layer with `mkfs.erofs --tar=f --aufs` and fsmerging with `--aufs --ovlfs-strip=1`, the expected result is only `dir/new.txt`. However, `dir/old.txt` incorrectly reappears. Reported-by: cayoub-oai <[email protected]> Fixes: 7fbec7d32ce3 ("erofs-utils: lib: honor rebuild whiteouts for recreated dirs") Fixes: 39147b48b76d ("erofs-utils: lib: add erofs_rebuild_load_tree() helper") Signed-off-by: Gao Xiang <[email protected]> --- include/erofs/xattr.h | 2 ++ lib/inode.c | 1 + lib/rebuild.c | 6 ++++-- lib/xattr.c | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h index 5fe3e91..d12c292 100644 --- a/include/erofs/xattr.h +++ b/include/erofs/xattr.h @@ -47,12 +47,14 @@ int erofs_vfs_setxattr(struct erofs_inode *inode, const char *name, const void *value, size_t size); int erofs_set_opaque_xattr(struct erofs_inode *inode); void erofs_clear_opaque_xattr(struct erofs_inode *inode); +bool erofs_get_opaque_from_disk(struct erofs_inode *inode); int erofs_set_origin_xattr(struct erofs_inode *inode); int erofs_read_xattrs_from_disk(struct erofs_inode *inode); bool erofs_xattr_prefix_matches(const char *key, unsigned int *index, unsigned int *len); void erofs_xattr_exit(struct erofs_sb_info *sbi); +void erofs_inode_free_xattrs(struct erofs_inode *inode); #ifdef __cplusplus } diff --git a/lib/inode.c b/lib/inode.c index 267694f..9f4d14c 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -166,6 +166,7 @@ unsigned int erofs_iput(struct erofs_inode *inode) if (inode->datalayout == EROFS_INODE_CHUNK_BASED) free(inode->chunkindexes); + erofs_inode_free_xattrs(inode); free(inode); return 0; } diff --git a/lib/rebuild.c b/lib/rebuild.c index 108a464..a5308dc 100644 --- a/lib/rebuild.c +++ b/lib/rebuild.c @@ -403,13 +403,15 @@ static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx) ret = erofs_read_inode_from_disk(&src); if (ret) goto out; + mergedir = d->inode; if (erofs_inode_is_whiteout(&src)) { - d->inode->opaque = true; + mergedir->opaque = true; goto out; } if (!S_ISDIR(src.i_mode)) goto out; - mergedir = d->inode; + mergedir->opaque |= erofs_get_opaque_from_disk(&src); + erofs_inode_free_xattrs(&src); inode = dir = &src; } else { u64 nid; diff --git a/lib/xattr.c b/lib/xattr.c index 051fdd8..a9486e4 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -576,6 +576,11 @@ void erofs_clear_opaque_xattr(struct erofs_inode *inode) erofs_removexattr(inode, OVL_XATTR_OPAQUE); } +bool erofs_get_opaque_from_disk(struct erofs_inode *inode) +{ + return (erofs_getxattr(inode, OVL_XATTR_OPAQUE, NULL, 0) >= 0); +} + int erofs_set_origin_xattr(struct erofs_inode *inode) { return erofs_vfs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0); @@ -1123,6 +1128,17 @@ char *erofs_export_xattr_ibody(struct erofs_inode *inode) return buf; } +void erofs_inode_free_xattrs(struct erofs_inode *inode) +{ + DBG_BUGON(inode->i_count > 0); + + if (erofs_atomic_read(&inode->flags) & EROFS_I_EA_INITED) { + free(inode->xattr_shared_xattrs); + inode->xattr_shared_xattrs = NULL; + inode->xattr_shared_count = 0; + } +} + struct erofs_xattr_iter { struct erofs_sb_info *sbi; struct erofs_buf buf; -- 2.47.3