* [PATCH 1/4] fs/erofs: align the malloc'ed data
2026-03-23 13:42 [PATCH 0/4] fs/erofs: major alignment fixes Michael Walle
@ 2026-03-23 13:42 ` Michael Walle
2026-03-23 14:41 ` Gao Xiang
2026-03-23 13:42 ` [PATCH 2/4] fs/erofs: allocate data buffers on heap with alignment (1/3) Michael Walle
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Michael Walle @ 2026-03-23 13:42 UTC (permalink / raw)
To: Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot, Michael Walle
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). Use malloc_cache_aligned() to get
an aligned buffer.
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
fs/erofs/data.c | 11 ++++-------
fs/erofs/internal.h | 1 +
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index b58ec6fcc66..61dbae51a9a 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -319,15 +319,13 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
}
if (map.m_plen > bufsize) {
- char *tmp;
-
bufsize = map.m_plen;
- tmp = realloc(raw, bufsize);
- if (!tmp) {
+ free(raw);
+ raw = malloc_cache_aligned(bufsize);
+ if (!raw) {
ret = -ENOMEM;
break;
}
- raw = tmp;
}
ret = z_erofs_read_one_data(inode, &map, raw,
@@ -336,8 +334,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
if (ret < 0)
break;
}
- if (raw)
- free(raw);
+ free(raw);
return ret < 0 ? ret : 0;
}
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 1875f37fcd2..13c862325a6 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -11,6 +11,7 @@
#include <linux/printk.h>
#include <linux/log2.h>
#include <inttypes.h>
+#include <memalign.h>
#include "erofs_fs.h"
#define erofs_err(fmt, ...) \
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 1/4] fs/erofs: align the malloc'ed data
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
0 siblings, 1 reply; 8+ messages in thread
From: Gao Xiang @ 2026-03-23 14:41 UTC (permalink / raw)
To: Michael Walle, Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot
Hi Michael,
On 2026/3/23 21:42, Michael Walle wrote:
> 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). Use malloc_cache_aligned() to get
> an aligned buffer.
Many thanks for the patch, I wonder if it's possible to
submit the patches to erofs-utils first (even make
malloc_cache_aligned() as another malloc() for example)?
Since I'd like to make u-boot codebase following
erofs-utils, but I don't think Jianan have the
bandwidth now, but if you have some use cases,
you could help syncing up a bit.
Or at least, let's keep these four patches in sync
between erofs-utils and u-boot.
Many thanks!
Gao Xiang
>
> Signed-off-by: Michael Walle <mwalle@kernel.org>
> ---
> fs/erofs/data.c | 11 ++++-------
> fs/erofs/internal.h | 1 +
> 2 files changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
> index b58ec6fcc66..61dbae51a9a 100644
> --- a/fs/erofs/data.c
> +++ b/fs/erofs/data.c
> @@ -319,15 +319,13 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
> }
>
> if (map.m_plen > bufsize) {
> - char *tmp;
> -
> bufsize = map.m_plen;
> - tmp = realloc(raw, bufsize);
> - if (!tmp) {
> + free(raw);
> + raw = malloc_cache_aligned(bufsize);
> + if (!raw) {
> ret = -ENOMEM;
> break;
> }
> - raw = tmp;
> }
>
> ret = z_erofs_read_one_data(inode, &map, raw,
> @@ -336,8 +334,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
> if (ret < 0)
> break;
> }
> - if (raw)
> - free(raw);
> + free(raw);
> return ret < 0 ? ret : 0;
> }
>
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 1875f37fcd2..13c862325a6 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -11,6 +11,7 @@
> #include <linux/printk.h>
> #include <linux/log2.h>
> #include <inttypes.h>
> +#include <memalign.h>
> #include "erofs_fs.h"
>
> #define erofs_err(fmt, ...) \
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 1/4] fs/erofs: align the malloc'ed data
2026-03-23 14:41 ` Gao Xiang
@ 2026-03-23 15:08 ` Michael Walle
2026-03-23 15:13 ` Gao Xiang
0 siblings, 1 reply; 8+ messages in thread
From: Michael Walle @ 2026-03-23 15:08 UTC (permalink / raw)
To: Gao Xiang, Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot
[-- Attachment #1: Type: text/plain, Size: 3047 bytes --]
Hi Gao,
On Mon Mar 23, 2026 at 3:41 PM CET, Gao Xiang wrote:
> Hi Michael,
>
> On 2026/3/23 21:42, Michael Walle wrote:
>> 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). Use malloc_cache_aligned() to get
>> an aligned buffer.
>
> Many thanks for the patch, I wonder if it's possible to
> submit the patches to erofs-utils first (even make
> malloc_cache_aligned() as another malloc() for example)?
>
> Since I'd like to make u-boot codebase following
> erofs-utils, but I don't think Jianan have the
> bandwidth now, but if you have some use cases,
> you could help syncing up a bit.
Sorry, I don't have the bandwidth neither. But now I see where all
this is coming from. In userspace, you have much less (or none at
all) restrictions. So not sure, if that even makes sense to share. As
you've already pointed out the malloc_cache_aligned() would have to
be changed (back!) to malloc() again.
> Or at least, let's keep these four patches in sync
> between erofs-utils and u-boot.
Not sure what a DMA alignment has to do with userspace, or do you
mean moving all the block data from stack to heap?
This is more or less the result from an internal evaluation. You (or
anybody else) might take it - or leave it.
Do you share code between linux and erofs-utils, too? How does that
work?
Thanks,
-michael
>
> Many thanks!
> Gao Xiang
>
>>
>> Signed-off-by: Michael Walle <mwalle@kernel.org>
>> ---
>> fs/erofs/data.c | 11 ++++-------
>> fs/erofs/internal.h | 1 +
>> 2 files changed, 5 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
>> index b58ec6fcc66..61dbae51a9a 100644
>> --- a/fs/erofs/data.c
>> +++ b/fs/erofs/data.c
>> @@ -319,15 +319,13 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
>> }
>>
>> if (map.m_plen > bufsize) {
>> - char *tmp;
>> -
>> bufsize = map.m_plen;
>> - tmp = realloc(raw, bufsize);
>> - if (!tmp) {
>> + free(raw);
>> + raw = malloc_cache_aligned(bufsize);
>> + if (!raw) {
>> ret = -ENOMEM;
>> break;
>> }
>> - raw = tmp;
>> }
>>
>> ret = z_erofs_read_one_data(inode, &map, raw,
>> @@ -336,8 +334,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
>> if (ret < 0)
>> break;
>> }
>> - if (raw)
>> - free(raw);
>> + free(raw);
>> return ret < 0 ? ret : 0;
>> }
>>
>> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
>> index 1875f37fcd2..13c862325a6 100644
>> --- a/fs/erofs/internal.h
>> +++ b/fs/erofs/internal.h
>> @@ -11,6 +11,7 @@
>> #include <linux/printk.h>
>> #include <linux/log2.h>
>> #include <inttypes.h>
>> +#include <memalign.h>
>> #include "erofs_fs.h"
>>
>> #define erofs_err(fmt, ...) \
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 1/4] fs/erofs: align the malloc'ed data
2026-03-23 15:08 ` Michael Walle
@ 2026-03-23 15:13 ` Gao Xiang
0 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2026-03-23 15:13 UTC (permalink / raw)
To: Michael Walle, Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot
On 2026/3/23 23:08, Michael Walle wrote:
> Hi Gao,
>
> On Mon Mar 23, 2026 at 3:41 PM CET, Gao Xiang wrote:
>> Hi Michael,
>>
>> On 2026/3/23 21:42, Michael Walle wrote:
>>> 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). Use malloc_cache_aligned() to get
>>> an aligned buffer.
>>
>> Many thanks for the patch, I wonder if it's possible to
>> submit the patches to erofs-utils first (even make
>> malloc_cache_aligned() as another malloc() for example)?
>>
>> Since I'd like to make u-boot codebase following
>> erofs-utils, but I don't think Jianan have the
>> bandwidth now, but if you have some use cases,
>> you could help syncing up a bit.
>
> Sorry, I don't have the bandwidth neither. But now I see where all
> this is coming from. In userspace, you have much less (or none at
> all) restrictions. So not sure, if that even makes sense to share. As
> you've already pointed out the malloc_cache_aligned() would have to
> be changed (back!) to malloc() again.
But it can align the codebase between erofs-utils and u-boot,
in that way, all potential bug fixes can be addressed
together.
>
>> Or at least, let's keep these four patches in sync
>> between erofs-utils and u-boot.
>
> Not sure what a DMA alignment has to do with userspace, or do you
> mean moving all the block data from stack to heap?
I think if it's not complex, we could do that, but if some
case is very hard, we can leave them alone.
>
> This is more or less the result from an internal evaluation. You (or
> anybody else) might take it - or leave it.
>
> Do you share code between linux and erofs-utils, too? How does that
> work?
Only the majority of metadata parsing logic is shared by
the linux kernel and erofs-utils, much like XFS shares
libxfs between the kernel and xfsprogs.
Thanks,
Gao Xiang
>
> Thanks,
> -michael
>
>>
>> Many thanks!
>> Gao Xiang
>>
>>>
>>> Signed-off-by: Michael Walle <mwalle@kernel.org>
>>> ---
>>> fs/erofs/data.c | 11 ++++-------
>>> fs/erofs/internal.h | 1 +
>>> 2 files changed, 5 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
>>> index b58ec6fcc66..61dbae51a9a 100644
>>> --- a/fs/erofs/data.c
>>> +++ b/fs/erofs/data.c
>>> @@ -319,15 +319,13 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
>>> }
>>>
>>> if (map.m_plen > bufsize) {
>>> - char *tmp;
>>> -
>>> bufsize = map.m_plen;
>>> - tmp = realloc(raw, bufsize);
>>> - if (!tmp) {
>>> + free(raw);
>>> + raw = malloc_cache_aligned(bufsize);
>>> + if (!raw) {
>>> ret = -ENOMEM;
>>> break;
>>> }
>>> - raw = tmp;
>>> }
>>>
>>> ret = z_erofs_read_one_data(inode, &map, raw,
>>> @@ -336,8 +334,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
>>> if (ret < 0)
>>> break;
>>> }
>>> - if (raw)
>>> - free(raw);
>>> + free(raw);
>>> return ret < 0 ? ret : 0;
>>> }
>>>
>>> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
>>> index 1875f37fcd2..13c862325a6 100644
>>> --- a/fs/erofs/internal.h
>>> +++ b/fs/erofs/internal.h
>>> @@ -11,6 +11,7 @@
>>> #include <linux/printk.h>
>>> #include <linux/log2.h>
>>> #include <inttypes.h>
>>> +#include <memalign.h>
>>> #include "erofs_fs.h"
>>>
>>> #define erofs_err(fmt, ...) \
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] fs/erofs: allocate data buffers on heap with alignment (1/3)
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 13:42 ` Michael Walle
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
3 siblings, 0 replies; 8+ messages in thread
From: Michael Walle @ 2026-03-23 13:42 UTC (permalink / raw)
To: Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot, Michael Walle
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
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 3/4] fs/erofs: allocate data buffers on heap with alignment (2/3)
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 13:42 ` [PATCH 2/4] fs/erofs: allocate data buffers on heap with alignment (1/3) Michael Walle
@ 2026-03-23 13:42 ` Michael Walle
2026-03-23 13:42 ` [PATCH 4/4] fs/erofs: allocate data buffers on heap with alignment (3/3) Michael Walle
3 siblings, 0 replies; 8+ messages in thread
From: Michael Walle @ 2026-03-23 13:42 UTC (permalink / raw)
To: Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot, Michael Walle
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 allocates
the inode buffer on the heap. Before, if there was an extended inode,
the buffer was read incrementally. Now, as we need to have an aligned
buffer, the first part is just read again to keep the original buffer
address.
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
fs/erofs/namei.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c
index b493ef97a09..7ce62955540 100644
--- a/fs/erofs/namei.c
+++ b/fs/erofs/namei.c
@@ -13,14 +13,20 @@ static dev_t erofs_new_decode_dev(u32 dev)
int erofs_read_inode_from_disk(struct erofs_inode *vi)
{
int ret, ifmt;
- char buf[sizeof(struct erofs_inode_extended)];
+ char *buf;
struct erofs_inode_compact *dic;
struct erofs_inode_extended *die;
const erofs_off_t inode_loc = iloc(vi->nid);
+ buf = malloc_cache_aligned(sizeof(struct erofs_inode_extended));
+ if (!buf)
+ return -ENOMEM;
+
ret = erofs_dev_read(0, buf, inode_loc, sizeof(*dic));
- if (ret < 0)
+ if (ret < 0) {
+ free(buf);
return -EIO;
+ }
dic = (struct erofs_inode_compact *)buf;
ifmt = le16_to_cpu(dic->i_format);
@@ -29,17 +35,18 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
erofs_err("unsupported datalayout %u of nid %llu",
vi->datalayout, vi->nid | 0ULL);
+ free(buf);
return -EOPNOTSUPP;
}
switch (erofs_inode_version(ifmt)) {
case EROFS_INODE_LAYOUT_EXTENDED:
vi->inode_isize = sizeof(struct erofs_inode_extended);
- ret = erofs_dev_read(0, buf + sizeof(*dic),
- inode_loc + sizeof(*dic),
- sizeof(*die) - sizeof(*dic));
- if (ret < 0)
+ ret = erofs_dev_read(0, buf, inode_loc, sizeof(*die));
+ if (ret < 0) {
+ free(buf);
return -EIO;
+ }
die = (struct erofs_inode_extended *)buf;
vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
@@ -113,6 +120,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
default:
erofs_err("unsupported on-disk inode version %u of nid %llu",
erofs_inode_version(ifmt), vi->nid | 0ULL);
+ free(buf);
return -EOPNOTSUPP;
}
@@ -121,6 +129,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
if (vi->u.chunkformat & ~EROFS_CHUNK_FORMAT_ALL) {
erofs_err("unsupported chunk format %x of nid %llu",
vi->u.chunkformat, vi->nid | 0ULL);
+ free(buf);
return -EOPNOTSUPP;
}
vi->u.chunkbits = sbi.blkszbits +
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 4/4] fs/erofs: allocate data buffers on heap with alignment (3/3)
2026-03-23 13:42 [PATCH 0/4] fs/erofs: major alignment fixes Michael Walle
` (2 preceding siblings ...)
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 ` Michael Walle
3 siblings, 0 replies; 8+ messages in thread
From: Michael Walle @ 2026-03-23 13:42 UTC (permalink / raw)
To: Huang Jianan, Tom Rini; +Cc: linux-erofs, u-boot, Michael Walle
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 handles the
"struct erofs_map_blocks" which itself contains a data buffer. Add some
helpers to alloc and free the struct because the data buffer will now be
malloc'ed separately.
Signed-off-by: Michael Walle <mwalle@kernel.org>
---
fs/erofs/data.c | 103 +++++++++++++++++++++++++++++---------------
fs/erofs/internal.h | 4 +-
fs/erofs/zmap.c | 29 ++++++++++---
3 files changed, 94 insertions(+), 42 deletions(-)
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 2fe345d80ee..d10c00fe9f3 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -174,32 +174,60 @@ int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset,
return 0;
}
+struct erofs_map_blocks *erofs_alloc_map_blocks(void)
+{
+ struct erofs_map_blocks *map;
+
+ map = malloc(sizeof(struct erofs_map_blocks));
+ if (!map)
+ return NULL;
+
+ memset(map, 0, sizeof(struct erofs_map_blocks));
+ map->index = UINT_MAX;
+
+ map->mpage = malloc_cache_aligned(EROFS_MAX_BLOCK_SIZE);
+ if (!map->mpage) {
+ free(map);
+ return NULL;
+ }
+
+ return map;
+}
+
+void erofs_free_map_blocks(struct erofs_map_blocks *map)
+{
+ free(map->mpage);
+ free(map);
+}
+
static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
erofs_off_t size, erofs_off_t offset)
{
- struct erofs_map_blocks map = {
- .index = UINT_MAX,
- };
+ struct erofs_map_blocks *map;
int ret;
erofs_off_t ptr = offset;
+ map = erofs_alloc_map_blocks();
+ if (!map)
+ return -ENOMEM;
+
while (ptr < offset + size) {
char *const estart = buffer + ptr - offset;
erofs_off_t eend, moff = 0;
- map.m_la = ptr;
- ret = erofs_map_blocks(inode, &map, 0);
+ map->m_la = ptr;
+ ret = erofs_map_blocks(inode, map, 0);
if (ret)
- return ret;
+ goto out;
- DBG_BUGON(map.m_plen != map.m_llen);
+ DBG_BUGON(map->m_plen != map->m_llen);
/* trim extent */
- eend = min(offset + size, map.m_la + map.m_llen);
- DBG_BUGON(ptr < map.m_la);
+ eend = min(offset + size, map->m_la + map->m_llen);
+ DBG_BUGON(ptr < map->m_la);
- if (!(map.m_flags & EROFS_MAP_MAPPED)) {
- if (!map.m_llen) {
+ if (!(map->m_flags & EROFS_MAP_MAPPED)) {
+ if (!map->m_llen) {
/* reached EOF */
memset(estart, 0, offset + size - ptr);
ptr = offset + size;
@@ -210,17 +238,21 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
continue;
}
- if (ptr > map.m_la) {
- moff = ptr - map.m_la;
- map.m_la = ptr;
+ if (ptr > map->m_la) {
+ moff = ptr - map->m_la;
+ map->m_la = ptr;
}
- ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la);
+ ret = erofs_read_one_data(map, estart, moff, eend - map->m_la);
if (ret)
- return ret;
+ goto out;
ptr = eend;
}
- return 0;
+
+ ret = 0;
+out:
+ erofs_free_map_blocks(map);
+ return ret;
}
int z_erofs_read_one_data(struct erofs_inode *inode,
@@ -282,19 +314,21 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
erofs_off_t size, erofs_off_t offset)
{
erofs_off_t end, length, skip;
- struct erofs_map_blocks map = {
- .index = UINT_MAX,
- };
+ struct erofs_map_blocks *map;
bool trimmed;
unsigned int bufsize = 0;
char *raw = NULL;
int ret = 0;
+ map = erofs_alloc_map_blocks();
+ if (!map)
+ return -ENOMEM;
+
end = offset + size;
while (end > offset) {
- map.m_la = end - 1;
+ map->m_la = end - 1;
- ret = z_erofs_map_blocks_iter(inode, &map, 0);
+ ret = z_erofs_map_blocks_iter(inode, map, 0);
if (ret)
break;
@@ -302,31 +336,31 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
* trim to the needed size if the returned extent is quite
* larger than requested, and set up partial flag as well.
*/
- if (end < map.m_la + map.m_llen) {
- length = end - map.m_la;
+ if (end < map->m_la + map->m_llen) {
+ length = end - map->m_la;
trimmed = true;
} else {
- DBG_BUGON(end != map.m_la + map.m_llen);
- length = map.m_llen;
+ DBG_BUGON(end != map->m_la + map->m_llen);
+ length = map->m_llen;
trimmed = false;
}
- if (map.m_la < offset) {
- skip = offset - map.m_la;
+ if (map->m_la < offset) {
+ skip = offset - map->m_la;
end = offset;
} else {
skip = 0;
- end = map.m_la;
+ end = map->m_la;
}
- if (!(map.m_flags & EROFS_MAP_MAPPED)) {
+ if (!(map->m_flags & EROFS_MAP_MAPPED)) {
memset(buffer + end - offset, 0, length - skip);
- end = map.m_la;
+ end = map->m_la;
continue;
}
- if (map.m_plen > bufsize) {
- bufsize = map.m_plen;
+ if (map->m_plen > bufsize) {
+ bufsize = map->m_plen;
free(raw);
raw = malloc_cache_aligned(bufsize);
if (!raw) {
@@ -335,13 +369,14 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
}
}
- ret = z_erofs_read_one_data(inode, &map, raw,
+ ret = z_erofs_read_one_data(inode, map, raw,
buffer + end - offset, skip, length,
trimmed);
if (ret < 0)
break;
}
free(raw);
+ erofs_free_map_blocks(map);
return ret < 0 ? ret : 0;
}
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 13c862325a6..2e471d66c7d 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -291,7 +291,7 @@ enum {
#define EROFS_MAP_PARTIAL_REF (1 << BH_Partialref)
struct erofs_map_blocks {
- char mpage[EROFS_MAX_BLOCK_SIZE];
+ char *mpage;
erofs_off_t m_pa, m_la;
u64 m_plen, m_llen;
@@ -367,6 +367,8 @@ static inline int erofs_get_occupied_size(const struct erofs_inode *inode,
}
/* data.c */
+struct erofs_map_blocks *erofs_alloc_map_blocks(void);
+void erofs_free_map_blocks(struct erofs_map_blocks *map);
int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer,
size_t buffer_size);
int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size);
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index 1ded934a5d7..3060b2e9ec6 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -75,28 +75,43 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
}
if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) {
- struct erofs_map_blocks map = { .index = UINT_MAX };
+ struct erofs_map_blocks *map;
+
+ map = erofs_alloc_map_blocks();
+ if (!map) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
vi->idata_size = le16_to_cpu(h->h_idata_size);
- ret = z_erofs_do_map_blocks(vi, &map,
+ ret = z_erofs_do_map_blocks(vi, map,
EROFS_GET_BLOCKS_FINDTAIL);
- if (!map.m_plen ||
- erofs_blkoff(map.m_pa) + map.m_plen > erofs_blksiz()) {
+ if (!map->m_plen ||
+ erofs_blkoff(map->m_pa) + map->m_plen > erofs_blksiz()) {
erofs_err("invalid tail-packing pclustersize %llu",
- map.m_plen | 0ULL);
+ map->m_plen | 0ULL);
ret = -EFSCORRUPTED;
+ erofs_free_map_blocks(map);
goto err_out;
}
+ erofs_free_map_blocks(map);
if (ret < 0)
goto err_out;
}
if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER &&
!(h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT)) {
- struct erofs_map_blocks map = { .index = UINT_MAX };
+ struct erofs_map_blocks *map;
+
+ map = erofs_alloc_map_blocks();
+ if (!map) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
vi->fragmentoff = le32_to_cpu(h->h_fragmentoff);
- ret = z_erofs_do_map_blocks(vi, &map,
+ ret = z_erofs_do_map_blocks(vi, map,
EROFS_GET_BLOCKS_FINDTAIL);
+ erofs_free_map_blocks(map);
if (ret < 0)
goto err_out;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread