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


Reply via email to