From: Michael Walle <mwalle@kernel.org>
To: Huang Jianan <jnhuang95@gmail.com>, Tom Rini <trini@konsulko.com>
Cc: linux-erofs@lists.ozlabs.org, u-boot@lists.denx.de,
Michael Walle <mwalle@kernel.org>
Subject: [PATCH 2/4] fs/erofs: allocate data buffers on heap with alignment (1/3)
Date: Mon, 23 Mar 2026 14:42:18 +0100 [thread overview]
Message-ID: <20260323134305.2675822-3-mwalle@kernel.org> (raw)
In-Reply-To: <20260323134305.2675822-1-mwalle@kernel.org>
The data buffers are used to transfer from or to hardware peripherals.
Often, there are restrictions on addresses, i.e. they have to be aligned
at a certain size. Thus, allocate the data on the heap instead of the
stack (at a random address alignment).
This will also have the benefit, that large data (4k) isn't eating up
the stack.
The actual change is split across multiple patches. This one contains
all the simple changes.
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
fs/erofs/data.c | 11 +++++++++--
fs/erofs/fs.c | 14 ++++++++++++--
fs/erofs/namei.c | 26 +++++++++++++++++++-------
fs/erofs/super.c | 40 +++++++++++++++++++++++++++++-----------
fs/erofs/zmap.c | 32 ++++++++++++++++++++++----------
5 files changed, 91 insertions(+), 32 deletions(-)
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 61dbae51a9a..2fe345d80ee 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -55,12 +55,16 @@ int erofs_map_blocks(struct erofs_inode *inode,
{
struct erofs_inode *vi = inode;
struct erofs_inode_chunk_index *idx;
- u8 buf[EROFS_MAX_BLOCK_SIZE];
+ u8 *buf;
u64 chunknr;
unsigned int unit;
erofs_off_t pos;
int err = 0;
+ buf = malloc_cache_aligned(EROFS_MAX_BLOCK_SIZE);
+ if (!buf)
+ return -ENOMEM;
+
map->m_deviceid = 0;
if (map->m_la >= inode->i_size) {
/* leave out-of-bound access unmapped */
@@ -82,8 +86,10 @@ int erofs_map_blocks(struct erofs_inode *inode,
vi->xattr_isize, unit) + unit * chunknr;
err = erofs_blk_read(buf, erofs_blknr(pos), 1);
- if (err < 0)
+ if (err < 0) {
+ free(buf);
return -EIO;
+ }
map->m_la = chunknr << vi->u.chunkbits;
map->m_plen = min_t(erofs_off_t, 1UL << vi->u.chunkbits,
@@ -116,6 +122,7 @@ int erofs_map_blocks(struct erofs_inode *inode,
}
out:
map->m_llen = map->m_plen;
+ free(buf);
return err;
}
diff --git a/fs/erofs/fs.c b/fs/erofs/fs.c
index db86928511e..f44af001e96 100644
--- a/fs/erofs/fs.c
+++ b/fs/erofs/fs.c
@@ -55,7 +55,7 @@ struct erofs_dir_stream {
struct fs_dirent dirent;
struct erofs_inode inode;
- char dblk[EROFS_MAX_BLOCK_SIZE];
+ char *dblk;
unsigned int maxsize, de_end;
erofs_off_t pos;
};
@@ -69,7 +69,7 @@ static int erofs_readlink(struct erofs_inode *vi)
if (__builtin_add_overflow(vi->i_size, 1, &alloc_size))
return -EFSCORRUPTED;
- target = malloc(alloc_size);
+ target = malloc_cache_aligned(alloc_size);
if (!target)
return -ENOMEM;
target[vi->i_size] = '\0';
@@ -96,6 +96,12 @@ int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
if (!dirs)
return -ENOMEM;
+ dirs->dblk = malloc_cache_aligned(EROFS_MAX_BLOCK_SIZE);
+ if (!dirs->dblk) {
+ free(dirs);
+ return -ENOMEM;
+ }
+
err = erofs_ilookup(filename, &dirs->inode);
if (err)
goto err_out;
@@ -113,6 +119,7 @@ int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
*dirsp = (struct fs_dir_stream *)dirs;
return 0;
err_out:
+ free(dirs->dblk);
free(dirs);
return err;
}
@@ -198,6 +205,9 @@ int erofs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
void erofs_closedir(struct fs_dir_stream *fs_dirs)
{
+ struct erofs_dir_stream *dirs = (struct erofs_dir_stream *)fs_dirs;
+
+ free(dirs->dblk);
free(fs_dirs);
}
diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c
index bde995f1bf2..b493ef97a09 100644
--- a/fs/erofs/namei.c
+++ b/fs/erofs/namei.c
@@ -182,7 +182,7 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
{
erofs_nid_t nid = nd->nid;
int ret;
- char buf[EROFS_MAX_BLOCK_SIZE];
+ char *buf;
struct erofs_inode vi = { .nid = nid };
erofs_off_t offset;
@@ -190,6 +190,10 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
if (ret)
return ret;
+ buf = malloc_cache_aligned(EROFS_MAX_BLOCK_SIZE);
+ if (!buf)
+ return -ENOMEM;
+
offset = 0;
while (offset < vi.i_size) {
erofs_off_t maxsize = min_t(erofs_off_t,
@@ -199,28 +203,36 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
ret = erofs_pread(&vi, buf, maxsize, offset);
if (ret)
- return ret;
+ goto out;
nameoff = le16_to_cpu(de->nameoff);
if (nameoff < sizeof(struct erofs_dirent) ||
nameoff >= erofs_blksiz()) {
erofs_err("invalid de[0].nameoff %u @ nid %llu",
nameoff, nid | 0ULL);
- return -EFSCORRUPTED;
+ ret = -EFSCORRUPTED;
+ goto out;
}
de = find_target_dirent(nid, buf, name, len,
nameoff, maxsize);
- if (IS_ERR(de))
- return PTR_ERR(de);
+ if (IS_ERR(de)) {
+ ret = PTR_ERR(de);
+ goto out;
+ }
if (de) {
nd->nid = le64_to_cpu(de->nid);
- return 0;
+ ret = 0;
+ goto out;
}
offset += maxsize;
}
- return -ENOENT;
+
+ ret = -ENOENT;
+out:
+ free(buf);
+ return ret;
}
static int link_path_walk(const char *name, struct nameidata *nd)
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index d405d488fd2..af6953b5ed5 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -43,40 +43,54 @@ static int erofs_init_devices(struct erofs_sb_info *sbi,
if (!sbi->devs)
return -ENOMEM;
pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
+
+ struct erofs_deviceslot *dis;
+
+ dis = malloc_cache_aligned(sizeof(*dis));
+ if (!dis)
+ return -ENOMEM;
+
for (i = 0; i < ondisk_extradevs; ++i) {
- struct erofs_deviceslot dis;
int ret;
- ret = erofs_dev_read(0, &dis, pos, sizeof(dis));
+ ret = erofs_dev_read(0, dis, pos, sizeof(*dis));
if (ret < 0) {
free(sbi->devs);
+ free(dis);
return ret;
}
- sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
- sbi->total_blocks += dis.blocks;
+ sbi->devs[i].mapped_blkaddr = dis->mapped_blkaddr;
+ sbi->total_blocks += dis->blocks;
pos += EROFS_DEVT_SLOT_SIZE;
}
+ free(dis);
+
return 0;
}
int erofs_read_superblock(void)
{
- u8 data[EROFS_MAX_BLOCK_SIZE];
+ u8 *data;
struct erofs_super_block *dsb;
int ret;
- ret = erofs_blk_read(data, 0, erofs_blknr(sizeof(data)));
+ data = malloc_cache_aligned(EROFS_MAX_BLOCK_SIZE);
+ if (!data)
+ return -ENOMEM;
+
+ ret = erofs_blk_read(data, 0, erofs_blknr(EROFS_MAX_BLOCK_SIZE));
if (ret < 0) {
erofs_dbg("cannot read erofs superblock: %d", ret);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
ret = -EINVAL;
if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
erofs_dbg("cannot find valid erofs superblock");
- return ret;
+ goto out;
}
sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
@@ -86,9 +100,9 @@ int erofs_read_superblock(void)
sbi.blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) {
erofs_err("blksize %llu isn't supported on this platform",
erofs_blksiz() | 0ULL);
- return ret;
+ goto out;
} else if (!check_layout_compatibility(&sbi, dsb)) {
- return ret;
+ goto out;
}
sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks);
@@ -104,5 +118,9 @@ int erofs_read_superblock(void)
sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
- return erofs_init_devices(&sbi, dsb);
+ ret = erofs_init_devices(&sbi, dsb);
+
+out:
+ free(data);
+ return ret;
}
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index 4f64258b004..1ded934a5d7 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -25,15 +25,21 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
int ret;
erofs_off_t pos;
struct z_erofs_map_header *h;
- char buf[sizeof(struct z_erofs_map_header)];
+ char *buf;
if (vi->flags & EROFS_I_Z_INITED)
return 0;
+ buf = malloc_cache_aligned(sizeof(struct z_erofs_map_header));
+ if (!buf)
+ return -ENOMEM;
+
pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
- ret = erofs_dev_read(0, buf, pos, sizeof(buf));
- if (ret < 0)
- return -EIO;
+ ret = erofs_dev_read(0, buf, pos, sizeof(struct z_erofs_map_header));
+ if (ret < 0) {
+ ret = -EIO;
+ goto err_out;
+ }
h = (struct z_erofs_map_header *)buf;
/*
@@ -54,7 +60,8 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
erofs_err("unknown compression format %u for nid %llu",
vi->z_algorithmtype[0], (unsigned long long)vi->nid);
- return -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
+ goto err_out;
}
vi->z_logical_clusterbits = sbi.blkszbits + (h->h_clusterbits & 7);
@@ -63,7 +70,8 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
erofs_err("big pcluster head1/2 of compact indexes should be consistent for nid %llu",
vi->nid * 1ULL);
- return -EFSCORRUPTED;
+ ret = -EFSCORRUPTED;
+ goto err_out;
}
if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) {
@@ -76,10 +84,11 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
erofs_blkoff(map.m_pa) + map.m_plen > erofs_blksiz()) {
erofs_err("invalid tail-packing pclustersize %llu",
map.m_plen | 0ULL);
- return -EFSCORRUPTED;
+ ret = -EFSCORRUPTED;
+ goto err_out;
}
if (ret < 0)
- return ret;
+ goto err_out;
}
if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER &&
!(h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT)) {
@@ -89,11 +98,14 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
ret = z_erofs_do_map_blocks(vi, &map,
EROFS_GET_BLOCKS_FINDTAIL);
if (ret < 0)
- return ret;
+ goto err_out;
}
out:
vi->flags |= EROFS_I_Z_INITED;
- return 0;
+ ret = 0;
+err_out:
+ free(buf);
+ return ret;
}
struct z_erofs_maprecorder {
--
2.47.3
next prev parent reply other threads:[~2026-03-23 13:43 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 13:42 [PATCH 0/4] fs/erofs: major alignment fixes Michael Walle
2026-03-23 13:42 ` [PATCH 1/4] fs/erofs: align the malloc'ed data Michael Walle
2026-03-23 14:41 ` Gao Xiang
2026-03-23 15:08 ` Michael Walle
2026-03-23 15:13 ` Gao Xiang
2026-03-23 13:42 ` Michael Walle [this message]
2026-03-23 13:42 ` [PATCH 3/4] fs/erofs: allocate data buffers on heap with alignment (2/3) Michael Walle
2026-03-23 13:42 ` [PATCH 4/4] fs/erofs: allocate data buffers on heap with alignment (3/3) Michael Walle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260323134305.2675822-3-mwalle@kernel.org \
--to=mwalle@kernel.org \
--cc=jnhuang95@gmail.com \
--cc=linux-erofs@lists.ozlabs.org \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox