kernel: backport upstream mtd support for partition parsers

In a log term it should replace our implementation. For now both can
coexist.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
This commit is contained in:
Rafał Miłecki 2017-06-23 10:47:18 +02:00
parent 8c1e760ab6
commit 4d5f296af8
9 changed files with 229 additions and 23 deletions

View file

@ -0,0 +1,96 @@
From 97519dc52b44af054d7654776e78eaa211cf1842 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 21 Jun 2017 08:26:45 +0200
Subject: [PATCH] mtd: partitions: add support for subpartitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some flash device partitions can be containers with extra subpartitions
(volumes). All callbacks are already capable of this additional level of
indirection.
This patch makes sure we always display subpartitions using a tree
structure and takes care of deleting subpartitions when parent gets
removed.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -413,7 +413,7 @@ static struct mtd_part *allocate_partiti
* parent conditional on that option. Note, this is a way to
* distinguish between the master and the partition in sysfs.
*/
- slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
+ slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd_is_partition(parent) ?
&parent->dev :
parent->dev.parent;
slave->mtd.dev.of_node = part->of_node;
@@ -664,8 +664,17 @@ EXPORT_SYMBOL_GPL(mtd_add_partition);
*/
static int __mtd_del_partition(struct mtd_part *priv)
{
+ struct mtd_part *child, *next;
int err;
+ list_for_each_entry_safe(child, next, &mtd_partitions, list) {
+ if (child->parent == &priv->mtd) {
+ err = __mtd_del_partition(child);
+ if (err)
+ return err;
+ }
+ }
+
sysfs_remove_files(&priv->mtd.dev.kobj, mtd_partition_attrs);
err = del_mtd_device(&priv->mtd);
@@ -680,16 +689,16 @@ static int __mtd_del_partition(struct mt
/*
* This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
+ * attached to the given MTD object.
*/
-int del_mtd_partitions(struct mtd_info *master)
+int del_mtd_partitions(struct mtd_info *mtd)
{
struct mtd_part *slave, *next;
int ret, err = 0;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
- if (slave->parent == master) {
+ if (slave->parent == mtd) {
ret = __mtd_del_partition(slave);
if (ret < 0)
err = ret;
@@ -699,14 +708,14 @@ int del_mtd_partitions(struct mtd_info *
return err;
}
-int mtd_del_partition(struct mtd_info *master, int partno)
+int mtd_del_partition(struct mtd_info *mtd, int partno)
{
struct mtd_part *slave, *next;
int ret = -EINVAL;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
- if ((slave->parent == master) &&
+ if ((slave->parent == mtd) &&
(slave->mtd.index == partno)) {
ret = __mtd_del_partition(slave);
break;
@@ -939,6 +948,6 @@ uint64_t mtd_get_device_size(const struc
if (!mtd_is_partition(mtd))
return mtd->size;
- return mtd_to_part(mtd)->parent->size;
+ return mtd_get_device_size(mtd_to_part(mtd)->parent);
}
EXPORT_SYMBOL_GPL(mtd_get_device_size);

View file

@ -0,0 +1,110 @@
From 1a0915be192606fee64830b9c5d70b7ed59426b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 21 Jun 2017 08:26:46 +0200
Subject: [PATCH] mtd: partitions: add support for partition parsers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some devices have partitions that are kind of containers with extra
subpartitions / volumes instead of e.g. a simple filesystem data. To
support such cases we need to first create normal flash device
partitions and then take care of these special ones.
It's very common case for home routers. Depending on the vendor there
are formats like TRX, Seama, TP-Link, WRGG & more. All of them are used
to embed few partitions into a single one / single firmware file.
Ideally all vendors would use some well documented / standardized format
like UBI (and some probably start doing so), but there are still
countless devices on the market using these poor vendor specific
formats.
This patch extends MTD subsystem by allowing to specify list of parsers
that should be tried for a given partition. Supporting such poor formats
is highly unlikely to be the top priority so these changes try to
minimize maintenance cost to the minimum. It reuses existing code for
these new parsers and just adds a one property and one new function.
This implementation requires setting partition parsers in a flash
parser. A proper change of bcm47xxpart will follow and in the future we
will hopefully also find a solution for doing it with ofpart
("fixed-partitions").
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 31 +++++++++++++++++++++++++++++++
include/linux/mtd/partitions.h | 7 +++++++
2 files changed, 38 insertions(+)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -369,6 +369,35 @@ static inline void free_partition(struct
kfree(p);
}
+/**
+ * mtd_parse_part - parse MTD partition looking for subpartitions
+ *
+ * @slave: part that is supposed to be a container and should be parsed
+ * @types: NULL-terminated array with names of partition parsers to try
+ *
+ * Some partitions are kind of containers with extra subpartitions (volumes).
+ * There can be various formats of such containers. This function tries to use
+ * specified parsers to analyze given partition and registers found
+ * subpartitions on success.
+ */
+static int mtd_parse_part(struct mtd_part *slave, const char *const *types)
+{
+ struct mtd_partitions parsed;
+ int err;
+
+ err = parse_mtd_partitions(&slave->mtd, types, &parsed, NULL);
+ if (err)
+ return err;
+ else if (!parsed.nr_parts)
+ return -ENOENT;
+
+ err = add_mtd_partitions(&slave->mtd, parsed.parts, parsed.nr_parts);
+
+ mtd_part_parser_cleanup(&parsed);
+
+ return err;
+}
+
static struct mtd_part *allocate_partition(struct mtd_info *parent,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
@@ -758,6 +787,8 @@ int add_mtd_partitions(struct mtd_info *
add_mtd_device(&slave->mtd);
mtd_add_partition_attrs(slave);
+ if (parts[i].types)
+ mtd_parse_part(slave, parts[i].types);
cur_offset = slave->offset + slave->mtd.size;
}
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -20,6 +20,12 @@
*
* For each partition, these fields are available:
* name: string that will be used to label the partition's MTD device.
+ * types: some partitions can be containers using specific format to describe
+ * embedded subpartitions / volumes. E.g. many home routers use "firmware"
+ * partition that contains at least kernel and rootfs. In such case an
+ * extra parser is needed that will detect these dynamic partitions and
+ * report them to the MTD subsystem. If set this property stores an array
+ * of parser names to use when looking for subpartitions.
* size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
* will extend to the end of the master MTD device.
* offset: absolute starting position within the master MTD device; if
@@ -38,6 +44,7 @@
struct mtd_partition {
const char *name; /* identifier string */
+ const char *const *types; /* names of parsers to use if any */
uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */

View file

@ -116,7 +116,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#include <linux/err.h> #include <linux/err.h>
#include "mtdcore.h" #include "mtdcore.h"
@@ -815,6 +816,42 @@ void deregister_mtd_parser(struct mtd_pa @@ -855,6 +856,42 @@ void deregister_mtd_parser(struct mtd_pa
EXPORT_SYMBOL_GPL(deregister_mtd_parser); EXPORT_SYMBOL_GPL(deregister_mtd_parser);
/* /*
@ -159,7 +159,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
* are changing this array! * are changing this array!
*/ */
@@ -872,6 +909,13 @@ int parse_mtd_partitions(struct mtd_info @@ -912,6 +949,13 @@ int parse_mtd_partitions(struct mtd_info
{ {
struct mtd_part_parser *parser; struct mtd_part_parser *parser;
int ret, err = 0; int ret, err = 0;
@ -173,7 +173,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
if (!types) if (!types)
types = default_mtd_part_types; types = default_mtd_part_types;
@@ -897,6 +941,7 @@ int parse_mtd_partitions(struct mtd_info @@ -937,6 +981,7 @@ int parse_mtd_partitions(struct mtd_info
if (ret < 0 && !err) if (ret < 0 && !err)
err = ret; err = ret;
} }

View file

@ -48,7 +48,7 @@
/* /*
* Given a pointer to the MTD object in the mtd_part structure, we can retrieve * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
* the pointer to that structure. * the pointer to that structure.
@@ -649,6 +653,7 @@ int mtd_add_partition(struct mtd_info *p @@ -678,6 +682,7 @@ int mtd_add_partition(struct mtd_info *p
mutex_unlock(&mtd_partitions_mutex); mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd); add_mtd_device(&new->mtd);
@ -56,7 +56,7 @@
mtd_add_partition_attrs(new); mtd_add_partition_attrs(new);
@@ -718,6 +723,35 @@ int mtd_del_partition(struct mtd_info *m @@ -756,6 +761,35 @@ int mtd_del_partition(struct mtd_info *m
} }
EXPORT_SYMBOL_GPL(mtd_del_partition); EXPORT_SYMBOL_GPL(mtd_del_partition);
@ -92,17 +92,17 @@
/* /*
* This function, given a master MTD object and a partition table, creates * This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to * and registers slave MTD objects which are bound to the master according to
@@ -749,6 +783,7 @@ int add_mtd_partitions(struct mtd_info * @@ -787,6 +821,7 @@ int add_mtd_partitions(struct mtd_info *
mutex_unlock(&mtd_partitions_mutex); mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd); add_mtd_device(&slave->mtd);
+ mtd_partition_split(master, slave); + mtd_partition_split(master, slave);
mtd_add_partition_attrs(slave); mtd_add_partition_attrs(slave);
if (parts[i].types)
cur_offset = slave->offset + slave->mtd.size; mtd_parse_part(slave, parts[i].types);
--- a/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h
@@ -102,5 +102,7 @@ int mtd_add_partition(struct mtd_info *m @@ -109,5 +109,7 @@ int mtd_add_partition(struct mtd_info *m
long long offset, long long length); long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno); int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd); uint64_t mtd_get_device_size(const struct mtd_info *mtd);

View file

@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c
@@ -996,6 +996,62 @@ void mtd_part_parser_cleanup(struct mtd_ @@ -1036,6 +1036,62 @@ void mtd_part_parser_cleanup(struct mtd_
} }
} }
@ -76,7 +76,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
struct mtd_part *part; struct mtd_part *part;
--- a/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h
@@ -61,11 +61,14 @@ struct mtd_part_parser_data { @@ -68,11 +68,14 @@ struct mtd_part_parser_data {
unsigned long origin; unsigned long origin;
}; };
@ -92,7 +92,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
struct mtd_part_parser { struct mtd_part_parser {
struct list_head list; struct list_head list;
struct module *owner; struct module *owner;
@@ -73,6 +76,7 @@ struct mtd_part_parser { @@ -80,6 +83,7 @@ struct mtd_part_parser {
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
struct mtd_part_parser_data *); struct mtd_part_parser_data *);
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
@ -100,7 +100,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
}; };
/* Container for passing around a set of parsed partitions */ /* Container for passing around a set of parsed partitions */
@@ -105,4 +109,9 @@ uint64_t mtd_get_device_size(const struc @@ -112,4 +116,9 @@ uint64_t mtd_get_device_size(const struc
extern void __weak arch_split_mtd_part(struct mtd_info *master, extern void __weak arch_split_mtd_part(struct mtd_info *master,
const char *name, int offset, int size); const char *name, int offset, int size);

View file

@ -1,6 +1,6 @@
--- a/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c
@@ -723,6 +723,36 @@ int mtd_del_partition(struct mtd_info *m @@ -761,6 +761,36 @@ int mtd_del_partition(struct mtd_info *m
} }
EXPORT_SYMBOL_GPL(mtd_del_partition); EXPORT_SYMBOL_GPL(mtd_del_partition);
@ -37,7 +37,7 @@
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else #else
@@ -731,6 +761,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); @@ -769,6 +799,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
static void split_firmware(struct mtd_info *master, struct mtd_part *part) static void split_firmware(struct mtd_info *master, struct mtd_part *part)
{ {
@ -45,7 +45,7 @@
} }
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
@@ -745,6 +776,12 @@ static void mtd_partition_split(struct m @@ -783,6 +814,12 @@ static void mtd_partition_split(struct m
if (rootfs_found) if (rootfs_found)
return; return;
@ -60,7 +60,7 @@
split_firmware(master, part); split_firmware(master, part);
--- a/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h
@@ -67,6 +67,8 @@ struct mtd_part_parser_data { @@ -74,6 +74,8 @@ struct mtd_part_parser_data {
enum mtd_parser_type { enum mtd_parser_type {
MTD_PARSER_TYPE_DEVICE = 0, MTD_PARSER_TYPE_DEVICE = 0,

View file

@ -1,6 +1,6 @@
--- a/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c
@@ -753,6 +753,17 @@ run_parsers_by_type(struct mtd_part *sla @@ -791,6 +791,17 @@ run_parsers_by_type(struct mtd_part *sla
return nr_parts; return nr_parts;
} }
@ -18,7 +18,7 @@
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else #else
@@ -1106,6 +1117,24 @@ int mtd_is_partition(const struct mtd_in @@ -1146,6 +1157,24 @@ int mtd_is_partition(const struct mtd_in
} }
EXPORT_SYMBOL_GPL(mtd_is_partition); EXPORT_SYMBOL_GPL(mtd_is_partition);
@ -45,7 +45,7 @@
{ {
--- a/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h
@@ -107,6 +107,8 @@ int mtd_is_partition(const struct mtd_in @@ -114,6 +114,8 @@ int mtd_is_partition(const struct mtd_in
int mtd_add_partition(struct mtd_info *master, const char *name, int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length); long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno); int mtd_del_partition(struct mtd_info *master, int partno);

View file

@ -1,6 +1,6 @@
--- a/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h
@@ -35,6 +35,7 @@ @@ -41,6 +41,7 @@
* Note: writeable partitions require their size and offset be * Note: writeable partitions require their size and offset be
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
*/ */
@ -8,7 +8,7 @@
struct mtd_partition { struct mtd_partition {
const char *name; /* identifier string */ const char *name; /* identifier string */
@@ -50,7 +51,6 @@ struct mtd_partition { @@ -57,7 +58,6 @@ struct mtd_partition {
#define MTDPART_SIZ_FULL (0) #define MTDPART_SIZ_FULL (0)

View file

@ -97,7 +97,7 @@
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset; instr->fail_addr -= part->offset;
@@ -561,19 +630,22 @@ static struct mtd_part *allocate_partiti @@ -590,19 +659,22 @@ static struct mtd_part *allocate_partiti
remainder = do_div(tmp, wr_alignment); remainder = do_div(tmp, wr_alignment);
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
/* Doesn't start on a boundary of major erase size */ /* Doesn't start on a boundary of major erase size */