aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/ubi/build.c80
-rw-r--r--drivers/mtd/ubi/cdev.c95
-rw-r--r--drivers/mtd/ubi/ubi.h2
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 */
635int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) 636int 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
745out_uif: 771out_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
674static 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 */
688struct file_operations ubi_ctrl_cdev_operations = { 752struct 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 */
486int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset); 486int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset);
487int ubi_detach_mtd_dev(int ubi_num, int anyway); 487int ubi_detach_mtd_dev(int ubi_num, int anyway);
488struct ubi_device *ubi_get_device(int ubi_num); 488struct ubi_device *ubi_get_device(int ubi_num);
489void ubi_put_device(struct ubi_device *ubi); 489void ubi_put_device(struct ubi_device *ubi);