[PATCH] erofs-utils: lib: dynamically sized `struct erofs_dentry`
Gao Xiang
hsiangkao at linux.alibaba.com
Wed Jan 15 13:27:20 AEDT 2025
- Reduced memory footprints;
- Optimize dname sorting and strlen(dname).
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
include/erofs/internal.h | 4 +++-
lib/inode.c | 29 +++++++++++++++++++++--------
2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 2edc1b4..596e363 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -314,15 +314,17 @@ static inline struct erofs_inode *erofs_parent_inode(struct erofs_inode *inode)
#define IS_ROOT(x) ((x) == erofs_parent_inode(x))
+#define EROFS_DENTRY_NAME_ALIGNMENT 4
struct erofs_dentry {
struct list_head d_child; /* child of parent list */
union {
struct erofs_inode *inode;
erofs_nid_t nid;
};
- char name[EROFS_NAME_LEN];
+ unsigned char namelen;
u8 type;
bool validnid;
+ char name[];
};
static inline bool is_dot_dotdot_len(const char *name, unsigned int len)
diff --git a/lib/inode.c b/lib/inode.c
index 7ee5d78..e51c0fc 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -160,14 +160,22 @@ unsigned int erofs_iput(struct erofs_inode *inode)
struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
const char *name)
{
- struct erofs_dentry *d = malloc(sizeof(*d));
+ unsigned int namelen = strlen(name);
+ unsigned int fsz = round_up(namelen + 1, EROFS_DENTRY_NAME_ALIGNMENT);
+ struct erofs_dentry *d;
+ if (namelen > EROFS_NAME_LEN) {
+ DBG_BUGON(1);
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+ d = malloc(sizeof(*d) + fsz);
if (!d)
return ERR_PTR(-ENOMEM);
- strncpy(d->name, name, EROFS_NAME_LEN - 1);
- d->name[EROFS_NAME_LEN - 1] = '\0';
+ memcpy(d->name, name, namelen);
+ memset(d->name + namelen, 0, fsz - namelen);
d->inode = NULL;
+ d->namelen = namelen;
d->type = EROFS_FT_UNKNOWN;
d->validnid = false;
list_add_tail(&d->d_child, &parent->i_subdirs);
@@ -208,10 +216,16 @@ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks)
static int comp_subdir(const void *a, const void *b)
{
const struct erofs_dentry *da, *db;
+ int commonlen, sign;
da = *((const struct erofs_dentry **)a);
db = *((const struct erofs_dentry **)b);
- return strcmp(da->name, db->name);
+ commonlen = min(round_up(da->namelen, EROFS_DENTRY_NAME_ALIGNMENT),
+ round_up(db->namelen, EROFS_DENTRY_NAME_ALIGNMENT));
+ sign = memcmp(da->name, db->name, commonlen);
+ if (sign)
+ return sign;
+ return cmpsgn(da->namelen, db->namelen);
}
int erofs_init_empty_dir(struct erofs_inode *dir)
@@ -260,7 +274,7 @@ static int erofs_prepare_dir_file(struct erofs_inode *dir,
/* let's calculate dir size */
list_for_each_entry(d, &dir->i_subdirs, d_child) {
- int len = strlen(d->name) + sizeof(struct erofs_dirent);
+ int len = d->namelen + sizeof(struct erofs_dirent);
if (erofs_blkoff(sbi, d_size) + len > erofs_blksiz(sbi))
d_size = round_up(d_size, erofs_blksiz(sbi));
@@ -283,7 +297,7 @@ static void fill_dirblock(char *buf, unsigned int size, unsigned int q,
/* write out all erofs_dirents + filenames */
while (head != end) {
- const unsigned int namelen = strlen(head->name);
+ const unsigned int namelen = head->namelen;
struct erofs_dirent d = {
.nid = cpu_to_le64(head->nid),
.nameoff = cpu_to_le16(q),
@@ -438,8 +452,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir)
return ret;
list_for_each_entry(d, &dir->i_subdirs, d_child) {
- const unsigned int len = strlen(d->name) +
- sizeof(struct erofs_dirent);
+ unsigned int len = d->namelen + sizeof(struct erofs_dirent);
/* XXX: a bit hacky, but to avoid another traversal */
if (d->validnid && d->type == EROFS_FT_DIR) {
--
2.43.5
More information about the Linux-erofs
mailing list