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 | |
parent | 9b79cc0f84edecceb04b806b9014fcec1306c34d (diff) |
UBI: handle attach ioctl
Actually implement the MTD device attach/detach handlers.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
-rw-r--r-- | drivers/mtd/ubi/build.c | 80 | ||||
-rw-r--r-- | drivers/mtd/ubi/cdev.c | 95 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 2 |
3 files changed, 135 insertions, 42 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); |
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 01978b57e9cb..a60a3a24c2a1 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c | |||
@@ -44,17 +44,6 @@ | |||
44 | #include <asm/div64.h> | 44 | #include <asm/div64.h> |
45 | #include "ubi.h" | 45 | #include "ubi.h" |
46 | 46 | ||
47 | /* | ||
48 | * Maximum sequence numbers of UBI and volume character device IOCTLs (direct | ||
49 | * logical eraseblock erase is a debug-only feature). | ||
50 | */ | ||
51 | #define UBI_CDEV_IOC_MAX_SEQ 2 | ||
52 | #ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO | ||
53 | #define VOL_CDEV_IOC_MAX_SEQ 1 | ||
54 | #else | ||
55 | #define VOL_CDEV_IOC_MAX_SEQ 2 | ||
56 | #endif | ||
57 | |||
58 | /** | 47 | /** |
59 | * get_exclusive - get exclusive access to an UBI volume. | 48 | * get_exclusive - get exclusive access to an UBI volume. |
60 | * @desc: volume descriptor | 49 | * @desc: volume descriptor |
@@ -582,8 +571,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
582 | struct ubi_mkvol_req req; | 571 | struct ubi_mkvol_req req; |
583 | 572 | ||
584 | dbg_msg("create volume"); | 573 | dbg_msg("create volume"); |
585 | err = copy_from_user(&req, argp, | 574 | err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); |
586 | sizeof(struct ubi_mkvol_req)); | ||
587 | if (err) { | 575 | if (err) { |
588 | err = -EFAULT; | 576 | err = -EFAULT; |
589 | break; | 577 | break; |
@@ -647,8 +635,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
647 | struct ubi_rsvol_req req; | 635 | struct ubi_rsvol_req req; |
648 | 636 | ||
649 | dbg_msg("re-size volume"); | 637 | dbg_msg("re-size volume"); |
650 | err = copy_from_user(&req, argp, | 638 | err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); |
651 | sizeof(struct ubi_rsvol_req)); | ||
652 | if (err) { | 639 | if (err) { |
653 | err = -EFAULT; | 640 | err = -EFAULT; |
654 | break; | 641 | break; |
@@ -684,8 +671,86 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
684 | return err; | 671 | return err; |
685 | } | 672 | } |
686 | 673 | ||
674 | static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, | ||
675 | unsigned int cmd, unsigned long arg) | ||
676 | { | ||
677 | int err = 0; | ||
678 | void __user *argp = (void __user *)arg; | ||
679 | |||
680 | if (!capable(CAP_SYS_RESOURCE)) | ||
681 | return -EPERM; | ||
682 | |||
683 | switch (cmd) { | ||
684 | /* Attach an MTD device command */ | ||
685 | case UBI_IOCATT: | ||
686 | { | ||
687 | struct ubi_attach_req req; | ||
688 | struct mtd_info *mtd; | ||
689 | |||
690 | dbg_msg("attach MTD device"); | ||
691 | err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); | ||
692 | if (err) { | ||
693 | err = -EFAULT; | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | if (req.mtd_num < 0 || | ||
698 | (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) { | ||
699 | err = -EINVAL; | ||
700 | break; | ||
701 | } | ||
702 | |||
703 | mtd = get_mtd_device(NULL, req.mtd_num); | ||
704 | if (IS_ERR(mtd)) { | ||
705 | err = PTR_ERR(mtd); | ||
706 | break; | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Note, further request verification is done by | ||
711 | * 'ubi_attach_mtd_dev()'. | ||
712 | */ | ||
713 | mutex_lock(&ubi_devices_mutex); | ||
714 | err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset); | ||
715 | mutex_unlock(&ubi_devices_mutex); | ||
716 | if (err < 0) | ||
717 | put_mtd_device(mtd); | ||
718 | else | ||
719 | /* @err contains UBI device number */ | ||
720 | err = put_user(err, (__user int32_t *)argp); | ||
721 | |||
722 | break; | ||
723 | } | ||
724 | |||
725 | /* Detach an MTD device command */ | ||
726 | case UBI_IOCDET: | ||
727 | { | ||
728 | int ubi_num; | ||
729 | |||
730 | dbg_msg("dettach MTD device"); | ||
731 | err = get_user(ubi_num, (__user int32_t *)argp); | ||
732 | if (err) { | ||
733 | err = -EFAULT; | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | mutex_lock(&ubi_devices_mutex); | ||
738 | err = ubi_detach_mtd_dev(ubi_num, 0); | ||
739 | mutex_unlock(&ubi_devices_mutex); | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | default: | ||
744 | err = -ENOTTY; | ||
745 | break; | ||
746 | } | ||
747 | |||
748 | return err; | ||
749 | } | ||
750 | |||
687 | /* UBI control character device operations */ | 751 | /* UBI control character device operations */ |
688 | struct file_operations ubi_ctrl_cdev_operations = { | 752 | struct file_operations ubi_ctrl_cdev_operations = { |
753 | .ioctl = ctrl_cdev_ioctl, | ||
689 | .owner = THIS_MODULE, | 754 | .owner = THIS_MODULE, |
690 | }; | 755 | }; |
691 | 756 | ||
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 4c3607e5743e..2a6171226f1f 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
@@ -483,7 +483,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, | |||
483 | struct ubi_vid_hdr *vid_hdr); | 483 | struct ubi_vid_hdr *vid_hdr); |
484 | 484 | ||
485 | /* build.c */ | 485 | /* build.c */ |
486 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset); | 486 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); |
487 | int ubi_detach_mtd_dev(int ubi_num, int anyway); | 487 | int ubi_detach_mtd_dev(int ubi_num, int anyway); |
488 | struct ubi_device *ubi_get_device(int ubi_num); | 488 | struct ubi_device *ubi_get_device(int ubi_num); |
489 | void ubi_put_device(struct ubi_device *ubi); | 489 | void ubi_put_device(struct ubi_device *ubi); |