[PATCH 5/7] erofs-utils: support dot-omitted directories
Gao Xiang
hsiangkao at linux.alibaba.com
Mon Mar 10 20:25:06 AEDT 2025
Omit the `dot` dirent by default if 48bit layout is set.
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
include/erofs/config.h | 1 +
include/erofs/internal.h | 1 +
lib/dir.c | 2 ++
lib/inode.c | 35 +++++++++++++++++++++++++----------
lib/namei.c | 3 ++-
mkfs/main.c | 14 ++++++++++++++
6 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 92c1467..eb5cad8 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -66,6 +66,7 @@ struct erofs_configure {
bool c_xattr_name_filter;
bool c_ovlfs_strip;
bool c_hard_dereference;
+ bool c_dot_omitted;
#ifdef HAVE_LIBSELINUX
struct selabel_handle *sehnd;
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index fd8d43d..227e830 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -236,6 +236,7 @@ struct erofs_inode {
bool opaque;
/* OVL: non-merge dir that may contain whiteout entries */
bool whiteouts;
+ bool dot_omitted;
unsigned int xattr_isize;
unsigned int extent_isize;
diff --git a/lib/dir.c b/lib/dir.c
index d786a5b..3405844 100644
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -150,6 +150,8 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
return -ENOTDIR;
ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND;
+ if (dir->dot_omitted)
+ ctx->flags |= EROFS_READDIR_DOT_FOUND;
pos = 0;
while (pos < dir->i_size) {
erofs_blk_t lblk = erofs_blknr(sbi, pos);
diff --git a/lib/inode.c b/lib/inode.c
index 7230549..7ded6c1 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -253,21 +253,29 @@ static int erofs_prepare_dir_file(struct erofs_inode *dir,
{
struct erofs_sb_info *sbi = dir->sbi;
struct erofs_dentry *d, *n, **sorted_d;
+ bool dot_omitted = cfg.c_dot_omitted;
unsigned int i;
unsigned int d_size = 0;
sorted_d = malloc(nr_subdirs * sizeof(d));
if (!sorted_d)
return -ENOMEM;
+
+ dir->dot_omitted = dot_omitted;
i = 0;
list_for_each_entry_safe(d, n, &dir->i_subdirs, d_child) {
list_del(&d->d_child);
+ if (dot_omitted && !strcmp(d->name, ".")) {
+ erofs_iput(d->inode);
+ free(d);
+ continue;
+ }
sorted_d[i++] = d;
}
- DBG_BUGON(i != nr_subdirs);
- qsort(sorted_d, nr_subdirs, sizeof(d), comp_subdir);
- for (i = 0; i < nr_subdirs; i++)
- list_add_tail(&sorted_d[i]->d_child, &dir->i_subdirs);
+ DBG_BUGON(i + dot_omitted != nr_subdirs);
+ qsort(sorted_d, i, sizeof(d), comp_subdir);
+ while (i)
+ list_add(&sorted_d[--i]->d_child, &dir->i_subdirs);
free(sorted_d);
/* let's calculate dir size */
@@ -642,10 +650,12 @@ int erofs_iflush(struct erofs_inode *inode)
nlink_1 = false;
nb = (union erofs_inode_i_nb){};
}
+ fmt = S_ISDIR(inode->i_mode) && inode->dot_omitted ?
+ 1 << EROFS_I_DOT_OMITTED_BIT : 0;
switch (inode->inode_isize) {
case sizeof(struct erofs_inode_compact):
- fmt = 0 | (inode->datalayout << 1);
+ fmt |= 0 | (inode->datalayout << 1);
u.dic.i_xattr_icount = cpu_to_le16(icount);
u.dic.i_mode = cpu_to_le16(inode->i_mode);
u.dic.i_nb.nlink = cpu_to_le16(inode->i_nlink);
@@ -670,7 +680,8 @@ int erofs_iflush(struct erofs_inode *inode)
u.dic.i_format = cpu_to_le16(fmt);
break;
case sizeof(struct erofs_inode_extended):
- u.die.i_format = cpu_to_le16(1 | (inode->datalayout << 1));
+ fmt |= 1 | (inode->datalayout << 1);
+ u.die.i_format = cpu_to_le16(fmt);
u.die.i_xattr_icount = cpu_to_le16(icount);
u.die.i_mode = cpu_to_le16(inode->i_mode);
u.die.i_nlink = cpu_to_le32(inode->i_nlink);
@@ -1543,13 +1554,17 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
/*
* if there're too many subdirs as compact form, set nlink=1
- * rather than upgrade to use extented form instead.
+ * rather than upgrade to use extented form instead if possible.
*/
if (i_nlink > USHRT_MAX &&
- dir->inode_isize == sizeof(struct erofs_inode_compact))
- dir->i_nlink = 1;
- else
+ dir->inode_isize == sizeof(struct erofs_inode_compact)) {
+ if (dir->dot_omitted)
+ dir->inode_isize = sizeof(struct erofs_inode_extended);
+ else
+ dir->i_nlink = 1;
+ } else {
dir->i_nlink = i_nlink;
+ }
return erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
diff --git a/lib/namei.c b/lib/namei.c
index ac14a20..4ccb8ff 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -91,8 +91,9 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
}
switch (vi->i_mode & S_IFMT) {
- case S_IFREG:
case S_IFDIR:
+ vi->dot_omitted = (ifmt >> EROFS_I_DOT_OMITTED_BIT) & 1;
+ case S_IFREG:
case S_IFLNK:
vi->u.i_blkaddr = le32_to_cpu(iu.startblk_lo);
break;
diff --git a/mkfs/main.c b/mkfs/main.c
index 2defa92..49a9eff 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -334,6 +334,16 @@ static int erofs_mkfs_feat_set_48bit(bool en, const char *val,
return 0;
}
+static int erofs_mkfs_feat_set_dot_omitted(bool en, const char *val,
+ unsigned int vallen)
+{
+ if (vallen)
+ return -EINVAL;
+
+ cfg.c_dot_omitted = en;
+ return 0;
+}
+
static struct {
char *feat;
int (*set)(bool en, const char *val, unsigned int len);
@@ -345,6 +355,7 @@ static struct {
{"dedupe", erofs_mkfs_feat_set_dedupe},
{"fragdedupe", erofs_mkfs_feat_set_fragdedupe},
{"48bit", erofs_mkfs_feat_set_48bit},
+ {"dot-omitted", erofs_mkfs_feat_set_dot_omitted},
{NULL, NULL},
};
@@ -1247,6 +1258,9 @@ int main(int argc, char **argv)
g_sbi.epoch = mkfs_time;
}
+ if (cfg.c_dot_omitted)
+ erofs_sb_set_48bit(&g_sbi);
+
err = erofs_dev_open(&g_sbi, cfg.c_img_path, O_RDWR |
(incremental_mode ? 0 : O_TRUNC));
if (err) {
--
2.43.5
More information about the Linux-erofs
mailing list