diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-17 13:33:20 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-26 12:15:17 -0500 |
commit | cdfa788acd134a35d3e5b73d1a76fca4033d8aa9 (patch) | |
tree | ccc8cbf0bad80f569d9e3bbdc7cbf9c97556f155 /drivers/mtd/ubi/build.c | |
parent | e73f4459d969bb266f03dd4cbe21bdba8cb2732c (diff) |
UBI: prepare attach and detach functions
Prepare the attach and detach functions to by used outside of
module initialization:
* detach function checks reference count before detaching
* it kills the background thread as well
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 | 235 |
1 files changed, 162 insertions, 73 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a4faf71ee3f2..071454376643 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/stat.h> | 40 | #include <linux/stat.h> |
41 | #include <linux/miscdevice.h> | 41 | #include <linux/miscdevice.h> |
42 | #include <linux/log2.h> | 42 | #include <linux/log2.h> |
43 | #include <linux/kthread.h> | ||
43 | #include "ubi.h" | 44 | #include "ubi.h" |
44 | 45 | ||
45 | /* Maximum length of the 'mtd=' parameter */ | 46 | /* Maximum length of the 'mtd=' parameter */ |
@@ -83,6 +84,9 @@ static struct miscdevice ubi_ctrl_cdev = { | |||
83 | /* All UBI devices in system */ | 84 | /* All UBI devices in system */ |
84 | static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; | 85 | static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; |
85 | 86 | ||
87 | /* Serializes UBI devices creations and removals */ | ||
88 | DEFINE_MUTEX(ubi_devices_mutex); | ||
89 | |||
86 | /* Protects @ubi_devices and @ubi->ref_count */ | 90 | /* Protects @ubi_devices and @ubi->ref_count */ |
87 | static DEFINE_SPINLOCK(ubi_devices_lock); | 91 | static DEFINE_SPINLOCK(ubi_devices_lock); |
88 | 92 | ||
@@ -192,7 +196,7 @@ struct ubi_device *ubi_get_by_major(int major) | |||
192 | * @major: major number | 196 | * @major: major number |
193 | * | 197 | * |
194 | * This function searches UBI device number object by its major number. If UBI | 198 | * This function searches UBI device number object by its major number. If UBI |
195 | * device was not found, this function returns -ENODEV, othewise the UBI device | 199 | * device was not found, this function returns -ENODEV, otherwise the UBI device |
196 | * number is returned. | 200 | * number is returned. |
197 | */ | 201 | */ |
198 | int ubi_major2num(int major) | 202 | int ubi_major2num(int major) |
@@ -485,9 +489,9 @@ out_si: | |||
485 | * assumed: | 489 | * assumed: |
486 | * o EC header is always at offset zero - this cannot be changed; | 490 | * o EC header is always at offset zero - this cannot be changed; |
487 | * o VID header starts just after the EC header at the closest address | 491 | * o VID header starts just after the EC header at the closest address |
488 | * aligned to @io->@hdrs_min_io_size; | 492 | * aligned to @io->hdrs_min_io_size; |
489 | * o data starts just after the VID header at the closest address aligned to | 493 | * o data starts just after the VID header at the closest address aligned to |
490 | * @io->@min_io_size | 494 | * @io->min_io_size |
491 | * | 495 | * |
492 | * This function returns zero in case of success and a negative error code in | 496 | * This function returns zero in case of success and a negative error code in |
493 | * case of failure. | 497 | * case of failure. |
@@ -508,6 +512,9 @@ static int io_init(struct ubi_device *ubi) | |||
508 | return -EINVAL; | 512 | return -EINVAL; |
509 | } | 513 | } |
510 | 514 | ||
515 | if (ubi->vid_hdr_offset < 0 || ubi->leb_start < ubi->vid_hdr_offset) | ||
516 | return -EINVAL; | ||
517 | |||
511 | /* | 518 | /* |
512 | * Note, in this implementation we support MTD devices with 0x7FFFFFFF | 519 | * Note, in this implementation we support MTD devices with 0x7FFFFFFF |
513 | * physical eraseblocks maximum. | 520 | * physical eraseblocks maximum. |
@@ -616,84 +623,62 @@ static int io_init(struct ubi_device *ubi) | |||
616 | } | 623 | } |
617 | 624 | ||
618 | /** | 625 | /** |
619 | * attach_mtd_dev - attach an MTD device. | 626 | * ubi_attach_mtd_dev - attach an MTD device. |
620 | * @mtd_dev: MTD device name or number string | 627 | * @mtd_dev: MTD device description object |
621 | * @vid_hdr_offset: VID header offset | 628 | * @vid_hdr_offset: VID header offset |
622 | * @data_offset: data offset | 629 | * @data_offset: data offset |
623 | * | 630 | * |
624 | * This function attaches an MTD device to UBI. It first treats @mtd_dev as the | 631 | * This function attaches an MTD device to UBI. It first treats @mtd_dev as the |
625 | * MTD device name, and tries to open it by this name. If it is unable to open, | 632 | * MTD device name, and tries to open it by this name. If it is unable to open, |
626 | * it tries to convert @mtd_dev to an integer and open the MTD device by its | 633 | * it tries to convert @mtd_dev to an integer and open the MTD device by its |
627 | * number. Returns zero in case of success and a negative error code in case of | 634 | * number. Returns new UBI device's number in case of success and a negative |
628 | * failure. | 635 | * error code in case of failure. |
636 | * | ||
637 | * Note, the invocations of this function has to be serialized by the | ||
638 | * @ubi_devices_mutex. | ||
629 | */ | 639 | */ |
630 | static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | 640 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset, |
631 | int data_offset) | 641 | int data_offset) |
632 | { | 642 | { |
633 | struct ubi_device *ubi; | 643 | struct ubi_device *ubi; |
634 | struct mtd_info *mtd; | ||
635 | int i, err; | 644 | int i, err; |
636 | 645 | ||
637 | mtd = get_mtd_device_nm(mtd_dev); | 646 | /* |
638 | if (IS_ERR(mtd)) { | 647 | * Check if we already have the same MTD device attached. |
639 | int mtd_num; | 648 | * |
640 | char *endp; | 649 | * Note, this function assumes that UBI devices creations and deletions |
641 | 650 | * are serialized, so it does not take the &ubi_devices_lock. | |
642 | if (PTR_ERR(mtd) != -ENODEV) | 651 | */ |
643 | return PTR_ERR(mtd); | ||
644 | |||
645 | /* | ||
646 | * Probably this is not MTD device name but MTD device number - | ||
647 | * check this out. | ||
648 | */ | ||
649 | mtd_num = simple_strtoul(mtd_dev, &endp, 0); | ||
650 | if (*endp != '\0' || mtd_dev == endp) { | ||
651 | ubi_err("incorrect MTD device: \"%s\"", mtd_dev); | ||
652 | return -ENODEV; | ||
653 | } | ||
654 | |||
655 | mtd = get_mtd_device(NULL, mtd_num); | ||
656 | if (IS_ERR(mtd)) | ||
657 | return PTR_ERR(mtd); | ||
658 | } | ||
659 | |||
660 | /* Check if we already have the same MTD device attached */ | ||
661 | for (i = 0; i < UBI_MAX_DEVICES; i++) | 652 | for (i = 0; i < UBI_MAX_DEVICES; i++) |
662 | ubi = ubi_devices[i]; | 653 | ubi = ubi_devices[i]; |
663 | if (ubi && ubi->mtd->index == mtd->index) { | 654 | if (ubi && mtd->index == ubi->mtd->index) { |
664 | ubi_err("mtd%d is already attached to ubi%d", | 655 | ubi_err("mtd%d is already attached to ubi%d", |
665 | mtd->index, i); | 656 | mtd->index, i); |
666 | err = -EINVAL; | 657 | return -EINVAL; |
667 | goto out_mtd; | ||
668 | } | 658 | } |
669 | 659 | ||
670 | ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); | ||
671 | if (!ubi) { | ||
672 | err = -ENOMEM; | ||
673 | goto out_mtd; | ||
674 | } | ||
675 | |||
676 | ubi->mtd = mtd; | ||
677 | |||
678 | /* Search for an empty slot in the @ubi_devices array */ | 660 | /* Search for an empty slot in the @ubi_devices array */ |
679 | ubi->ubi_num = -1; | ||
680 | for (i = 0; i < UBI_MAX_DEVICES; i++) | 661 | for (i = 0; i < UBI_MAX_DEVICES; i++) |
681 | if (!ubi_devices[i]) { | 662 | if (!ubi_devices[i]) |
682 | ubi->ubi_num = i; | ||
683 | break; | 663 | break; |
684 | } | ||
685 | 664 | ||
686 | if (ubi->ubi_num == -1) { | 665 | if (i == UBI_MAX_DEVICES) { |
687 | ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); | 666 | ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); |
688 | err = -ENFILE; | 667 | return -ENFILE; |
689 | goto out_free; | ||
690 | } | 668 | } |
691 | 669 | ||
692 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", | 670 | ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); |
693 | ubi->mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); | 671 | if (!ubi) |
672 | return -ENOMEM; | ||
694 | 673 | ||
674 | ubi->mtd = mtd; | ||
675 | ubi->ubi_num = i; | ||
695 | ubi->vid_hdr_offset = vid_hdr_offset; | 676 | ubi->vid_hdr_offset = vid_hdr_offset; |
696 | ubi->leb_start = data_offset; | 677 | ubi->leb_start = data_offset; |
678 | |||
679 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", | ||
680 | mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); | ||
681 | |||
697 | err = io_init(ubi); | 682 | err = io_init(ubi); |
698 | if (err) | 683 | if (err) |
699 | goto out_free; | 684 | goto out_free; |
@@ -724,8 +709,16 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | |||
724 | if (err) | 709 | if (err) |
725 | goto out_detach; | 710 | goto out_detach; |
726 | 711 | ||
727 | ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi->ubi_num); | 712 | ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); |
728 | ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); | 713 | if (IS_ERR(ubi->bgt_thread)) { |
714 | err = PTR_ERR(ubi->bgt_thread); | ||
715 | ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, | ||
716 | err); | ||
717 | goto out_uif; | ||
718 | } | ||
719 | |||
720 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num); | ||
721 | ubi_msg("MTD device name: \"%s\"", mtd->name); | ||
729 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); | 722 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); |
730 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", | 723 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", |
731 | ubi->peb_size, ubi->peb_size >> 10); | 724 | ubi->peb_size, ubi->peb_size >> 10); |
@@ -754,8 +747,10 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | |||
754 | } | 747 | } |
755 | 748 | ||
756 | ubi_devices[ubi->ubi_num] = ubi; | 749 | ubi_devices[ubi->ubi_num] = ubi; |
757 | return 0; | 750 | return ubi->ubi_num; |
758 | 751 | ||
752 | out_uif: | ||
753 | uif_close(ubi); | ||
759 | out_detach: | 754 | out_detach: |
760 | ubi_eba_close(ubi); | 755 | ubi_eba_close(ubi); |
761 | ubi_wl_close(ubi); | 756 | ubi_wl_close(ubi); |
@@ -767,21 +762,57 @@ out_free: | |||
767 | vfree(ubi->dbg_peb_buf); | 762 | vfree(ubi->dbg_peb_buf); |
768 | #endif | 763 | #endif |
769 | kfree(ubi); | 764 | kfree(ubi); |
770 | out_mtd: | ||
771 | put_mtd_device(mtd); | ||
772 | return err; | 765 | return err; |
773 | } | 766 | } |
774 | 767 | ||
775 | /** | 768 | /** |
776 | * detach_mtd_dev - detach an MTD device. | 769 | * ubi_detach_mtd_dev - detach an MTD device. |
777 | * @ubi: UBI device description object | 770 | * @ubi_num: UBI device number to detach from |
771 | * @anyway: detach MTD even if device reference count is not zero | ||
772 | * | ||
773 | * This function destroys an UBI device number @ubi_num and detaches the | ||
774 | * underlying MTD device. Returns zero in case of success and %-EBUSY if the | ||
775 | * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not | ||
776 | * exist. | ||
777 | * | ||
778 | * Note, the invocations of this function has to be serialized by the | ||
779 | * @ubi_devices_mutex. | ||
778 | */ | 780 | */ |
779 | static void detach_mtd_dev(struct ubi_device *ubi) | 781 | int ubi_detach_mtd_dev(int ubi_num, int anyway) |
780 | { | 782 | { |
781 | int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; | 783 | struct ubi_device *ubi; |
784 | |||
785 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) | ||
786 | return -EINVAL; | ||
787 | |||
788 | spin_lock(&ubi_devices_lock); | ||
789 | ubi = ubi_devices[ubi_num]; | ||
790 | if (!ubi) { | ||
791 | spin_lock(&ubi_devices_lock); | ||
792 | return -EINVAL; | ||
793 | } | ||
794 | |||
795 | if (ubi->ref_count) { | ||
796 | if (!anyway) { | ||
797 | spin_lock(&ubi_devices_lock); | ||
798 | return -EBUSY; | ||
799 | } | ||
800 | /* This may only happen if there is a bug */ | ||
801 | ubi_err("%s reference count %d, destroy anyway", | ||
802 | ubi->ubi_name, ubi->ref_count); | ||
803 | } | ||
804 | ubi_devices[ubi->ubi_num] = NULL; | ||
805 | spin_unlock(&ubi_devices_lock); | ||
806 | |||
807 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num); | ||
808 | |||
809 | /* | ||
810 | * Before freeing anything, we have to stop the background thread to | ||
811 | * prevent it from doing anything on this device while we are freeing. | ||
812 | */ | ||
813 | if (ubi->bgt_thread) | ||
814 | kthread_stop(ubi->bgt_thread); | ||
782 | 815 | ||
783 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); | ||
784 | ubi_assert(ubi->ref_count == 0); | ||
785 | uif_close(ubi); | 816 | uif_close(ubi); |
786 | ubi_eba_close(ubi); | 817 | ubi_eba_close(ubi); |
787 | ubi_wl_close(ubi); | 818 | ubi_wl_close(ubi); |
@@ -792,9 +823,9 @@ static void detach_mtd_dev(struct ubi_device *ubi) | |||
792 | #ifdef CONFIG_MTD_UBI_DEBUG | 823 | #ifdef CONFIG_MTD_UBI_DEBUG |
793 | vfree(ubi->dbg_peb_buf); | 824 | vfree(ubi->dbg_peb_buf); |
794 | #endif | 825 | #endif |
795 | kfree(ubi_devices[ubi_num]); | 826 | ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); |
796 | ubi_devices[ubi_num] = NULL; | 827 | kfree(ubi); |
797 | ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); | 828 | return 0; |
798 | } | 829 | } |
799 | 830 | ||
800 | /** | 831 | /** |
@@ -811,6 +842,46 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) | |||
811 | init_rwsem(&le->mutex); | 842 | init_rwsem(&le->mutex); |
812 | } | 843 | } |
813 | 844 | ||
845 | /** | ||
846 | * find_mtd_device - open an MTD device by its name or number. | ||
847 | * @mtd_dev: name or number of the device | ||
848 | * | ||
849 | * This function tries to open and MTD device with name @mtd_dev, and if it | ||
850 | * fails, then it tries to interpret the @mtd_dev string as an ASCII-coded | ||
851 | * integer and open an MTD device with this number. Returns MTD device | ||
852 | * description object in case of success and a negative error code in case of | ||
853 | * failure. | ||
854 | */ | ||
855 | static struct mtd_info * __init open_mtd_device(const char *mtd_dev) | ||
856 | { | ||
857 | struct mtd_info *mtd; | ||
858 | |||
859 | mtd = get_mtd_device_nm(mtd_dev); | ||
860 | if (IS_ERR(mtd)) { | ||
861 | int mtd_num; | ||
862 | char *endp; | ||
863 | |||
864 | if (PTR_ERR(mtd) != -ENODEV) | ||
865 | return mtd; | ||
866 | |||
867 | /* | ||
868 | * Probably this is not MTD device name but MTD device number - | ||
869 | * check this out. | ||
870 | */ | ||
871 | mtd_num = simple_strtoul(mtd_dev, &endp, 0); | ||
872 | if (*endp != '\0' || mtd_dev == endp) { | ||
873 | ubi_err("incorrect MTD device: \"%s\"", mtd_dev); | ||
874 | return ERR_PTR(-ENODEV); | ||
875 | } | ||
876 | |||
877 | mtd = get_mtd_device(NULL, mtd_num); | ||
878 | if (IS_ERR(mtd)) | ||
879 | return mtd; | ||
880 | } | ||
881 | |||
882 | return mtd; | ||
883 | } | ||
884 | |||
814 | static int __init ubi_init(void) | 885 | static int __init ubi_init(void) |
815 | { | 886 | { |
816 | int err, i, k; | 887 | int err, i, k; |
@@ -860,10 +931,21 @@ static int __init ubi_init(void) | |||
860 | /* Attach MTD devices */ | 931 | /* Attach MTD devices */ |
861 | for (i = 0; i < mtd_devs; i++) { | 932 | for (i = 0; i < mtd_devs; i++) { |
862 | struct mtd_dev_param *p = &mtd_dev_param[i]; | 933 | struct mtd_dev_param *p = &mtd_dev_param[i]; |
934 | struct mtd_info *mtd; | ||
863 | 935 | ||
864 | cond_resched(); | 936 | cond_resched(); |
865 | err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); | 937 | |
866 | if (err) { | 938 | mtd = open_mtd_device(p->name); |
939 | if (IS_ERR(mtd)) { | ||
940 | err = PTR_ERR(mtd); | ||
941 | goto out_detach; | ||
942 | } | ||
943 | |||
944 | mutex_lock(&ubi_devices_mutex); | ||
945 | err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs, p->data_offs); | ||
946 | mutex_unlock(&ubi_devices_mutex); | ||
947 | if (err < 0) { | ||
948 | put_mtd_device(mtd); | ||
867 | printk(KERN_ERR "UBI error: cannot attach %s\n", | 949 | printk(KERN_ERR "UBI error: cannot attach %s\n", |
868 | p->name); | 950 | p->name); |
869 | goto out_detach; | 951 | goto out_detach; |
@@ -874,7 +956,11 @@ static int __init ubi_init(void) | |||
874 | 956 | ||
875 | out_detach: | 957 | out_detach: |
876 | for (k = 0; k < i; k++) | 958 | for (k = 0; k < i; k++) |
877 | detach_mtd_dev(ubi_devices[k]); | 959 | if (ubi_devices[k]) { |
960 | mutex_lock(&ubi_devices_mutex); | ||
961 | ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1); | ||
962 | mutex_unlock(&ubi_devices_mutex); | ||
963 | } | ||
878 | kmem_cache_destroy(ubi_wl_entry_slab); | 964 | kmem_cache_destroy(ubi_wl_entry_slab); |
879 | out_ltree: | 965 | out_ltree: |
880 | kmem_cache_destroy(ubi_ltree_slab); | 966 | kmem_cache_destroy(ubi_ltree_slab); |
@@ -895,8 +981,11 @@ static void __exit ubi_exit(void) | |||
895 | int i; | 981 | int i; |
896 | 982 | ||
897 | for (i = 0; i < UBI_MAX_DEVICES; i++) | 983 | for (i = 0; i < UBI_MAX_DEVICES; i++) |
898 | if (ubi_devices[i]) | 984 | if (ubi_devices[i]) { |
899 | detach_mtd_dev(ubi_devices[i]); | 985 | mutex_lock(&ubi_devices_mutex); |
986 | ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1); | ||
987 | mutex_unlock(&ubi_devices_mutex); | ||
988 | } | ||
900 | kmem_cache_destroy(ubi_wl_entry_slab); | 989 | kmem_cache_destroy(ubi_wl_entry_slab); |
901 | kmem_cache_destroy(ubi_ltree_slab); | 990 | kmem_cache_destroy(ubi_ltree_slab); |
902 | misc_deregister(&ubi_ctrl_cdev); | 991 | misc_deregister(&ubi_ctrl_cdev); |