[PATCH] kernel: mtdsplit: add erofs support

Jonas Lochmann openwrt at jonaslochmann.de
Sun Dec 28 11:45:34 PST 2025


Previously, read only root partitions were not detected if they did
not use a squashfs filesystem.

Signed-off-by: Jonas Lochmann <openwrt at jonaslochmann.de>
---
 target/linux/generic/config-6.12              |   1 +
 .../files/drivers/mtd/mtdsplit/Kconfig        |   9 ++
 .../files/drivers/mtd/mtdsplit/Makefile       |   1 +
 .../files/drivers/mtd/mtdsplit/mtdsplit.c     |  13 ++
 .../files/drivers/mtd/mtdsplit/mtdsplit.h     |   2 +
 .../drivers/mtd/mtdsplit/mtdsplit_erofs.c     | 138 ++++++++++++++++++
 6 files changed, 164 insertions(+)
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_erofs.c

diff --git a/target/linux/generic/config-6.12 b/target/linux/generic/config-6.12
index fda78b422e..5e7d9af098 100644
--- a/target/linux/generic/config-6.12
+++ b/target/linux/generic/config-6.12
@@ -3913,6 +3913,7 @@ CONFIG_MTD_SPLIT=y
 # CONFIG_MTD_SPLIT_BCM_WFI_FW is not set
 # CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
 # CONFIG_MTD_SPLIT_ELF_FW is not set
+CONFIG_MTD_SPLIT_EROFS_ROOT=y
 # CONFIG_MTD_SPLIT_EVA_FW is not set
 # CONFIG_MTD_SPLIT_FIRMWARE is not set
 CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
index 396becf160..3d64428470 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
@@ -17,6 +17,15 @@ config MTD_SPLIT_SQUASHFS_ROOT
 	  offset and size of the unused portion of a rootfs partition
 	  containing a squashfs.
 
+config MTD_SPLIT_EROFS_ROOT
+	bool "EROFS based root partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+	help
+	  This provides a parsing function which allows to detect the
+	  offset and size of the unused portion of a rootfs partition
+	  containing a erofs.
+
 comment "Firmware partition parsers"
 
 config MTD_SPLIT_BCM63XX_FW
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
index b85ce5d21f..e6f3d2c3e4 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o
 obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o
 obj-$(CONFIG_MTD_SPLIT_SEIL_FW) += mtdsplit_seil.o
 obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o
+obj-$(CONFIG_MTD_SPLIT_EROFS_ROOT) += mtdsplit_erofs.o
 obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o
 obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o
 obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
index 42edb97c3a..ce72e8939b 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2009-2013 Gabor Juhos <juhosg at openwrt.org>
  * Copyright (C) 2012 Jonas Gorski <jogo at openwrt.org>
  * Copyright (C) 2013 Hauke Mehrtens <hauke at hauke-m.de>
+ * Copyright (C) 2025 Jonas Lochmann <openwrt at jonaslochmann.de>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -101,6 +102,18 @@ int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
 		return 0;
 	}
 
+	ret = mtd_read(mtd, offset + 1024, sizeof(magic), &retlen,
+		       (unsigned char *) &magic);
+
+	if (ret)
+		return ret;
+
+	if (magic == EROFS_SUPER_MAGIC_V1) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_EROFS;
+		return 0;
+	}
+
 	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
index 1d3f031733..8d9c084f28 100644
--- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
@@ -3,6 +3,7 @@
  * Copyright (C) 2009-2013 Gabor Juhos <juhosg at openwrt.org>
  * Copyright (C) 2012 Jonas Gorski <jogo at openwrt.org>
  * Copyright (C) 2013 Hauke Mehrtens <hauke at hauke-m.de>
