400-mtd-mtdsplit-support.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001
  2. From: OpenWrt community <[email protected]>
  3. Date: Wed, 13 Jul 2022 11:47:35 +0200
  4. Subject: [PATCH] mtd: mtdsplit support
  5. ---
  6. drivers/mtd/Kconfig | 19 ++++
  7. drivers/mtd/Makefile | 2 +
  8. drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++-----
  9. include/linux/mtd/mtd.h | 25 +++++
  10. include/linux/mtd/partitions.h | 7 ++
  11. 5 files changed, 197 insertions(+), 25 deletions(-)
  12. --- a/drivers/mtd/Kconfig
  13. +++ b/drivers/mtd/Kconfig
  14. @@ -12,6 +12,25 @@ menuconfig MTD
  15. if MTD
  16. +menu "OpenWrt specific MTD options"
  17. +
  18. +config MTD_ROOTFS_ROOT_DEV
  19. + bool "Automatically set 'rootfs' partition to be root filesystem"
  20. + default y
  21. +
  22. +config MTD_SPLIT_FIRMWARE
  23. + bool "Automatically split firmware partition for kernel+rootfs"
  24. + default y
  25. +
  26. +config MTD_SPLIT_FIRMWARE_NAME
  27. + string "Firmware partition name"
  28. + depends on MTD_SPLIT_FIRMWARE
  29. + default "firmware"
  30. +
  31. +source "drivers/mtd/mtdsplit/Kconfig"
  32. +
  33. +endmenu
  34. +
  35. config MTD_TESTS
  36. tristate "MTD tests support (DANGEROUS)"
  37. depends on m
  38. --- a/drivers/mtd/Makefile
  39. +++ b/drivers/mtd/Makefile
  40. @@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
  41. obj-y += parsers/
  42. +obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
  43. +
  44. # 'Users' - code which presents functionality to userspace.
  45. obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
  46. obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
  47. --- a/drivers/mtd/mtdpart.c
  48. +++ b/drivers/mtd/mtdpart.c
  49. @@ -15,11 +15,13 @@
  50. #include <linux/kmod.h>
  51. #include <linux/mtd/mtd.h>
  52. #include <linux/mtd/partitions.h>
  53. +#include <linux/magic.h>
  54. #include <linux/err.h>
  55. #include <linux/of.h>
  56. #include <linux/of_platform.h>
  57. #include "mtdcore.h"
  58. +#include "mtdsplit/mtdsplit.h"
  59. /*
  60. * MTD methods which simply translate the effective address and pass through
  61. @@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struc
  62. return ret;
  63. }
  64. +static DEFINE_SPINLOCK(part_parser_lock);
  65. +static LIST_HEAD(part_parsers);
  66. +
  67. +static struct mtd_part_parser *mtd_part_parser_get(const char *name)
  68. +{
  69. + struct mtd_part_parser *p, *ret = NULL;
  70. +
  71. + spin_lock(&part_parser_lock);
  72. +
  73. + list_for_each_entry(p, &part_parsers, list)
  74. + if (!strcmp(p->name, name) && try_module_get(p->owner)) {
  75. + ret = p;
  76. + break;
  77. + }
  78. +
  79. + spin_unlock(&part_parser_lock);
  80. +
  81. + return ret;
  82. +}
  83. +
  84. +static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
  85. +{
  86. + module_put(p->owner);
  87. +}
  88. +
  89. +static struct mtd_part_parser *
  90. +get_partition_parser_by_type(enum mtd_parser_type type,
  91. + struct mtd_part_parser *start)
  92. +{
  93. + struct mtd_part_parser *p, *ret = NULL;
  94. +
  95. + spin_lock(&part_parser_lock);
  96. +
  97. + p = list_prepare_entry(start, &part_parsers, list);
  98. + if (start)
  99. + mtd_part_parser_put(start);
  100. +
  101. + list_for_each_entry_continue(p, &part_parsers, list) {
  102. + if (p->type == type && try_module_get(p->owner)) {
  103. + ret = p;
  104. + break;
  105. + }
  106. + }
  107. +
  108. + spin_unlock(&part_parser_lock);
  109. +
  110. + return ret;
  111. +}
  112. +
  113. +static int parse_mtd_partitions_by_type(struct mtd_info *master,
  114. + enum mtd_parser_type type,
  115. + const struct mtd_partition **pparts,
  116. + struct mtd_part_parser_data *data)
  117. +{
  118. + struct mtd_part_parser *prev = NULL;
  119. + int ret = 0;
  120. +
  121. + while (1) {
  122. + struct mtd_part_parser *parser;
  123. +
  124. + parser = get_partition_parser_by_type(type, prev);
  125. + if (!parser)
  126. + break;
  127. +
  128. + ret = (*parser->parse_fn)(master, pparts, data);
  129. +
  130. + if (ret > 0) {
  131. + mtd_part_parser_put(parser);
  132. + printk(KERN_NOTICE
  133. + "%d %s partitions found on MTD device %s\n",
  134. + ret, parser->name, master->name);
  135. + break;
  136. + }
  137. +
  138. + prev = parser;
  139. + }
  140. +
  141. + return ret;
  142. +}
  143. +
  144. +static int
  145. +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
  146. +{
  147. + struct mtd_partition *parts;
  148. + int nr_parts;
  149. + int i;
  150. +
  151. + nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
  152. + NULL);
  153. + if (nr_parts <= 0)
  154. + return nr_parts;
  155. +
  156. + if (WARN_ON(!parts))
  157. + return 0;
  158. +
  159. + for (i = 0; i < nr_parts; i++) {
  160. + /* adjust partition offsets */
  161. + parts[i].offset += child->part.offset;
  162. +
  163. + mtd_add_partition(child->parent,
  164. + parts[i].name,
  165. + parts[i].offset,
  166. + parts[i].size);
  167. + }
  168. +
  169. + kfree(parts);
  170. +
  171. + return nr_parts;
  172. +}
  173. +
  174. +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
  175. +#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
  176. +#else
  177. +#define SPLIT_FIRMWARE_NAME "unused"
  178. +#endif
  179. +
  180. +static void split_firmware(struct mtd_info *master, struct mtd_info *part)
  181. +{
  182. + run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
  183. +}
  184. +
  185. +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
  186. +{
  187. + static int rootfs_found = 0;
  188. +
  189. + if (rootfs_found)
  190. + return;
  191. +
  192. + if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) ||
  193. + !strcmp(part->name, "rootfs")) {
  194. + run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
  195. +
  196. + rootfs_found = 1;
  197. + }
  198. +
  199. + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
  200. + !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
  201. + !of_find_property(mtd_get_of_node(part), "compatible", NULL))
  202. + split_firmware(master, part);
  203. +}
  204. +
  205. int mtd_add_partition(struct mtd_info *parent, const char *name,
  206. long long offset, long long length)
  207. {
  208. @@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *p
  209. if (ret)
  210. goto err_remove_part;
  211. + mtd_partition_split(parent, child);
  212. mtd_add_partition_attrs(child);
  213. return 0;
  214. @@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *
  215. goto err_del_partitions;
  216. }
  217. + mtd_partition_split(master, child);
  218. mtd_add_partition_attrs(child);
  219. /* Look for subpartitions */
  220. @@ -439,31 +584,6 @@ err_del_partitions:
  221. return ret;
  222. }
  223. -static DEFINE_SPINLOCK(part_parser_lock);
  224. -static LIST_HEAD(part_parsers);
  225. -
  226. -static struct mtd_part_parser *mtd_part_parser_get(const char *name)
  227. -{
  228. - struct mtd_part_parser *p, *ret = NULL;
  229. -
  230. - spin_lock(&part_parser_lock);
  231. -
  232. - list_for_each_entry(p, &part_parsers, list)
  233. - if (!strcmp(p->name, name) && try_module_get(p->owner)) {
  234. - ret = p;
  235. - break;
  236. - }
  237. -
  238. - spin_unlock(&part_parser_lock);
  239. -
  240. - return ret;
  241. -}
  242. -
  243. -static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
  244. -{
  245. - module_put(p->owner);
  246. -}
  247. -
  248. /*
  249. * Many partition parsers just expected the core to kfree() all their data in
  250. * one chunk. Do that by default.
  251. --- a/include/linux/mtd/mtd.h
  252. +++ b/include/linux/mtd/mtd.h
  253. @@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
  254. req->len += mtd->erasesize - mod;
  255. }
  256. +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
  257. +{
  258. + if (mtd_mod_by_eb(sz, mtd) == 0)
  259. + return sz;
  260. +
  261. + /* Round up to next erase block */
  262. + return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
  263. +}
  264. +
  265. +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
  266. +{
  267. + if (mtd_mod_by_eb(sz, mtd) == 0)
  268. + return sz;
  269. +
  270. + /* Round down to the start of the current erase block */
  271. + return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
  272. +}
  273. +
  274. static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
  275. {
  276. if (mtd->writesize_shift)
  277. @@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic
  278. extern struct mtd_info *get_mtd_device_nm(const char *name);
  279. extern void put_mtd_device(struct mtd_info *mtd);
  280. +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
  281. +{
  282. + if (!mtd_is_partition(mtd))
  283. + return 0;
  284. +
  285. + return mtd->part.offset;
  286. +}
  287. struct mtd_notifier {
  288. void (*add)(struct mtd_info *mtd);
  289. --- a/include/linux/mtd/partitions.h
  290. +++ b/include/linux/mtd/partitions.h
  291. @@ -75,6 +75,12 @@ struct mtd_part_parser_data {
  292. * Functions dealing with the various ways of partitioning the space
  293. */
  294. +enum mtd_parser_type {
  295. + MTD_PARSER_TYPE_DEVICE = 0,
  296. + MTD_PARSER_TYPE_ROOTFS,
  297. + MTD_PARSER_TYPE_FIRMWARE,
  298. +};
  299. +
  300. struct mtd_part_parser {
  301. struct list_head list;
  302. struct module *owner;
  303. @@ -83,6 +89,7 @@ struct mtd_part_parser {
  304. int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
  305. struct mtd_part_parser_data *);
  306. void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
  307. + enum mtd_parser_type type;
  308. };
  309. /* Container for passing around a set of parsed partitions */