diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-18 11:23:39 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-26 12:15:17 -0500 |
commit | 897a316c9e6f7fea6f1d3759797b75c0ebaec479 (patch) | |
tree | 487f211f3a862d8948ba19ca3f645c7a37f4d547 /drivers/mtd/ubi/build.c | |
parent | 9b79cc0f84edecceb04b806b9014fcec1306c34d (diff) |
UBI: handle attach ioctl
Actually implement the MTD device attach/detach handlers.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/build.c')
-rw-r--r-- | drivers/mtd/ubi/build.c | 80 |
1 files changed, 54 insertions, 26 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 403c10a668bd..70c0b9a9e6e3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -621,18 +621,19 @@ static int io_init(struct ubi_device *ubi) | |||
621 | /** | 621 | /** |
622 | * ubi_attach_mtd_dev - attach an MTD device. | 622 | * ubi_attach_mtd_dev - attach an MTD device. |
623 | * @mtd_dev: MTD device description object | 623 | * @mtd_dev: MTD device description object |
624 | * @ubi_num: number to assign to the new UBI device | ||
624 | * @vid_hdr_offset: VID header offset | 625 | * @vid_hdr_offset: VID header offset |
625 | * | 626 | * |
626 | * This function attaches an MTD device to UBI. It first treats @mtd_dev as the | 627 | * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number |
627 | * MTD device name, and tries to open it by this name. If it is unable to open, | 628 | * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in |
628 | * it tries to convert @mtd_dev to an integer and open the MTD device by its | 629 | * which case this function finds a vacant device nubert and assings it |
629 | * number. Returns new UBI device's number in case of success and a negative | 630 | * automatically. Returns the new UBI device number in case of success and a |
630 | * error code in case of failure. | 631 | * negative error code in case of failure. |
631 | * | 632 | * |
632 | * Note, the invocations of this function has to be serialized by the | 633 | * Note, the invocations of this function has to be serialized by the |
633 | * @ubi_devices_mutex. | 634 | * @ubi_devices_mutex. |
634 | */ | 635 | */ |
635 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) | 636 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) |
636 | { | 637 | { |
637 | struct ubi_device *ubi; | 638 | struct ubi_device *ubi; |
638 | int i, err; | 639 | int i, err; |
@@ -643,22 +644,47 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) | |||
643 | * Note, this function assumes that UBI devices creations and deletions | 644 | * Note, this function assumes that UBI devices creations and deletions |
644 | * are serialized, so it does not take the &ubi_devices_lock. | 645 | * are serialized, so it does not take the &ubi_devices_lock. |
645 | */ | 646 | */ |
646 | for (i = 0; i < UBI_MAX_DEVICES; i++) | 647 | for (i = 0; i < UBI_MAX_DEVICES; i++) { |
647 | ubi = ubi_devices[i]; | 648 | ubi = ubi_devices[i]; |
648 | if (ubi && mtd->index == ubi->mtd->index) { | 649 | if (ubi && mtd->index == ubi->mtd->index) { |
649 | ubi_err("mtd%d is already attached to ubi%d", | 650 | dbg_err("mtd%d is already attached to ubi%d", |
650 | mtd->index, i); | 651 | mtd->index, i); |
651 | return -EINVAL; | 652 | return -EEXIST; |
652 | } | 653 | } |
654 | } | ||
653 | 655 | ||
654 | /* Search for an empty slot in the @ubi_devices array */ | 656 | /* |
655 | for (i = 0; i < UBI_MAX_DEVICES; i++) | 657 | * Make sure this MTD device is not emulated on top of an UBI volume |
656 | if (!ubi_devices[i]) | 658 | * already. Well, generally this recursion works fine, but there are |
657 | break; | 659 | * different problems like the UBI module takes a reference to itself |
660 | * by attaching (and thus, opening) the emulated MTD device. This | ||
661 | * results in inability to unload the module. And in general it makes | ||
662 | * no sense to attach emulated MTD devices, so we prohibit this. | ||
663 | */ | ||
664 | if (mtd->type == MTD_UBIVOLUME) { | ||
665 | ubi_err("refuse attaching mtd%d - it is already emulated on " | ||
666 | "top of UBI", mtd->index); | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | |||
670 | if (ubi_num == UBI_DEV_NUM_AUTO) { | ||
671 | /* Search for an empty slot in the @ubi_devices array */ | ||
672 | for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) | ||
673 | if (!ubi_devices[ubi_num]) | ||
674 | break; | ||
675 | if (ubi_num == UBI_MAX_DEVICES) { | ||
676 | dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); | ||
677 | return -ENFILE; | ||
678 | } | ||
679 | } else { | ||
680 | if (ubi_num >= UBI_MAX_DEVICES) | ||
681 | return -EINVAL; | ||
658 | 682 | ||
659 | if (i == UBI_MAX_DEVICES) { | 683 | /* Make sure ubi_num is not busy */ |
660 | ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); | 684 | if (ubi_devices[ubi_num]) { |
661 | return -ENFILE; | 685 | dbg_err("ubi%d already exists", ubi_num); |
686 | return -EEXIST; | ||
687 | } | ||
662 | } | 688 | } |
663 | 689 | ||
664 | ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); | 690 | ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); |
@@ -666,11 +692,11 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) | |||
666 | return -ENOMEM; | 692 | return -ENOMEM; |
667 | 693 | ||
668 | ubi->mtd = mtd; | 694 | ubi->mtd = mtd; |
669 | ubi->ubi_num = i; | 695 | ubi->ubi_num = ubi_num; |
670 | ubi->vid_hdr_offset = vid_hdr_offset; | 696 | ubi->vid_hdr_offset = vid_hdr_offset; |
671 | 697 | ||
672 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", | 698 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", |
673 | mtd->index, ubi->ubi_num, vid_hdr_offset); | 699 | mtd->index, ubi_num, vid_hdr_offset); |
674 | 700 | ||
675 | err = io_init(ubi); | 701 | err = io_init(ubi); |
676 | if (err) | 702 | if (err) |
@@ -710,7 +736,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) | |||
710 | goto out_uif; | 736 | goto out_uif; |
711 | } | 737 | } |
712 | 738 | ||
713 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num); | 739 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); |
714 | ubi_msg("MTD device name: \"%s\"", mtd->name); | 740 | ubi_msg("MTD device name: \"%s\"", mtd->name); |
715 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); | 741 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); |
716 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", | 742 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", |
@@ -739,8 +765,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) | |||
739 | wake_up_process(ubi->bgt_thread); | 765 | wake_up_process(ubi->bgt_thread); |
740 | } | 766 | } |
741 | 767 | ||
742 | ubi_devices[ubi->ubi_num] = ubi; | 768 | ubi_devices[ubi_num] = ubi; |
743 | return ubi->ubi_num; | 769 | return ubi_num; |
744 | 770 | ||
745 | out_uif: | 771 | out_uif: |
746 | uif_close(ubi); | 772 | uif_close(ubi); |
@@ -781,23 +807,24 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) | |||
781 | spin_lock(&ubi_devices_lock); | 807 | spin_lock(&ubi_devices_lock); |
782 | ubi = ubi_devices[ubi_num]; | 808 | ubi = ubi_devices[ubi_num]; |
783 | if (!ubi) { | 809 | if (!ubi) { |
784 | spin_lock(&ubi_devices_lock); | 810 | spin_unlock(&ubi_devices_lock); |
785 | return -EINVAL; | 811 | return -EINVAL; |
786 | } | 812 | } |
787 | 813 | ||
788 | if (ubi->ref_count) { | 814 | if (ubi->ref_count) { |
789 | if (!anyway) { | 815 | if (!anyway) { |
790 | spin_lock(&ubi_devices_lock); | 816 | spin_unlock(&ubi_devices_lock); |
791 | return -EBUSY; | 817 | return -EBUSY; |
792 | } | 818 | } |
793 | /* This may only happen if there is a bug */ | 819 | /* This may only happen if there is a bug */ |
794 | ubi_err("%s reference count %d, destroy anyway", | 820 | ubi_err("%s reference count %d, destroy anyway", |
795 | ubi->ubi_name, ubi->ref_count); | 821 | ubi->ubi_name, ubi->ref_count); |
796 | } | 822 | } |
797 | ubi_devices[ubi->ubi_num] = NULL; | 823 | ubi_devices[ubi_num] = NULL; |
798 | spin_unlock(&ubi_devices_lock); | 824 | spin_unlock(&ubi_devices_lock); |
799 | 825 | ||
800 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num); | 826 | ubi_assert(ubi_num == ubi->ubi_num); |
827 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); | ||
801 | 828 | ||
802 | /* | 829 | /* |
803 | * Before freeing anything, we have to stop the background thread to | 830 | * Before freeing anything, we have to stop the background thread to |
@@ -935,7 +962,8 @@ static int __init ubi_init(void) | |||
935 | } | 962 | } |
936 | 963 | ||
937 | mutex_lock(&ubi_devices_mutex); | 964 | mutex_lock(&ubi_devices_mutex); |
938 | err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs); | 965 | err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, |
966 | p->vid_hdr_offs); | ||
939 | mutex_unlock(&ubi_devices_mutex); | 967 | mutex_unlock(&ubi_devices_mutex); |
940 | if (err < 0) { | 968 | if (err < 0) { |
941 | put_mtd_device(mtd); | 969 | put_mtd_device(mtd); |