diff options
author | Dan Ehrenberg <dehrenberg@chromium.org> | 2015-04-02 18:15:10 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2015-04-05 20:44:01 -0400 |
commit | 727dc612c46b8f3858537ea23805b3e897cf127e (patch) | |
tree | 5bcda420d5f0071fc8d8c8c02dc68166256323e7 /drivers | |
parent | 9cd5196ed25979a3760f97225aae3e17caf21512 (diff) |
mtd: part: Create the master device node when partitioned
For many use cases, it helps to have a device node for the entire
MTD device as well as device nodes for the individual partitions.
For example, this allows querying the entire device's properties.
A common idiom is to create an additional partition which spans
over the whole device.
This patch makes a config option, CONFIG_MTD_PARTITIONED_MASTER,
which makes the master partition present even when the device is
partitioned. This isn't turned on by default since it presents
a backwards-incompatible device numbering.
The patch also makes the parent of a partition device be the master,
if the config flag is set, now that the master is a full device.
Signed-off-by: Dan Ehrenberg <dehrenberg@chromium.org>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mtd/mtdcore.c | 52 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 18 |
3 files changed, 62 insertions, 21 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 71fea895ce38..a03ad2951c7b 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -309,6 +309,19 @@ config MTD_SWAP | |||
309 | The driver provides wear leveling by storing erase counter into the | 309 | The driver provides wear leveling by storing erase counter into the |
310 | OOB. | 310 | OOB. |
311 | 311 | ||
312 | config MTD_PARTITIONED_MASTER | ||
313 | bool "Retain master device when partitioned" | ||
314 | default n | ||
315 | depends on MTD | ||
316 | help | ||
317 | For historical reasons, by default, either a master is present or | ||
318 | several partitions are present, but not both. The concern was that | ||
319 | data listed in multiple partitions was dangerous; however, SCSI does | ||
320 | this and it is frequently useful for applications. This config option | ||
321 | leaves the master in even if the device is partitioned. It also makes | ||
322 | the parent of the partition device be the master device, rather than | ||
323 | what lies behind the master. | ||
324 | |||
312 | source "drivers/mtd/chips/Kconfig" | 325 | source "drivers/mtd/chips/Kconfig" |
313 | 326 | ||
314 | source "drivers/mtd/maps/Kconfig" | 327 | source "drivers/mtd/maps/Kconfig" |
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 11883bd26d9d..d172195fbd15 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/gfp.h> | 38 | #include <linux/gfp.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/reboot.h> | 40 | #include <linux/reboot.h> |
41 | #include <linux/kconfig.h> | ||
41 | 42 | ||
42 | #include <linux/mtd/mtd.h> | 43 | #include <linux/mtd/mtd.h> |
43 | #include <linux/mtd/partitions.h> | 44 | #include <linux/mtd/partitions.h> |
@@ -501,6 +502,29 @@ out_error: | |||
501 | return ret; | 502 | return ret; |
502 | } | 503 | } |
503 | 504 | ||
505 | static int mtd_add_device_partitions(struct mtd_info *mtd, | ||
506 | struct mtd_partition *real_parts, | ||
507 | int nbparts) | ||
508 | { | ||
509 | int ret; | ||
510 | |||
511 | if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { | ||
512 | ret = add_mtd_device(mtd); | ||
513 | if (ret == 1) | ||
514 | return -ENODEV; | ||
515 | } | ||
516 | |||
517 | if (nbparts > 0) { | ||
518 | ret = add_mtd_partitions(mtd, real_parts, nbparts); | ||
519 | if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) | ||
520 | del_mtd_device(mtd); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | |||
504 | /** | 528 | /** |
505 | * mtd_device_parse_register - parse partitions and register an MTD device. | 529 | * mtd_device_parse_register - parse partitions and register an MTD device. |
506 | * | 530 | * |
@@ -523,7 +547,8 @@ out_error: | |||
523 | * found this functions tries to fallback to information specified in | 547 | * found this functions tries to fallback to information specified in |
524 | * @parts/@nr_parts. | 548 | * @parts/@nr_parts. |
525 | * * If any partitioning info was found, this function registers the found | 549 | * * If any partitioning info was found, this function registers the found |
526 | * partitions. | 550 | * partitions. If the MTD_PARTITIONED_MASTER option is set, then the device |
551 | * as a whole is registered first. | ||
527 | * * If no partitions were found this function just registers the MTD device | 552 | * * If no partitions were found this function just registers the MTD device |
528 | * @mtd and exits. | 553 | * @mtd and exits. |
529 | * | 554 | * |
@@ -534,27 +559,21 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, | |||
534 | const struct mtd_partition *parts, | 559 | const struct mtd_partition *parts, |
535 | int nr_parts) | 560 | int nr_parts) |
536 | { | 561 | { |
537 | int err; | 562 | int ret; |
538 | struct mtd_partition *real_parts; | 563 | struct mtd_partition *real_parts = NULL; |
539 | 564 | ||
540 | err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); | 565 | ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data); |
541 | if (err <= 0 && nr_parts && parts) { | 566 | if (ret <= 0 && nr_parts && parts) { |
542 | real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, | 567 | real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, |
543 | GFP_KERNEL); | 568 | GFP_KERNEL); |
544 | if (!real_parts) | 569 | if (!real_parts) |
545 | err = -ENOMEM; | 570 | ret = -ENOMEM; |
546 | else | 571 | else |
547 | err = nr_parts; | 572 | ret = nr_parts; |
548 | } | 573 | } |
549 | 574 | ||
550 | if (err > 0) { | 575 | if (ret >= 0) |
551 | err = add_mtd_partitions(mtd, real_parts, err); | 576 | ret = mtd_add_device_partitions(mtd, real_parts, ret); |
552 | kfree(real_parts); | ||
553 | } else if (err == 0) { | ||
554 | err = add_mtd_device(mtd); | ||
555 | if (err == 1) | ||
556 | err = -ENODEV; | ||
557 | } | ||
558 | 577 | ||
559 | /* | 578 | /* |
560 | * FIXME: some drivers unfortunately call this function more than once. | 579 | * FIXME: some drivers unfortunately call this function more than once. |
@@ -569,7 +588,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, | |||
569 | register_reboot_notifier(&mtd->reboot_notifier); | 588 | register_reboot_notifier(&mtd->reboot_notifier); |
570 | } | 589 | } |
571 | 590 | ||
572 | return err; | 591 | kfree(real_parts); |
592 | return ret; | ||
573 | } | 593 | } |
574 | EXPORT_SYMBOL_GPL(mtd_device_parse_register); | 594 | EXPORT_SYMBOL_GPL(mtd_device_parse_register); |
575 | 595 | ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index e779de315ade..a19ec5a4e409 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
31 | #include <linux/mtd/partitions.h> | 31 | #include <linux/mtd/partitions.h> |
32 | #include <linux/err.h> | 32 | #include <linux/err.h> |
33 | #include <linux/kconfig.h> | ||
33 | 34 | ||
34 | #include "mtdcore.h" | 35 | #include "mtdcore.h" |
35 | 36 | ||
@@ -379,10 +380,17 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, | |||
379 | slave->mtd.name = name; | 380 | slave->mtd.name = name; |
380 | slave->mtd.owner = master->owner; | 381 | slave->mtd.owner = master->owner; |
381 | 382 | ||
382 | /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone | 383 | /* NOTE: Historically, we didn't arrange MTDs as a tree out of |
383 | * to have the same data be in two different partitions. | 384 | * concern for showing the same data in multiple partitions. |
385 | * However, it is very useful to have the master node present, | ||
386 | * so the MTD_PARTITIONED_MASTER option allows that. The master | ||
387 | * will have device nodes etc only if this is set, so make the | ||
388 | * parent conditional on that option. Note, this is a way to | ||
389 | * distinguish between the master and the partition in sysfs. | ||
384 | */ | 390 | */ |
385 | slave->mtd.dev.parent = master->dev.parent; | 391 | slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? |
392 | &master->dev : | ||
393 | master->dev.parent; | ||
386 | 394 | ||
387 | slave->mtd._read = part_read; | 395 | slave->mtd._read = part_read; |
388 | slave->mtd._write = part_write; | 396 | slave->mtd._write = part_write; |
@@ -631,8 +639,8 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); | |||
631 | * and registers slave MTD objects which are bound to the master according to | 639 | * and registers slave MTD objects which are bound to the master according to |
632 | * the partition definitions. | 640 | * the partition definitions. |
633 | * | 641 | * |
634 | * We don't register the master, or expect the caller to have done so, | 642 | * For historical reasons, this function's caller only registers the master |
635 | * for reasons of data integrity. | 643 | * if the MTD_PARTITIONED_MASTER config option is set. |
636 | */ | 644 | */ |
637 | 645 | ||
638 | int add_mtd_partitions(struct mtd_info *master, | 646 | int add_mtd_partitions(struct mtd_info *master, |