mtd: add BLKPG API based repartition support
authorRoman Tereshonkov <roman.tereshonkov@nokia.com>
Fri, 17 Sep 2010 10:31:42 +0000 (13:31 +0300)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sun, 24 Oct 2010 23:48:49 +0000 (00:48 +0100)
Add support for mtd repartition based on the block
device BLKPG interface:
BLKPG_ADD_PARTITION - for partition creation;
BLKPG_DEL_PARTITION - for partition delete

The usage is based on BLKPG ioctl called with
struct blkpg_ioctl_arg argument which includes the
reference to struct blkpg_partition discribing the
partition offset and length.

Disadvantage: there is no implementation for mtd
flags control. The flags are always borrowed from
the master device.

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>
drivers/mtd/mtdchar.c

index 5895de7018d4facfeca14c5f07220cfe525e20ac..b7ed09c579031fed9c77d2cbdca1035f3a3d5ba9 100644 (file)
@@ -30,8 +30,9 @@
 #include <linux/backing-dev.h>
 #include <linux/compat.h>
 #include <linux/mount.h>
-
+#include <linux/blkpg.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 #include <linux/mtd/map.h>
 
 #include <asm/uaccess.h>
@@ -510,6 +511,45 @@ static int shrink_ecclayout(const struct nand_ecclayout *from,
        return 0;
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+static int mtd_blkpg_ioctl(struct mtd_info *mtd,
+                          struct blkpg_ioctl_arg __user *arg)
+{
+       struct blkpg_ioctl_arg a;
+       struct blkpg_partition p;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /* Only master mtd device must be used to control partitions */
+       if (!mtd_is_master(mtd))
+               return -EINVAL;
+
+       if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+               return -EFAULT;
+
+       if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+               return -EFAULT;
+
+       switch (a.op) {
+       case BLKPG_ADD_PARTITION:
+
+               return mtd_add_partition(mtd, p.devname, p.start, p.length);
+
+       case BLKPG_DEL_PARTITION:
+
+               if (p.pno < 0)
+                       return -EINVAL;
+
+               return mtd_del_partition(mtd, p.pno);
+
+       default:
+               return -EINVAL;
+       }
+}
+#endif
+
+
 static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        struct mtd_file_info *mfi = file->private_data;
@@ -900,6 +940,22 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
                break;
        }
 
+#ifdef CONFIG_MTD_PARTITIONS
+       case BLKPG:
+       {
+               ret = mtd_blkpg_ioctl(mtd,
+                     (struct blkpg_ioctl_arg __user *)arg);
+               break;
+       }
+
+       case BLKRRPART:
+       {
+               /* No reread partition feature. Just return ok */
+               ret = 0;
+               break;
+       }
+#endif
+
        default:
                ret = -ENOTTY;
        }
@@ -1078,7 +1134,7 @@ static int mtd_inodefs_get_sb(struct file_system_type *fs_type, int flags,
                                const char *dev_name, void *data,
                                struct vfsmount *mnt)
 {
-        return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC,
+       return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC,
                              mnt);
 }