[PATCH 2/2] erofs-utils: lib: refine on-disk meta arrangement again
Gao Xiang
hsiangkao at linux.alibaba.com
Sat Apr 6 16:37:17 AEDT 2024
Most workloads like `ls -R` and `tar -c` traverse in depth-first mode.
However, it still arranges sub-directory inodes more closely so that
it isn't a simple reversion compared to pre-BFS old versions.
Also the build performance out of linux-6.1.53 source code is greatly
improved by 91.2% (33.040s->2.861s) as well as the new image size is
decreased by 0.0094% (120 KiB), which is minor.
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
lib/inode.c | 192 +++++++++++++++++++++++++---------------------------
1 file changed, 91 insertions(+), 101 deletions(-)
diff --git a/lib/inode.c b/lib/inode.c
index f419f3c..79626ab 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -162,7 +162,8 @@ struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
strncpy(d->name, name, EROFS_NAME_LEN - 1);
d->name[EROFS_NAME_LEN - 1] = '\0';
-
+ d->inode = NULL;
+ d->type = EROFS_FT_UNKNOWN;
list_add_tail(&d->d_child, &parent->i_subdirs);
return d;
}
@@ -1131,7 +1132,7 @@ static int erofs_mkfs_handle_nondirectory(struct erofs_inode *inode)
return 0;
}
-static int erofs_mkfs_handle_directory(struct erofs_inode *dir, struct list_head *dirs)
+static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
{
DIR *_dir;
struct dirent *dp;
@@ -1147,18 +1148,28 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir, struct list_head
}
nr_subdirs = 0;
+ i_nlink = 0;
while (1) {
+ char buf[PATH_MAX];
+ struct erofs_inode *inode;
+
/*
* set errno to 0 before calling readdir() in order to
* distinguish end of stream and from an error.
*/
errno = 0;
dp = readdir(_dir);
- if (!dp)
- break;
+ if (!dp) {
+ if (!errno)
+ break;
+ ret = -errno;
+ goto err_closedir;
+ }
- if (is_dot_dotdot(dp->d_name))
+ if (is_dot_dotdot(dp->d_name)) {
+ ++i_nlink;
continue;
+ }
/* skip if it's a exclude file */
if (erofs_is_exclude_path(dir->i_srcpath, dp->d_name))
@@ -1169,70 +1180,28 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir, struct list_head
ret = PTR_ERR(d);
goto err_closedir;
}
- nr_subdirs++;
- }
-
- if (errno) {
- ret = -errno;
- goto err_closedir;
- }
- closedir(_dir);
-
- ret = erofs_prepare_dir_file(dir, nr_subdirs);
- if (ret)
- return ret;
-
- ret = erofs_prepare_inode_buffer(dir);
- if (ret)
- return ret;
- dir->bh->op = &erofs_skip_write_bhops;
-
- if (IS_ROOT(dir))
- erofs_fixup_meta_blkaddr(dir);
-
- i_nlink = 0;
- list_for_each_entry(d, &dir->i_subdirs, d_child) {
- char buf[PATH_MAX];
- unsigned char ftype;
- struct erofs_inode *inode;
-
- if (is_dot_dotdot(d->name)) {
- ++i_nlink;
- continue;
- }
- ret = snprintf(buf, PATH_MAX, "%s/%s",
- dir->i_srcpath, d->name);
- if (ret < 0 || ret >= PATH_MAX) {
- /* ignore the too long path */
- goto fail;
- }
+ ret = snprintf(buf, PATH_MAX, "%s/%s", dir->i_srcpath, d->name);
+ if (ret < 0 || ret >= PATH_MAX)
+ goto err_closedir;
inode = erofs_iget_from_path(buf, true);
-
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
-fail:
- d->inode = NULL;
- d->type = EROFS_FT_UNKNOWN;
- return ret;
- }
-
- /* a hardlink to the existed inode */
- if (inode->i_parent) {
- ++inode->i_nlink;
- } else {
- inode->i_parent = dir;
- erofs_igrab(inode);
- list_add_tail(&inode->i_subdirs, dirs);
+ goto err_closedir;
}
- ftype = erofs_mode_to_ftype(inode->i_mode);
- i_nlink += (ftype == EROFS_FT_DIR);
d->inode = inode;
- d->type = ftype;
- erofs_info("file %s/%s dumped (type %u)",
- dir->i_srcpath, d->name, d->type);
+ d->type = erofs_mode_to_ftype(inode->i_mode);
+ i_nlink += S_ISDIR(inode->i_mode);
+ erofs_dbg("file %s added (type %u)", buf, d->type);
+ nr_subdirs++;
}
+ closedir(_dir);
+
+ ret = erofs_prepare_dir_file(dir, nr_subdirs);
+ if (ret)
+ return ret;
+
/*
* if there're too many subdirs as compact form, set nlink=1
* rather than upgrade to use extented form instead.
@@ -1242,6 +1211,11 @@ fail:
dir->i_nlink = 1;
else
dir->i_nlink = i_nlink;
+
+ ret = erofs_prepare_inode_buffer(dir);
+ if (ret)
+ return ret;
+ dir->bh->op = &erofs_skip_write_bhops;
return 0;
err_closedir:
@@ -1249,10 +1223,16 @@ err_closedir:
return ret;
}
-static int erofs_mkfs_build_tree(struct erofs_inode *inode, struct list_head *dirs)
+static int erofs_mkfs_build_tree(struct erofs_inode *inode)
{
+ char *trimmed;
int ret;
+ trimmed = erofs_trim_for_progressinfo(erofs_fspath(inode->i_srcpath),
+ sizeof("Processing ...") - 1);
+ erofs_update_progressinfo("Processing %s ...", trimmed);
+ free(trimmed);
+
ret = erofs_scan_file_xattrs(inode);
if (ret < 0)
return ret;
@@ -1262,60 +1242,70 @@ static int erofs_mkfs_build_tree(struct erofs_inode *inode, struct list_head *di
return ret;
if (!S_ISDIR(inode->i_mode))
- return erofs_mkfs_handle_nondirectory(inode);
- return erofs_mkfs_handle_directory(inode, dirs);
+ ret = erofs_mkfs_handle_nondirectory(inode);
+ else
+ ret = erofs_mkfs_handle_directory(inode);
+ erofs_info("file %s dumped", erofs_fspath(inode->i_srcpath));
+ return ret;
}
struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path)
{
- LIST_HEAD(dirs);
- struct erofs_inode *inode, *root, *dumpdir;
+ struct erofs_inode *root, *dumpdir;
+ int err;
root = erofs_iget_from_path(path, true);
if (IS_ERR(root))
return root;
- (void)erofs_igrab(root);
root->i_parent = root; /* rootdir mark */
- list_add(&root->i_subdirs, &dirs);
+ root->next_dirwrite = NULL;
+ (void)erofs_igrab(root);
+ dumpdir = root;
+
+ err = erofs_mkfs_build_tree(root);
+ if (err)
+ return ERR_PTR(err);
+ erofs_fixup_meta_blkaddr(root);
- dumpdir = NULL;
do {
int err;
- char *trimmed;
-
- inode = list_first_entry(&dirs, struct erofs_inode, i_subdirs);
- list_del(&inode->i_subdirs);
- init_list_head(&inode->i_subdirs);
-
- trimmed = erofs_trim_for_progressinfo(
- erofs_fspath(inode->i_srcpath),
- sizeof("Processing ...") - 1);
- erofs_update_progressinfo("Processing %s ...", trimmed);
- free(trimmed);
-
- err = erofs_mkfs_build_tree(inode, &dirs);
- if (err) {
- root = ERR_PTR(err);
- break;
+ struct erofs_inode *dir = dumpdir;
+ /* used for adding sub-directories in reverse order due to FIFO */
+ struct erofs_inode *head, **last = &head;
+ struct erofs_dentry *d;
+
+ dumpdir = dir->next_dirwrite;
+ list_for_each_entry(d, &dir->i_subdirs, d_child) {
+ struct erofs_inode *inode = d->inode;
+
+ if (is_dot_dotdot(d->name))
+ continue;
+ if (inode->i_parent) {
+ ++inode->i_nlink;
+ } else {
+ inode->i_parent = dir;
+
+ err = erofs_mkfs_build_tree(inode);
+ if (err) {
+ root = ERR_PTR(err);
+ break;
+ }
+ if (S_ISDIR(inode->i_mode)) {
+ *last = inode;
+ last = &inode->next_dirwrite;
+ (void)erofs_igrab(inode);
+ }
+ }
}
+ *last = dumpdir; /* fixup the last (or the only) one */
+ dumpdir = head;
+ erofs_write_dir_file(dir);
+ erofs_write_tail_end(dir);
+ dir->bh->op = &erofs_write_inode_bhops;
+ erofs_iput(dir);
+ } while (dumpdir);
- if (S_ISDIR(inode->i_mode)) {
- inode->next_dirwrite = dumpdir;
- dumpdir = inode;
- } else {
- erofs_iput(inode);
- }
- } while (!list_empty(&dirs));
-
- while (dumpdir) {
- inode = dumpdir;
- erofs_write_dir_file(inode);
- erofs_write_tail_end(inode);
- inode->bh->op = &erofs_write_inode_bhops;
- dumpdir = inode->next_dirwrite;
- erofs_iput(inode);
- }
return root;
}
--
2.39.3
More information about the Linux-erofs
mailing list