+ * Copyright (C) 2025 Jonas Lochmann <openwrt at jonaslochmann.de>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -24,6 +25,7 @@ enum mtdsplit_part_type {
 	MTDSPLIT_PART_TYPE_SQUASHFS,
 	MTDSPLIT_PART_TYPE_JFFS2,
 	MTDSPLIT_PART_TYPE_UBI,
+	MTDSPLIT_PART_TYPE_EROFS,
 };
 
 #ifdef CONFIG_MTD_SPLIT
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_erofs.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_erofs.c
new file mode 100644
index 0000000000..bf1287cf59
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_erofs.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2009-2013 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jogo at openwrt.org>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke at hauke-m.de>
+ * Copyright (C) 2013 Felix Fietkau <nbd at nbd.name>
+ * Copyright (C) 2025 Jonas Lochmann <openwrt at jonaslochmann.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/magic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+struct erofs_super_block {
+        __le32 magic;
+        __le32 pad1[2];
+	__u8 blkszbits;
+	__u8 pad2;
+	__le16 pad3;
+	__le32 pad4[5];
+        __le32 blocks;
+};
+
+static int mtd_get_erofs_len(struct mtd_info *master,
+			     size_t offset,
+			     size_t *erofs_len)
+{
+	struct erofs_super_block sb;
+	size_t retlen, blksz;
+	int err;
+
+	err = mtd_read(master, offset + 1024, sizeof(sb), &retlen, (void *)&sb);
+	if (err || (retlen != sizeof(sb))) {
+		pr_alert("error occured while reading from \"%s\"\n",
+			master->name);
+		return -EIO;
+	}
+
+	if (le32_to_cpu(sb.magic) != EROFS_SUPER_MAGIC_V1) {
+		pr_alert("no erofs found in \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	blksz = 1 << sb.blkszbits;
+
+	// this catches overflows too as the number goes negative
+	// or reaches zero in case of an overflow
+	if (blksz < 512) {
+		pr_alert("erofs has invalid blkszbits in \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	int blocks = le32_to_cpu(sb.blocks);
+
+	retlen = blksz * blocks;
+
+	if (retlen / blksz != blocks) {
+		pr_alert("erofs size overflow in \"%s\"\n", master->name);
+		return -ENOENT;
+	}
+
+	if (retlen <= 0) {
+		pr_alert("erofs is empty in \"%s\"\n", master->name);
+		return -ENOENT;
+	}
+
+	if (offset + retlen > master->size) {
+		pr_alert("erofs has invalid size in \"%s\"\n",
+			master->name);
+		return -EINVAL;
+	}
+
+	*erofs_len = retlen;
+	return 0;
+}
+
+static int
+mtdsplit_parse_erofs(struct mtd_info *master,
+		     const struct mtd_partition **pparts,
+		     struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *part;
+	struct mtd_info *parent_mtd;
+	size_t part_offset;
+	size_t erofs_len;
+	int err;
+
+	err = mtd_get_erofs_len(master, 0, &erofs_len);
+	if (err)
+		return err;
+
+	parent_mtd = mtd_get_master(master);
+	part_offset = mtdpart_get_offset(master);
+
+	part = kzalloc(sizeof(*part), GFP_KERNEL);
+	if (!part) {
+		pr_alert("unable to allocate memory for \"%s\" partition\n",
+			 ROOTFS_SPLIT_NAME);
+		return -ENOMEM;
+	}
+
+	part->name = ROOTFS_SPLIT_NAME;
+	part->offset = mtd_roundup_to_eb(part_offset + erofs_len,
+					 parent_mtd) - part_offset;
+	part->size = mtd_rounddown_to_eb(master->size - part->offset, master);
+
+	*pparts = part;
+	return 1;
+}
+
+static struct mtd_part_parser mtdsplit_erofs_parser = {
+	.owner = THIS_MODULE,
+	.name = "erofs-split",
+	.parse_fn = mtdsplit_parse_erofs,
+	.type = MTD_PARSER_TYPE_ROOTFS,
+};
+
+static int __init mtdsplit_erofs_init(void)
+{
+	register_mtd_parser(&mtdsplit_erofs_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_erofs_init);
-- 
2.47.3




More information about the openwrt-devel mailing list