Patchwork [3/4] mtd: add MTDREPARTITION ioctl

login
register
mail settings
Submitter Roman Tereshonkov
Date June 18, 2010, 10:08 a.m.
Message ID <1276855711-18570-4-git-send-email-roman.tereshonkov@nokia.com>
Download mbox | patch
Permalink /patch/56161/
State New
Headers show

Comments

Roman Tereshonkov - June 18, 2010, 10:08 a.m.
Add MTDREPARTITION ioctl to modify all partitions for given mtd
master device. The partitions having the same master are modified
all at once: all previous are deleted and the new set is created.

Signed-off-by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
---
 drivers/mtd/mtdchar.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 109 insertions(+), 1 deletions(-)

Patch

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 91c8013..ccdccad 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -19,7 +19,7 @@ 
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
-
+#include <linux/mtd/partitions.h>
 #include <asm/uaccess.h>
 
 #define MTD_INODE_FS_MAGIC 0x11307854
@@ -463,6 +463,65 @@  static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
 	return ret;
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+static int mtd_do_repartition(struct file *file, struct mtd_info *mtd,
+				uint32_t nparts, void __user *ptr)
+{
+	struct mtd_partition *parts;
+	struct mtd_partition_user *up;
+	int size, i, ret = -ENOMEM;
+
+	if (!(file->f_mode & FMODE_WRITE))
+		return -EPERM;
+
+	size = nparts * sizeof(struct mtd_partition_user);
+	if (!size)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_READ, ptr, size))
+		return -EFAULT;
+
+	up = kmalloc(size, GFP_KERNEL);
+	if (!up)
+		return -ENOMEM;
+
+	if (copy_from_user(up, ptr, size)) {
+		ret = -EFAULT;
+		goto err_free_up;
+	}
+
+	size = nparts * sizeof(struct mtd_partition);
+	parts = kzalloc(size, GFP_KERNEL);
+	if (!parts)
+		goto err_free_up;
+
+	for (i = 0; i < nparts; i++) {
+		parts[i].offset = up[i].offset;
+		parts[i].size = up[i].size;
+		parts[i].mask_flags = up[i].mask_flags;
+
+		parts[i].name = kstrndup(up[i].name, MTD_MAX_PARTITION_NAME_LEN,
+					 GFP_KERNEL);
+		if (!parts[i].name)
+			goto err_free;
+	}
+
+	ret = del_mtd_partitions(mtd);
+	if (!ret)
+		ret = add_mtd_partitions(mtd, parts, nparts);
+
+ err_free:
+	for (i = 0; i < nparts; i++)
+		kfree(parts[i].name);
+	kfree(parts);
+ err_free_up:
+	kfree(up);
+
+	return ret;
+}
+#endif
+
+
 static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 	struct mtd_file_info *mfi = file->private_data;
@@ -826,7 +885,25 @@  static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
 		file->f_pos = 0;
 		break;
 	}
+#ifdef CONFIG_MTD_PARTITIONS
+	case MTDREPARTITION:
+	{
+		struct mtd_partitions p;
+		struct mtd_info *master;
+
+		/* only root (no assigned master) device can be accessed */
+		master = part_get_mtd_master(mtd);
+		if (master)
+			return -EACCES;
+
+		if (copy_from_user(&p, argp, sizeof(p)))
+			return -EFAULT;
+
+		ret = mtd_do_repartition(file, mtd, p.nparts, p.parts);
 
+		break;
+	}
+#endif
 	default:
 		ret = -ENOTTY;
 	}
@@ -856,6 +933,15 @@  struct mtd_oob_buf32 {
 #define MEMWRITEOOB32		_IOWR('M', 3, struct mtd_oob_buf32)
 #define MEMREADOOB32		_IOWR('M', 4, struct mtd_oob_buf32)
 
+#ifdef CONFIG_MTD_PARTITIONS
+struct mtd_partitions32 {
+	uint32_t nparts;
+	compat_caddr_t ptr;
+};
+
+#define MTDREPARTITION32	_IOW('M', 23, struct mtd_partitions32)
+#endif
+
 static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
@@ -895,6 +981,28 @@  static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
 				&buf_user->start);
 		break;
 	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	case MTDREPARTITION32:
+	{
+		struct mtd_partitions32 p;
+		struct mtd_info *master;
+
+		/* only root (no assigned master) device can be accessed */
+		master = part_get_mtd_master(mtd);
+		if (!master) {
+			if (copy_from_user(&p, argp, sizeof(p)))
+				ret = -EFAULT;
+			else
+				ret = mtd_do_repartition(file, mtd, p.nparts,
+							 compat_ptr(p.ptr));
+		} else {
+			ret = -EACCES;
+		}
+
+		break;
+	}
+#endif
 	default:
 		ret = mtd_ioctl(file, cmd, (unsigned long)argp);
 	}