diff options
author | Roman Tereshonkov <roman.tereshonkov@nokia.com> | 2010-09-17 06:31:41 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-10-24 19:47:37 -0400 |
commit | 5daa7b21496aebf057c12be03038e7220e33353b (patch) | |
tree | 7ec8f8a086dcfdcb7aec800bf528d3704bcaadc8 /drivers/mtd | |
parent | 93ac5a552c831096003f9bc74471300dc1710a42 (diff) |
mtd: prepare partition add and del functions for ioctl requests
mtd_is_master, mtd_add_partition and mtd_del_partition functions
are added to give the possibility of partition manipulation
by ioctl request.
The old partition add function is modified to fit the dynamic
allocation.
Signed-off-by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/mtdpart.c | 154 |
1 files changed, 136 insertions, 18 deletions
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index dc6558568876..79e3689f1e16 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -29,9 +29,11 @@ | |||
29 | #include <linux/kmod.h> | 29 | #include <linux/kmod.h> |
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 | 33 | ||
33 | /* Our partition linked list */ | 34 | /* Our partition linked list */ |
34 | static LIST_HEAD(mtd_partitions); | 35 | static LIST_HEAD(mtd_partitions); |
36 | static DEFINE_MUTEX(mtd_partitions_mutex); | ||
35 | 37 | ||
36 | /* Our partition node structure */ | 38 | /* Our partition node structure */ |
37 | struct mtd_part { | 39 | struct mtd_part { |
@@ -326,6 +328,12 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
326 | return res; | 328 | return res; |
327 | } | 329 | } |
328 | 330 | ||
331 | static inline void free_partition(struct mtd_part *p) | ||
332 | { | ||
333 | kfree(p->mtd.name); | ||
334 | kfree(p); | ||
335 | } | ||
336 | |||
329 | /* | 337 | /* |
330 | * This function unregisters and destroy all slave MTD objects which are | 338 | * This function unregisters and destroy all slave MTD objects which are |
331 | * attached to the given master MTD object. | 339 | * attached to the given master MTD object. |
@@ -334,33 +342,42 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
334 | int del_mtd_partitions(struct mtd_info *master) | 342 | int del_mtd_partitions(struct mtd_info *master) |
335 | { | 343 | { |
336 | struct mtd_part *slave, *next; | 344 | struct mtd_part *slave, *next; |
345 | int ret, err = 0; | ||
337 | 346 | ||
347 | mutex_lock(&mtd_partitions_mutex); | ||
338 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) | 348 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) |
339 | if (slave->master == master) { | 349 | if (slave->master == master) { |
350 | ret = del_mtd_device(&slave->mtd); | ||
351 | if (ret < 0) { | ||
352 | err = ret; | ||
353 | continue; | ||
354 | } | ||
340 | list_del(&slave->list); | 355 | list_del(&slave->list); |
341 | del_mtd_device(&slave->mtd); | 356 | free_partition(slave); |
342 | kfree(slave); | ||
343 | } | 357 | } |
358 | mutex_unlock(&mtd_partitions_mutex); | ||
344 | 359 | ||
345 | return 0; | 360 | return err; |
346 | } | 361 | } |
347 | EXPORT_SYMBOL(del_mtd_partitions); | 362 | EXPORT_SYMBOL(del_mtd_partitions); |
348 | 363 | ||
349 | static struct mtd_part *add_one_partition(struct mtd_info *master, | 364 | static struct mtd_part *allocate_partition(struct mtd_info *master, |
350 | const struct mtd_partition *part, int partno, | 365 | const struct mtd_partition *part, int partno, |
351 | uint64_t cur_offset) | 366 | uint64_t cur_offset) |
352 | { | 367 | { |
353 | struct mtd_part *slave; | 368 | struct mtd_part *slave; |
369 | char *name; | ||
354 | 370 | ||
355 | /* allocate the partition structure */ | 371 | /* allocate the partition structure */ |
356 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); | 372 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); |
357 | if (!slave) { | 373 | name = kstrdup(part->name, GFP_KERNEL); |
374 | if (!name || !slave) { | ||
358 | printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", | 375 | printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", |
359 | master->name); | 376 | master->name); |
360 | del_mtd_partitions(master); | 377 | kfree(name); |
361 | return NULL; | 378 | kfree(slave); |
379 | return ERR_PTR(-ENOMEM); | ||
362 | } | 380 | } |
363 | list_add(&slave->list, &mtd_partitions); | ||
364 | 381 | ||
365 | /* set up the MTD object for this partition */ | 382 | /* set up the MTD object for this partition */ |
366 | slave->mtd.type = master->type; | 383 | slave->mtd.type = master->type; |
@@ -371,7 +388,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, | |||
371 | slave->mtd.oobavail = master->oobavail; | 388 | slave->mtd.oobavail = master->oobavail; |
372 | slave->mtd.subpage_sft = master->subpage_sft; | 389 | slave->mtd.subpage_sft = master->subpage_sft; |
373 | 390 | ||
374 | slave->mtd.name = part->name; | 391 | slave->mtd.name = name; |
375 | slave->mtd.owner = master->owner; | 392 | slave->mtd.owner = master->owner; |
376 | slave->mtd.backing_dev_info = master->backing_dev_info; | 393 | slave->mtd.backing_dev_info = master->backing_dev_info; |
377 | 394 | ||
@@ -518,12 +535,89 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, | |||
518 | } | 535 | } |
519 | 536 | ||
520 | out_register: | 537 | out_register: |
521 | /* register our partition */ | ||
522 | add_mtd_device(&slave->mtd); | ||
523 | |||
524 | return slave; | 538 | return slave; |
525 | } | 539 | } |
526 | 540 | ||
541 | int mtd_add_partition(struct mtd_info *master, char *name, | ||
542 | long long offset, long long length) | ||
543 | { | ||
544 | struct mtd_partition part; | ||
545 | struct mtd_part *p, *new; | ||
546 | uint64_t start, end; | ||
547 | int ret = 0; | ||
548 | |||
549 | /* the direct offset is expected */ | ||
550 | if (offset == MTDPART_OFS_APPEND || | ||
551 | offset == MTDPART_OFS_NXTBLK) | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (length == MTDPART_SIZ_FULL) | ||
555 | length = master->size - offset; | ||
556 | |||
557 | if (length <= 0) | ||
558 | return -EINVAL; | ||
559 | |||
560 | part.name = name; | ||
561 | part.size = length; | ||
562 | part.offset = offset; | ||
563 | part.mask_flags = 0; | ||
564 | part.ecclayout = NULL; | ||
565 | |||
566 | new = allocate_partition(master, &part, -1, offset); | ||
567 | if (IS_ERR(new)) | ||
568 | return PTR_ERR(new); | ||
569 | |||
570 | start = offset; | ||
571 | end = offset + length; | ||
572 | |||
573 | mutex_lock(&mtd_partitions_mutex); | ||
574 | list_for_each_entry(p, &mtd_partitions, list) | ||
575 | if (p->master == master) { | ||
576 | if ((start >= p->offset) && | ||
577 | (start < (p->offset + p->mtd.size))) | ||
578 | goto err_inv; | ||
579 | |||
580 | if ((end >= p->offset) && | ||
581 | (end < (p->offset + p->mtd.size))) | ||
582 | goto err_inv; | ||
583 | } | ||
584 | |||
585 | list_add(&new->list, &mtd_partitions); | ||
586 | mutex_unlock(&mtd_partitions_mutex); | ||
587 | |||
588 | add_mtd_device(&new->mtd); | ||
589 | |||
590 | return ret; | ||
591 | err_inv: | ||
592 | mutex_unlock(&mtd_partitions_mutex); | ||
593 | free_partition(new); | ||
594 | return -EINVAL; | ||
595 | } | ||
596 | EXPORT_SYMBOL_GPL(mtd_add_partition); | ||
597 | |||
598 | int mtd_del_partition(struct mtd_info *master, int partno) | ||
599 | { | ||
600 | struct mtd_part *slave, *next; | ||
601 | int ret = -EINVAL; | ||
602 | |||
603 | mutex_lock(&mtd_partitions_mutex); | ||
604 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) | ||
605 | if ((slave->master == master) && | ||
606 | (slave->mtd.index == partno)) { | ||
607 | ret = del_mtd_device(&slave->mtd); | ||
608 | if (ret < 0) | ||
609 | break; | ||
610 | |||
611 | list_del(&slave->list); | ||
612 | free_partition(slave); | ||
613 | break; | ||
614 | } | ||
615 | mutex_unlock(&mtd_partitions_mutex); | ||
616 | |||
617 | return ret; | ||
618 | } | ||
619 | EXPORT_SYMBOL_GPL(mtd_del_partition); | ||
620 | |||
527 | /* | 621 | /* |
528 | * This function, given a master MTD object and a partition table, creates | 622 | * This function, given a master MTD object and a partition table, creates |
529 | * and registers slave MTD objects which are bound to the master according to | 623 | * and registers slave MTD objects which are bound to the master according to |
@@ -544,9 +638,16 @@ int add_mtd_partitions(struct mtd_info *master, | |||
544 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); | 638 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); |
545 | 639 | ||
546 | for (i = 0; i < nbparts; i++) { | 640 | for (i = 0; i < nbparts; i++) { |
547 | slave = add_one_partition(master, parts + i, i, cur_offset); | 641 | slave = allocate_partition(master, parts + i, i, cur_offset); |
548 | if (!slave) | 642 | if (IS_ERR(slave)) |
549 | return -ENOMEM; | 643 | return PTR_ERR(slave); |
644 | |||
645 | mutex_lock(&mtd_partitions_mutex); | ||
646 | list_add(&slave->list, &mtd_partitions); | ||
647 | mutex_unlock(&mtd_partitions_mutex); | ||
648 | |||
649 | add_mtd_device(&slave->mtd); | ||
650 | |||
550 | cur_offset = slave->offset + slave->mtd.size; | 651 | cur_offset = slave->offset + slave->mtd.size; |
551 | } | 652 | } |
552 | 653 | ||
@@ -618,3 +719,20 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
618 | return ret; | 719 | return ret; |
619 | } | 720 | } |
620 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); | 721 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); |
722 | |||
723 | int mtd_is_master(struct mtd_info *mtd) | ||
724 | { | ||
725 | struct mtd_part *part; | ||
726 | int nopart = 0; | ||
727 | |||
728 | mutex_lock(&mtd_partitions_mutex); | ||
729 | list_for_each_entry(part, &mtd_partitions, list) | ||
730 | if (&part->mtd == mtd) { | ||
731 | nopart = 1; | ||
732 | break; | ||
733 | } | ||
734 | mutex_unlock(&mtd_partitions_mutex); | ||
735 | |||
736 | return nopart; | ||
737 | } | ||
738 | EXPORT_SYMBOL_GPL(mtd_is_master); | ||