123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001
- From: OpenWrt community <[email protected]>
- Date: Wed, 13 Jul 2022 11:47:35 +0200
- Subject: [PATCH] mtd: mtdsplit support
- ---
- drivers/mtd/Kconfig | 19 ++++
- drivers/mtd/Makefile | 2 +
- drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++-----
- include/linux/mtd/mtd.h | 25 +++++
- include/linux/mtd/partitions.h | 7 ++
- 5 files changed, 197 insertions(+), 25 deletions(-)
- --- a/drivers/mtd/Kconfig
- +++ b/drivers/mtd/Kconfig
- @@ -12,6 +12,25 @@ menuconfig MTD
-
- if MTD
-
- +menu "OpenWrt specific MTD options"
- +
- +config MTD_ROOTFS_ROOT_DEV
- + bool "Automatically set 'rootfs' partition to be root filesystem"
- + default y
- +
- +config MTD_SPLIT_FIRMWARE
- + bool "Automatically split firmware partition for kernel+rootfs"
- + default y
- +
- +config MTD_SPLIT_FIRMWARE_NAME
- + string "Firmware partition name"
- + depends on MTD_SPLIT_FIRMWARE
- + default "firmware"
- +
- +source "drivers/mtd/mtdsplit/Kconfig"
- +
- +endmenu
- +
- config MTD_TESTS
- tristate "MTD tests support (DANGEROUS)"
- depends on m
- --- a/drivers/mtd/Makefile
- +++ b/drivers/mtd/Makefile
- @@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
-
- obj-y += parsers/
-
- +obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
- +
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
- obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
- --- a/drivers/mtd/mtdpart.c
- +++ b/drivers/mtd/mtdpart.c
- @@ -15,11 +15,13 @@
- #include <linux/kmod.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
- +#include <linux/magic.h>
- #include <linux/err.h>
- #include <linux/of.h>
- #include <linux/of_platform.h>
-
- #include "mtdcore.h"
- +#include "mtdsplit/mtdsplit.h"
-
- /*
- * MTD methods which simply translate the effective address and pass through
- @@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struc
- return ret;
- }
-
- +static DEFINE_SPINLOCK(part_parser_lock);
- +static LIST_HEAD(part_parsers);
- +
- +static struct mtd_part_parser *mtd_part_parser_get(const char *name)
- +{
- + struct mtd_part_parser *p, *ret = NULL;
- +
- + spin_lock(&part_parser_lock);
- +
- + list_for_each_entry(p, &part_parsers, list)
- + if (!strcmp(p->name, name) && try_module_get(p->owner)) {
- + ret = p;
- + break;
- + }
- +
- + spin_unlock(&part_parser_lock);
- +
- + return ret;
- +}
- +
- +static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
- +{
- + module_put(p->owner);
- +}
- +
- +static struct mtd_part_parser *
- +get_partition_parser_by_type(enum mtd_parser_type type,
- + struct mtd_part_parser *start)
- +{
- + struct mtd_part_parser *p, *ret = NULL;
- +
- + spin_lock(&part_parser_lock);
- +
- + p = list_prepare_entry(start, &part_parsers, list);
- + if (start)
- + mtd_part_parser_put(start);
- +
- + list_for_each_entry_continue(p, &part_parsers, list) {
- + if (p->type == type && try_module_get(p->owner)) {
- + ret = p;
- + break;
- + }
- + }
- +
- + spin_unlock(&part_parser_lock);
- +
- + return ret;
- +}
- +
- +static int parse_mtd_partitions_by_type(struct mtd_info *master,
- + enum mtd_parser_type type,
- + const struct mtd_partition **pparts,
- + struct mtd_part_parser_data *data)
- +{
- + struct mtd_part_parser *prev = NULL;
- + int ret = 0;
- +
- + while (1) {
- + struct mtd_part_parser *parser;
- +
- + parser = get_partition_parser_by_type(type, prev);
- + if (!parser)
- + break;
- +
- + ret = (*parser->parse_fn)(master, pparts, data);
- +
- + if (ret > 0) {
- + mtd_part_parser_put(parser);
- + printk(KERN_NOTICE
- + "%d %s partitions found on MTD device %s\n",
- + ret, parser->name, master->name);
- + break;
- + }
- +
- + prev = parser;
- + }
- +
- + return ret;
- +}
- +
- +static int
- +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
- +{
- + struct mtd_partition *parts;
- + int nr_parts;
- + int i;
- +
- + nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
- + NULL);
- + if (nr_parts <= 0)
- + return nr_parts;
- +
- + if (WARN_ON(!parts))
- + return 0;
- +
- + for (i = 0; i < nr_parts; i++) {
- + /* adjust partition offsets */
- + parts[i].offset += child->part.offset;
- +
- + mtd_add_partition(child->parent,
- + parts[i].name,
- + parts[i].offset,
- + parts[i].size);
- + }
- +
- + kfree(parts);
- +
- + return nr_parts;
- +}
- +
- +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
- +#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
- +#else
- +#define SPLIT_FIRMWARE_NAME "unused"
- +#endif
- +
- +static void split_firmware(struct mtd_info *master, struct mtd_info *part)
- +{
- + run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
- +}
- +
- +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
- +{
- + static int rootfs_found = 0;
- +
- + if (rootfs_found)
- + return;
- +
- + if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) ||
- + !strcmp(part->name, "rootfs")) {
- + run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
- +
- + rootfs_found = 1;
- + }
- +
- + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
- + !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
- + !of_find_property(mtd_get_of_node(part), "compatible", NULL))
- + split_firmware(master, part);
- +}
- +
- int mtd_add_partition(struct mtd_info *parent, const char *name,
- long long offset, long long length)
- {
- @@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *p
- if (ret)
- goto err_remove_part;
-
- + mtd_partition_split(parent, child);
- mtd_add_partition_attrs(child);
-
- return 0;
- @@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *
- goto err_del_partitions;
- }
-
- + mtd_partition_split(master, child);
- mtd_add_partition_attrs(child);
-
- /* Look for subpartitions */
- @@ -439,31 +584,6 @@ err_del_partitions:
- return ret;
- }
-
- -static DEFINE_SPINLOCK(part_parser_lock);
- -static LIST_HEAD(part_parsers);
- -
- -static struct mtd_part_parser *mtd_part_parser_get(const char *name)
- -{
- - struct mtd_part_parser *p, *ret = NULL;
- -
- - spin_lock(&part_parser_lock);
- -
- - list_for_each_entry(p, &part_parsers, list)
- - if (!strcmp(p->name, name) && try_module_get(p->owner)) {
- - ret = p;
- - break;
- - }
- -
- - spin_unlock(&part_parser_lock);
- -
- - return ret;
- -}
- -
- -static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
- -{
- - module_put(p->owner);
- -}
- -
- /*
- * Many partition parsers just expected the core to kfree() all their data in
- * one chunk. Do that by default.
- --- a/include/linux/mtd/mtd.h
- +++ b/include/linux/mtd/mtd.h
- @@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
- req->len += mtd->erasesize - mod;
- }
-
- +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
- +{
- + if (mtd_mod_by_eb(sz, mtd) == 0)
- + return sz;
- +
- + /* Round up to next erase block */
- + return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
- +}
- +
- +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
- +{
- + if (mtd_mod_by_eb(sz, mtd) == 0)
- + return sz;
- +
- + /* Round down to the start of the current erase block */
- + return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
- +}
- +
- static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
- {
- if (mtd->writesize_shift)
- @@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic
- extern struct mtd_info *get_mtd_device_nm(const char *name);
- extern void put_mtd_device(struct mtd_info *mtd);
-
- +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
- +{
- + if (!mtd_is_partition(mtd))
- + return 0;
- +
- + return mtd->part.offset;
- +}
-
- struct mtd_notifier {
- void (*add)(struct mtd_info *mtd);
- --- a/include/linux/mtd/partitions.h
- +++ b/include/linux/mtd/partitions.h
- @@ -75,6 +75,12 @@ struct mtd_part_parser_data {
- * Functions dealing with the various ways of partitioning the space
- */
-
- +enum mtd_parser_type {
- + MTD_PARSER_TYPE_DEVICE = 0,
- + MTD_PARSER_TYPE_ROOTFS,
- + MTD_PARSER_TYPE_FIRMWARE,
- +};
- +
- struct mtd_part_parser {
- struct list_head list;
- struct module *owner;
- @@ -83,6 +89,7 @@ struct mtd_part_parser {
- int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
- struct mtd_part_parser_data *);
- void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
- + enum mtd_parser_type type;
- };
-
- /* Container for passing around a set of parsed partitions */
|