All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] UBI: make UBI devices dynamic
@ 2007-12-20 14:22 Artem Bityutskiy
  2007-12-20 14:22 ` [PATCH v2 1/6] UBI: add UBI control device Artem Bityutskiy
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:22 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1368 bytes --]

Hi,

here is the second iteration of the patch-set. Changes (were
requested by Arnd):

* data_offset is removed as it makes no sens to set it to anything
  but the default value
* UBI control device is now registered as "misc" device, so we
  do not waste Linux major/minor numbers
* More commentaries in the ubi-user.h file

The ltree slab cache is not removed, it will be done separately.

The original message
~~~~~~~~~~~~~~~~~~~~

here is a patch-set which makes UBI devices dynamic. This means,
that you may attach/detach MTD devices run-time, not just when
UBI module is loaded/unloaded. This is very convenient - you do
may compile UBI into the kernel and attach/detach needed MTD
devices later, when your init scripts (loaded from initrd) decide
which exactly MTD device(s) to attach. This also makes testing
a lot easier.

The idea is similar to what the device mapper has: UBI creates
an UBI control device, which registers itself in UBI sysfs
hierarchy (/sys/class/ubi/ubi_ctrl) with dynamically allocated
major and minor numbers. The control device has 2 ioctls -
attach MTD device and detach MTD device.

This patch-set applies on top of my other UBI changes and fixes,
which you may find in the UBI git.

I CC Frank and Andreas, as one of the main UBI users. I CC
Arnd as an ioctl expert.

--
Best regards,
Artem Bityutskiy (Битюцкий Артём)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/6] UBI: add UBI control device
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
@ 2007-12-20 14:22 ` Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 2/6] UBI: add UBI devices reference counting Artem Bityutskiy
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:22 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From 028997ff1dca743d538187962133ea77aefbc510 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Sun, 16 Dec 2007 16:59:31 +0200
Subject: [PATCH] UBI: add UBI control device

This patch is a preparation to make UBI devices dynamic. It
adds an UBI control device which has dynamically allocated
major number and registers itself as "ubi_ctrl". It does not
do anything so far. The idea is that this device will allow
to attach/detach MTD devices from userspace.

This is symilar to what the Linux device mapper has.

The next things to do are:
* Fix UBI, because it now assumes UBI devices cannot go away
* Implement control device ioctls which will attach/detach MTD
  devices

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/build.c |   69 ++++++++++++++++++++++++++++++++++++++++-------
 drivers/mtd/ubi/cdev.c  |   10 +++++++
 drivers/mtd/ubi/ubi.h   |    3 +-
 3 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index b3efb2f..8d05d96 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -21,11 +21,16 @@
  */
 
 /*
- * This file includes UBI initialization and building of UBI devices. At the
- * moment UBI devices may only be added while UBI is initialized, but dynamic
- * device add/remove functionality is planned. Also, at the moment we only
- * attach UBI devices by scanning, which will become a bottleneck when flashes
- * reach certain large size. Then one may improve UBI and add other methods.
+ * This file includes UBI initialization and building of UBI devices.
+ *
+ * When UBI is initialized, it attaches all the MTD devices specified as the
+ * module load parameters or the kernel boot parameters. If MTD devices were
+ * specified, UBI does not attach any MTD device, but it is possible to do
+ * later using the "UBI control device".
+ *
+ * At the moment we only attach UBI devices by scanning, which will become a
+ * bottleneck when flashes reach certain large size. Then one may improve UBI
+ * and add other methods, although it does not seem to be easy to do.
  */
 
 #include <linux/err.h>
@@ -70,6 +75,11 @@ struct kmem_cache *ubi_ltree_slab;
 /* Slab cache for wear-leveling entries */
 struct kmem_cache *ubi_wl_entry_slab;
 
+/* UBI control character device major number */
+static int ubi_ctrl_major;
+
+/* Linux device model object corresponding to the control UBI device */
+static struct device ubi_ctrl_dev;
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
 static ssize_t ubi_version_show(struct class *class, char *buf)
@@ -142,6 +152,9 @@ static ssize_t dev_attribute_show(struct device *dev,
 /* Fake "release" method for UBI devices */
 static void dev_release(struct device *dev) { }
 
+/* Fake "release" method for UBI control device */
+static void ctrl_dev_release(struct device *dev) { }
+
 /**
  * ubi_sysfs_init - initialize sysfs for an UBI device.
  * @ubi: UBI device description object
@@ -701,19 +714,45 @@ static int __init ubi_init(void)
 		return -EINVAL;
 	}
 
+	/* Allocate major number for the UBI control device and register it */
+	ubi_ctrl_major = register_chrdev(0, "ubi_ctrl",
+					 &ubi_ctrl_cdev_operations);
+	if (ubi_ctrl_major < 0) {
+		err = ubi_ctrl_major;
+		printk(KERN_ERR "UBI error: cannot register control device\n");
+		return err;
+	}
+
+	/* Create base sysfs directory and sysfs files */
 	ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
-	if (IS_ERR(ubi_class))
-		return PTR_ERR(ubi_class);
+	if (IS_ERR(ubi_class)) {
+		err = PTR_ERR(ubi_class);
+		printk(KERN_ERR "UBI error: cannot create UBI class\n");
+		goto out_cdev_unreg;
+	}
 
 	err = class_create_file(ubi_class, &ubi_version);
-	if (err)
+	if (err) {
+		printk(KERN_ERR "UBI error: cannot create sysfs file\n");
 		goto out_class;
+	}
+
+	/* Register the control device in the Linux device system */
+	ubi_ctrl_dev.release = ctrl_dev_release;
+	ubi_ctrl_dev.devt = MKDEV(ubi_ctrl_major, 0);
+	ubi_ctrl_dev.class = ubi_class;
+	sprintf(&ubi_ctrl_dev.bus_id[0], "ubi_ctrl");
+	err = device_register(&ubi_ctrl_dev);
+	if (err) {
+		printk(KERN_ERR "UBI error: cannot register device\n");
+		goto out_version;
+	}
 
 	ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab",
 					   sizeof(struct ubi_ltree_entry), 0,
 					   0, &ltree_entry_ctor);
 	if (!ubi_ltree_slab)
-		goto out_version;
+		goto out_dev_unreg;
 
 	ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
 						sizeof(struct ubi_wl_entry),
@@ -727,8 +766,11 @@ static int __init ubi_init(void)
 
 		cond_resched();
 		err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
-		if (err)
+		if (err) {
+			printk(KERN_ERR "UBI error: cannot attach %s\n",
+			       p->name);
 			goto out_detach;
+		}
 	}
 
 	return 0;
@@ -739,10 +781,15 @@ out_detach:
 	kmem_cache_destroy(ubi_wl_entry_slab);
 out_ltree:
 	kmem_cache_destroy(ubi_ltree_slab);
+out_dev_unreg:
+	device_unregister(&ubi_ctrl_dev);
 out_version:
 	class_remove_file(ubi_class, &ubi_version);
 out_class:
 	class_destroy(ubi_class);
+out_cdev_unreg:
+	unregister_chrdev(ubi_ctrl_major, "ubi_ctrl");
+	printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
 	return err;
 }
 module_init(ubi_init);
@@ -756,8 +803,10 @@ static void __exit ubi_exit(void)
 			detach_mtd_dev(ubi_devices[i]);
 	kmem_cache_destroy(ubi_wl_entry_slab);
 	kmem_cache_destroy(ubi_ltree_slab);
+	device_unregister(&ubi_ctrl_dev);
 	class_remove_file(ubi_class, &ubi_version);
 	class_destroy(ubi_class);
+	unregister_chrdev(ubi_ctrl_major, "ubi_ctrl");
 }
 module_exit(ubi_exit);
 
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 22c15a3..bc900d2 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -28,6 +28,11 @@
  *
  * Major and minor numbers are assigned dynamically to both UBI and volume
  * character devices.
+ *
+ * Well, there is the third kind of character devices - the UBI control
+ * character device, which allows to manipulate by UBI devices - create and
+ * delete them. In other words, it is used for attaching and detaching MTD
+ * devices.
  */
 
 #include <linux/module.h>
@@ -693,6 +698,11 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 	return err;
 }
 
+/* UBI control character device operations */
+struct file_operations ubi_ctrl_cdev_operations = {
+	.owner = THIS_MODULE,
+};
+
 /* UBI character device operations */
 struct file_operations ubi_cdev_operations = {
 	.owner = THIS_MODULE,
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 994233d..21c0283 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -235,7 +235,7 @@ struct ubi_wl_entry;
 
 /**
  * struct ubi_device - UBI device description structure
- * @dev: class device object to use the the Linux device model
+ * @dev: UBI device object to use the the Linux device model
  * @cdev: character device object to create character device
  * @ubi_num: UBI device number
  * @ubi_name: UBI device name
@@ -398,6 +398,7 @@ struct ubi_device {
 
 extern struct kmem_cache *ubi_ltree_slab;
 extern struct kmem_cache *ubi_wl_entry_slab;
+extern struct file_operations ubi_ctrl_cdev_operations;
 extern struct file_operations ubi_cdev_operations;
 extern struct file_operations ubi_vol_cdev_operations;
 extern struct ubi_device *ubi_devices[];
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/6] UBI: add UBI devices reference counting
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
  2007-12-20 14:22 ` [PATCH v2 1/6] UBI: add UBI control device Artem Bityutskiy
@ 2007-12-20 14:23 ` Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 3/6] UBI: prepare attach and detach functions Artem Bityutskiy
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:23 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From 502c3f72aacff2056497bbbdb219459914a28a7f Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Mon, 17 Dec 2007 17:37:26 +0200
Subject: [PATCH] UBI: add UBI devices reference counting

This is one more step on the way to "removable" UBI devices. It
adds reference counting for UBI devices. Every time a volume on
this device is opened - the device's refcount is increased. It
is also increased if someone is reading any sysfs file of this
UBI device or of one of its volumes.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/build.c |  142 ++++++++++++++++++++++++++++++++++++++++++-----
 drivers/mtd/ubi/cdev.c  |   34 +++--------
 drivers/mtd/ubi/eba.c   |    5 ++
 drivers/mtd/ubi/kapi.c  |   59 ++++++++++++++------
 drivers/mtd/ubi/ubi.h   |    9 +++-
 drivers/mtd/ubi/vmt.c   |   14 +++--
 drivers/mtd/ubi/wl.c    |    1 +
 7 files changed, 201 insertions(+), 63 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 8d05d96..e60a646 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -63,9 +63,6 @@ static int mtd_devs = 0;
 /* MTD devices specification parameters */
 static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
 
-/* All UBI devices in system */
-struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
-
 /* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
 struct class *ubi_class;
 
@@ -81,6 +78,12 @@ static int ubi_ctrl_major;
 /* Linux device model object corresponding to the control UBI device */
 static struct device ubi_ctrl_dev;
 
+/* All UBI devices in system */
+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
+
+/* Protects @ubi_devices and @ubi->ref_count */
+static DEFINE_SPINLOCK(ubi_devices_lock);
+
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
 static ssize_t ubi_version_show(struct class *class, char *buf)
 {
@@ -116,37 +119,145 @@ static struct device_attribute dev_min_io_size =
 static struct device_attribute dev_bgt_enabled =
 	__ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
 
+/**
+ * ubi_get_device - get UBI device.
+ * @ubi_num: UBI device number
+ *
+ * This function returns UBI device description object for UBI device number
+ * @ubi_num, or %NULL if the device does not exist. This function increases the
+ * device reference count to prevent removal of the device. In other words, the
+ * device cannot be removed if its reference count is not zero.
+ */
+struct ubi_device *ubi_get_device(int ubi_num)
+{
+	struct ubi_device *ubi;
+
+	spin_lock(&ubi_devices_lock);
+	ubi = ubi_devices[ubi_num];
+	if (ubi) {
+		ubi_assert(ubi->ref_count >= 0);
+		ubi->ref_count += 1;
+		get_device(&ubi->dev);
+	}
+	spin_unlock(&ubi_devices_lock);
+
+	return ubi;
+}
+
+/**
+ * ubi_put_device - drop an UBI device reference.
+ * @ubi: UBI device description object
+ */
+void ubi_put_device(struct ubi_device *ubi)
+{
+	spin_lock(&ubi_devices_lock);
+	ubi->ref_count -= 1;
+	put_device(&ubi->dev);
+	spin_unlock(&ubi_devices_lock);
+}
+
+/**
+ * ubi_get_by_major - get UBI device description object by character device
+ *                    major number.
+ * @major: major number
+ *
+ * This function is similar to 'ubi_get_device()', but it searches the device
+ * by its major number.
+ */
+struct ubi_device *ubi_get_by_major(int major)
+{
+	int i;
+	struct ubi_device *ubi;
+
+	spin_lock(&ubi_devices_lock);
+	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+		ubi = ubi_devices[i];
+		if (ubi && MAJOR(ubi->cdev.dev) == major) {
+			ubi_assert(ubi->ref_count >= 0);
+			ubi->ref_count += 1;
+			get_device(&ubi->dev);
+			spin_unlock(&ubi_devices_lock);
+			return ubi;
+		}
+	}
+	spin_unlock(&ubi_devices_lock);
+
+	return NULL;
+}
+
+/**
+ * ubi_major2num - get UBI device number by character device major number.
+ * @major: major number
+ *
+ * This function searches UBI device number object by its major number. If UBI
+ * device was not found, this function returns -ENODEV, othewise the UBI device
+ * number is returned.
+ */
+int ubi_major2num(int major)
+{
+	int i, ubi_num = -ENODEV;
+
+	spin_lock(&ubi_devices_lock);
+	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+		struct ubi_device *ubi = ubi_devices[i];
+
+		if (ubi && MAJOR(ubi->cdev.dev) == major) {
+			ubi_num = ubi->ubi_num;
+			break;
+		}
+	}
+	spin_unlock(&ubi_devices_lock);
+
+	return ubi_num;
+}
+
 /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
 static ssize_t dev_attribute_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
-	const struct ubi_device *ubi;
+	ssize_t ret;
+	struct ubi_device *ubi;
 
+	/*
+	 * The below code looks weird, but it actually makes sense. We get the
+	 * UBI device reference from the contained 'struct ubi_device'. But it
+	 * is unclear if the device was removed or not yet. Indeed, if the
+	 * device was removed before we increased its reference count,
+	 * 'ubi_get_device()' will return -ENODEV and we fail.
+	 *
+	 * Remember, 'struct ubi_device' is freed in the release function, so
+	 * we still can use 'ubi->ubi_num'.
+	 */
 	ubi = container_of(dev, struct ubi_device, dev);
+	ubi = ubi_get_device(ubi->ubi_num);
+	if (!ubi)
+		return -ENODEV;
+
 	if (attr == &dev_eraseblock_size)
-		return sprintf(buf, "%d\n", ubi->leb_size);
+		ret = sprintf(buf, "%d\n", ubi->leb_size);
 	else if (attr == &dev_avail_eraseblocks)
-		return sprintf(buf, "%d\n", ubi->avail_pebs);
+		ret = sprintf(buf, "%d\n", ubi->avail_pebs);
 	else if (attr == &dev_total_eraseblocks)
-		return sprintf(buf, "%d\n", ubi->good_peb_count);
+		ret = sprintf(buf, "%d\n", ubi->good_peb_count);
 	else if (attr == &dev_volumes_count)
-		return sprintf(buf, "%d\n", ubi->vol_count);
+		ret = sprintf(buf, "%d\n", ubi->vol_count);
 	else if (attr == &dev_max_ec)
-		return sprintf(buf, "%d\n", ubi->max_ec);
+		ret = sprintf(buf, "%d\n", ubi->max_ec);
 	else if (attr == &dev_reserved_for_bad)
-		return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
+		ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
 	else if (attr == &dev_bad_peb_count)
-		return sprintf(buf, "%d\n", ubi->bad_peb_count);
+		ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
 	else if (attr == &dev_max_vol_count)
-		return sprintf(buf, "%d\n", ubi->vtbl_slots);
+		ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
 	else if (attr == &dev_min_io_size)
-		return sprintf(buf, "%d\n", ubi->min_io_size);
+		ret = sprintf(buf, "%d\n", ubi->min_io_size);
 	else if (attr == &dev_bgt_enabled)
-		return sprintf(buf, "%d\n", ubi->thread_enabled);
+		ret = sprintf(buf, "%d\n", ubi->thread_enabled);
 	else
 		BUG();
 
-	return 0;
+	ubi_put_device(ubi);
+	return ret;
 }
 
 /* Fake "release" method for UBI devices */
@@ -671,6 +782,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
 	int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
 
 	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+	ubi_assert(ubi->ref_count == 0);
 	uif_close(ubi);
 	ubi_eba_close(ubi);
 	ubi_wl_close(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index bc900d2..01978b5 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -56,23 +56,6 @@
 #endif
 
 /**
- * major_to_device - get UBI device object by character device major number.
- * @major: major number
- *
- * This function returns a pointer to the UBI device object.
- */
-static struct ubi_device *major_to_device(int major)
-{
-	int i;
-
-	for (i = 0; i < UBI_MAX_DEVICES; i++)
-		if (ubi_devices[i] && MAJOR(ubi_devices[i]->cdev.dev) == major)
-			return ubi_devices[i];
-	BUG();
-	return NULL;
-}
-
-/**
  * get_exclusive - get exclusive access to an UBI volume.
  * @desc: volume descriptor
  *
@@ -129,9 +112,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
 static int vol_cdev_open(struct inode *inode, struct file *file)
 {
 	struct ubi_volume_desc *desc;
-	const struct ubi_device *ubi = major_to_device(imajor(inode));
-	int vol_id = iminor(inode) - 1;
-	int mode;
+	int vol_id = iminor(inode) - 1, mode, ubi_num;
+
+	ubi_num = ubi_major2num(imajor(inode));
+	if (ubi_num < 0)
+		return ubi_num;
 
 	if (file->f_mode & FMODE_WRITE)
 		mode = UBI_READWRITE;
@@ -140,7 +125,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
 
 	dbg_msg("open volume %d, mode %d", vol_id, mode);
 
-	desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
+	desc = ubi_open_volume(ubi_num, vol_id, mode);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
 
@@ -586,9 +571,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 	if (!capable(CAP_SYS_RESOURCE))
 		return -EPERM;
 
-	ubi = major_to_device(imajor(inode));
-	if (IS_ERR(ubi))
-		return PTR_ERR(ubi);
+	ubi = ubi_get_by_major(imajor(inode));
+	if (!ubi)
+		return -ENODEV;
 
 	switch (cmd) {
 	/* Create volume command */
@@ -695,6 +680,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 		break;
 	}
 
+	ubi_put_device(ubi);
 	return err;
 }
 
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index c94f475..85297cd 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -339,6 +339,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
 {
 	int err, pnum, vol_id = vol->vol_id;
 
+	ubi_assert(ubi->ref_count > 0);
 	ubi_assert(vol->ref_count > 0);
 
 	if (ubi->ro_mode)
@@ -389,6 +390,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t uninitialized_var(crc);
 
+	ubi_assert(ubi->ref_count > 0);
 	ubi_assert(vol->ref_count > 0);
 
 	err = leb_read_lock(ubi, vol_id, lnum);
@@ -614,6 +616,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 	int err, pnum, tries = 0, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
 
+	ubi_assert(ubi->ref_count > 0);
 	ubi_assert(vol->ref_count > 0);
 
 	if (ubi->ro_mode)
@@ -749,6 +752,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t crc;
 
+	ubi_assert(ubi->ref_count > 0);
 	ubi_assert(vol->ref_count > 0);
 
 	if (ubi->ro_mode)
@@ -865,6 +869,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t crc;
 
+	ubi_assert(ubi->ref_count > 0);
 	ubi_assert(vol->ref_count > 0);
 
 	if (ubi->ro_mode)
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 780c273..4ec3a33 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -30,23 +30,27 @@
  * @ubi_num: UBI device number
  * @di: the information is stored here
  *
- * This function returns %0 in case of success and a %-ENODEV if there is no
- * such UBI device.
+ * This function returns %0 in case of success, %-EINVAL if the UBI device
+ * number is invalid, and %-ENODEV if there is no such UBI device.
  */
 int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
 {
-	const struct ubi_device *ubi;
+	struct ubi_device *ubi;
 
-	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-	    !ubi_devices[ubi_num])
+	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+		return -EINVAL;
+
+	ubi = ubi_get_device(ubi_num);
+	if (!ubi)
 		return -ENODEV;
 
-	ubi = ubi_devices[ubi_num];
 	di->ubi_num = ubi->ubi_num;
 	di->leb_size = ubi->leb_size;
 	di->min_io_size = ubi->min_io_size;
 	di->ro_mode = ubi->ro_mode;
 	di->cdev = ubi->cdev.dev;
+
+	ubi_put_device(ubi);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
 	    mode != UBI_EXCLUSIVE)
 		return ERR_PTR(-EINVAL);
 
-	ubi = ubi_devices[ubi_num];
+	/*
+	 * First of all, we have to get the UBI device to prevent its removal.
+	 */
+	ubi = ubi_get_device(ubi_num);
 	if (!ubi)
 		return ERR_PTR(-ENODEV);
 
-	if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
-		return ERR_PTR(-EINVAL);
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
+		err = -EINVAL;
+		goto out_put_ubi;
+	}
 
 	desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
-	if (!desc)
-		return ERR_PTR(-ENOMEM);
+	if (!desc) {
+		err = -ENOMEM;
+		goto out_put_ubi;
+	}
 
 	err = -ENODEV;
 	if (!try_module_get(THIS_MODULE))
@@ -188,6 +199,8 @@ out_unlock:
 	module_put(THIS_MODULE);
 out_free:
 	kfree(desc);
+out_put_ubi:
+	ubi_put_device(ubi);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 {
 	int i, vol_id = -1, len;
 	struct ubi_device *ubi;
+	struct ubi_volume_desc *ret;
 
 	dbg_msg("open volume %s, mode %d", name, mode);
 
@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
 		return ERR_PTR(-EINVAL);
 
-	ubi = ubi_devices[ubi_num];
+	ubi = ubi_get_device(ubi_num);
 	if (!ubi)
 		return ERR_PTR(-ENODEV);
 
@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 	}
 	spin_unlock(&ubi->volumes_lock);
 
-	if (vol_id < 0)
-		return ERR_PTR(-ENODEV);
+	if (vol_id >= 0)
+		ret = ubi_open_volume(ubi_num, vol_id, mode);
+	else
+		ret = ERR_PTR(-ENODEV);
 
-	return ubi_open_volume(ubi_num, vol_id, mode);
+	/*
+	 * We should put the UBI device even in case of success, because
+	 * 'ubi_open_volume()' took a reference as well.
+	 */
+	ubi_put_device(ubi);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 
@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 void ubi_close_volume(struct ubi_volume_desc *desc)
 {
 	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
 
 	dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
 
-	spin_lock(&vol->ubi->volumes_lock);
+	spin_lock(&ubi->volumes_lock);
 	switch (desc->mode) {
 	case UBI_READONLY:
 		vol->readers -= 1;
@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
 		vol->exclusive = 0;
 	}
 	vol->ref_count -= 1;
-	spin_unlock(&vol->ubi->volumes_lock);
+	spin_unlock(&ubi->volumes_lock);
 
-	put_device(&vol->dev);
 	kfree(desc);
+	put_device(&vol->dev);
+	ubi_put_device(ubi);
 	module_put(THIS_MODULE);
 }
 EXPORT_SYMBOL_GPL(ubi_close_volume);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 21c0283..91fde0e 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -245,6 +245,7 @@ struct ubi_wl_entry;
  *                @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
  *                @vol->readers, @vol->writers, @vol->exclusive,
  *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ * @ref_count: count of references on the UBI device
  *
  * @rsvd_pebs: count of reserved physical eraseblocks
  * @avail_pebs: count of available physical eraseblocks
@@ -325,6 +326,7 @@ struct ubi_device {
 	int vol_count;
 	struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
 	spinlock_t volumes_lock;
+	int ref_count;
 
 	int rsvd_pebs;
 	int avail_pebs;
@@ -401,7 +403,6 @@ extern struct kmem_cache *ubi_wl_entry_slab;
 extern struct file_operations ubi_ctrl_cdev_operations;
 extern struct file_operations ubi_cdev_operations;
 extern struct file_operations ubi_vol_cdev_operations;
-extern struct ubi_device *ubi_devices[];
 extern struct class *ubi_class;
 
 /* vtbl.c */
@@ -479,6 +480,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
 int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
 			 struct ubi_vid_hdr *vid_hdr);
 
+/* build.c */
+struct ubi_device *ubi_get_device(int ubi_num);
+void ubi_put_device(struct ubi_device *ubi);
+struct ubi_device *ubi_get_by_major(int major);
+int ubi_major2num(int major);
+
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
  * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 3ed63dc..42d3dd7 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -71,11 +71,16 @@ static ssize_t vol_attribute_show(struct device *dev,
 {
 	int ret;
 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
-	struct ubi_device *ubi = vol->ubi;
+	struct ubi_device *ubi;
+
+	ubi = ubi_get_device(vol->ubi->ubi_num);
+	if (!ubi)
+		return -ENODEV;
 
 	spin_lock(&ubi->volumes_lock);
 	if (!ubi->volumes[vol->vol_id]) {
 		spin_unlock(&ubi->volumes_lock);
+		ubi_put_device(ubi);
 		return -ENODEV;
 	}
 	/* Take a reference to prevent volume removal */
@@ -108,10 +113,12 @@ static ssize_t vol_attribute_show(struct device *dev,
 		/* This must be a bug */
 		ret = -EINVAL;
 
+	/* We've done the operation, drop volume and UBI device references */
 	spin_lock(&ubi->volumes_lock);
 	vol->ref_count -= 1;
 	ubi_assert(vol->ref_count >= 0);
 	spin_unlock(&ubi->volumes_lock);
+	ubi_put_device(ubi);
 	return ret;
 }
 
@@ -260,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 	}
 	ubi->avail_pebs -= vol->reserved_pebs;
 	ubi->rsvd_pebs += vol->reserved_pebs;
+	spin_unlock(&ubi->volumes_lock);
 
 	vol->vol_id    = vol_id;
 	vol->alignment = req->alignment;
@@ -267,9 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 	vol->vol_type  = req->vol_type;
 	vol->name_len  = req->name_len;
 	memcpy(vol->name, req->name, vol->name_len + 1);
-	vol->exclusive = 1;
 	vol->ubi = ubi;
-	spin_unlock(&ubi->volumes_lock);
 
 	/*
 	 * Finish all pending erases because there may be some LEBs belonging
@@ -350,8 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 		goto out_sysfs;
 
 	spin_lock(&ubi->volumes_lock);
-	ubi->vol_count += 1;
-	vol->exclusive = 0;
 	ubi->volumes[vol_id] = vol;
 	spin_unlock(&ubi->volumes_lock);
 
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7d32f71..bfc64c8 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1303,6 +1303,7 @@ int ubi_wl_flush(struct ubi_device *ubi)
 	 * Make sure all the works which have been done in parallel are
 	 * finished.
 	 */
+	ubi_assert(ubi->ref_count > 0);
 	down_write(&ubi->work_sem);
 	up_write(&ubi->work_sem);
 
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/6] UBI: prepare attach and detach functions
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
  2007-12-20 14:22 ` [PATCH v2 1/6] UBI: add UBI control device Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 2/6] UBI: add UBI devices reference counting Artem Bityutskiy
@ 2007-12-20 14:23 ` Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 4/6] UBI: UBI: remove data_offset Artem Bityutskiy
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:23 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From 9fd405794615345e2089a6cfe719988f8bf4ff9a Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Mon, 17 Dec 2007 20:33:20 +0200
Subject: [PATCH] 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>
---
 drivers/mtd/ubi/build.c |  235 ++++++++++++++++++++++++++++++++---------------
 drivers/mtd/ubi/ubi.h   |    5 +
 drivers/mtd/ubi/wl.c    |   16 +---
 3 files changed, 169 insertions(+), 87 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index e60a646..8f6aef6 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -39,6 +39,7 @@
 #include <linux/stringify.h>
 #include <linux/stat.h>
 #include <linux/log2.h>
+#include <linux/kthread.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
@@ -81,6 +82,9 @@ static struct device ubi_ctrl_dev;
 /* All UBI devices in system */
 static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
 
+/* Serializes UBI devices creations and removals */
+DEFINE_MUTEX(ubi_devices_mutex);
+
 /* Protects @ubi_devices and @ubi->ref_count */
 static DEFINE_SPINLOCK(ubi_devices_lock);
 
@@ -190,7 +194,7 @@ struct ubi_device *ubi_get_by_major(int major)
  * @major: major number
  *
  * This function searches UBI device number object by its major number. If UBI
- * device was not found, this function returns -ENODEV, othewise the UBI device
+ * device was not found, this function returns -ENODEV, otherwise the UBI device
  * number is returned.
  */
 int ubi_major2num(int major)
@@ -486,9 +490,9 @@ out_si:
  * assumed:
  *   o EC header is always at offset zero - this cannot be changed;
  *   o VID header starts just after the EC header at the closest address
- *   aligned to @io->@hdrs_min_io_size;
+ *     aligned to @io->hdrs_min_io_size;
  *   o data starts just after the VID header at the closest address aligned to
- *     @io->@min_io_size
+ *     @io->min_io_size
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
@@ -509,6 +513,9 @@ static int io_init(struct ubi_device *ubi)
 		return -EINVAL;
 	}
 
+	if (ubi->vid_hdr_offset < 0 || ubi->leb_start < ubi->vid_hdr_offset)
+		return -EINVAL;
+
 	/*
 	 * Note, in this implementation we support MTD devices with 0x7FFFFFFF
 	 * physical eraseblocks maximum.
@@ -617,84 +624,62 @@ static int io_init(struct ubi_device *ubi)
 }
 
 /**
- * attach_mtd_dev - attach an MTD device.
- * @mtd_dev: MTD device name or number string
+ * ubi_attach_mtd_dev - attach an MTD device.
+ * @mtd_dev: MTD device description object
  * @vid_hdr_offset: VID header offset
  * @data_offset: data offset
  *
  * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
  * MTD device name, and tries to open it by this name. If it is unable to open,
  * it tries to convert @mtd_dev to an integer and open the MTD device by its
- * number. Returns zero in case of success and a negative error code in case of
- * failure.
+ * number. Returns new UBI device's number in case of success and a negative
+ * error code in case of failure.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
  */
-static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
-			  int data_offset)
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset,
+		       int data_offset)
 {
 	struct ubi_device *ubi;
-	struct mtd_info *mtd;
 	int i, err;
 
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		int mtd_num;
-		char *endp;
-
-		if (PTR_ERR(mtd) != -ENODEV)
-			return PTR_ERR(mtd);
-
-		/*
-		 * Probably this is not MTD device name but MTD device number -
-		 * check this out.
-		 */
-		mtd_num = simple_strtoul(mtd_dev, &endp, 0);
-		if (*endp != '\0' || mtd_dev == endp) {
-			ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
-			return -ENODEV;
-		}
-
-		mtd = get_mtd_device(NULL, mtd_num);
-		if (IS_ERR(mtd))
-			return PTR_ERR(mtd);
-	}
-
-	/* Check if we already have the same MTD device attached */
+	/*
+	 * Check if we already have the same MTD device attached.
+	 *
+	 * Note, this function assumes that UBI devices creations and deletions
+	 * are serialized, so it does not take the &ubi_devices_lock.
+	 */
 	for (i = 0; i < UBI_MAX_DEVICES; i++)
 		ubi = ubi_devices[i];
-		if (ubi && ubi->mtd->index == mtd->index) {
+		if (ubi && mtd->index == ubi->mtd->index) {
 			ubi_err("mtd%d is already attached to ubi%d",
 				mtd->index, i);
-			err = -EINVAL;
-			goto out_mtd;
+			return -EINVAL;
 		}
 
-	ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
-	if (!ubi) {
-		err = -ENOMEM;
-		goto out_mtd;
-	}
-
-	ubi->mtd = mtd;
-
 	/* Search for an empty slot in the @ubi_devices array */
-	ubi->ubi_num = -1;
 	for (i = 0; i < UBI_MAX_DEVICES; i++)
-		if (!ubi_devices[i]) {
-			ubi->ubi_num = i;
+		if (!ubi_devices[i])
 			break;
-		}
 
-	if (ubi->ubi_num == -1) {
+	if (i == UBI_MAX_DEVICES) {
 		ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
-		err = -ENFILE;
-		goto out_free;
+		return -ENFILE;
 	}
 
-	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
-		ubi->mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset);
+	ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
+	if (!ubi)
+		return -ENOMEM;
 
+	ubi->mtd = mtd;
+	ubi->ubi_num = i;
 	ubi->vid_hdr_offset = vid_hdr_offset;
 	ubi->leb_start = data_offset;
+
+	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
+		mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset);
+
 	err = io_init(ubi);
 	if (err)
 		goto out_free;
@@ -725,8 +710,16 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
 	if (err)
 		goto out_detach;
 
-	ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi->ubi_num);
-	ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
+	ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+	if (IS_ERR(ubi->bgt_thread)) {
+		err = PTR_ERR(ubi->bgt_thread);
+		ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+			err);
+		goto out_uif;
+	}
+
+	ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num);
+	ubi_msg("MTD device name:            \"%s\"", mtd->name);
 	ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
 	ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
 		ubi->peb_size, ubi->peb_size >> 10);
@@ -755,8 +748,10 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
 	}
 
 	ubi_devices[ubi->ubi_num] = ubi;
-	return 0;
+	return ubi->ubi_num;
 
+out_uif:
+	uif_close(ubi);
 out_detach:
 	ubi_eba_close(ubi);
 	ubi_wl_close(ubi);
@@ -768,21 +763,57 @@ out_free:
 	vfree(ubi->dbg_peb_buf);
 #endif
 	kfree(ubi);
-out_mtd:
-	put_mtd_device(mtd);
 	return err;
 }
 
 /**
- * detach_mtd_dev - detach an MTD device.
- * @ubi: UBI device description object
+ * ubi_detach_mtd_dev - detach an MTD device.
+ * @ubi_num: UBI device number to detach from
+ * @anyway: detach MTD even if device reference count is not zero
+ *
+ * This function destroys an UBI device number @ubi_num and detaches the
+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
+ * exist.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
  */
-static void detach_mtd_dev(struct ubi_device *ubi)
+int ubi_detach_mtd_dev(int ubi_num, int anyway)
 {
-	int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
+	struct ubi_device *ubi;
+
+	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+		return -EINVAL;
+
+	spin_lock(&ubi_devices_lock);
+	ubi = ubi_devices[ubi_num];
+	if (!ubi) {
+		spin_lock(&ubi_devices_lock);
+		return -EINVAL;
+	}
+
+	if (ubi->ref_count) {
+		if (!anyway) {
+			spin_lock(&ubi_devices_lock);
+			return -EBUSY;
+		}
+		/* This may only happen if there is a bug */
+		ubi_err("%s reference count %d, destroy anyway",
+			ubi->ubi_name, ubi->ref_count);
+	}
+	ubi_devices[ubi->ubi_num] = NULL;
+	spin_unlock(&ubi_devices_lock);
+
+	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num);
+
+	/*
+	 * Before freeing anything, we have to stop the background thread to
+	 * prevent it from doing anything on this device while we are freeing.
+	 */
+	if (ubi->bgt_thread)
+		kthread_stop(ubi->bgt_thread);
 
-	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
-	ubi_assert(ubi->ref_count == 0);
 	uif_close(ubi);
 	ubi_eba_close(ubi);
 	ubi_wl_close(ubi);
@@ -793,9 +824,9 @@ static void detach_mtd_dev(struct ubi_device *ubi)
 #ifdef CONFIG_MTD_UBI_DEBUG
 	vfree(ubi->dbg_peb_buf);
 #endif
-	kfree(ubi_devices[ubi_num]);
-	ubi_devices[ubi_num] = NULL;
-	ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num);
+	ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+	kfree(ubi);
+	return 0;
 }
 
 /**
@@ -812,6 +843,46 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
 	init_rwsem(&le->mutex);
 }
 
+/**
+ * find_mtd_device - open an MTD device by its name or number.
+ * @mtd_dev: name or number of the device
+ *
+ * This function tries to open and MTD device with name @mtd_dev, and if it
+ * fails, then it tries to interpret the @mtd_dev string as an ASCII-coded
+ * integer and open an MTD device with this number. Returns MTD device
+ * description object in case of success and a negative error code in case of
+ * failure.
+ */
+static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
+{
+	struct mtd_info *mtd;
+
+	mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(mtd)) {
+		int mtd_num;
+		char *endp;
+
+		if (PTR_ERR(mtd) != -ENODEV)
+			return mtd;
+
+		/*
+		 * Probably this is not MTD device name but MTD device number -
+		 * check this out.
+		 */
+		mtd_num = simple_strtoul(mtd_dev, &endp, 0);
+		if (*endp != '\0' || mtd_dev == endp) {
+			ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
+			return ERR_PTR(-ENODEV);
+		}
+
+		mtd = get_mtd_device(NULL, mtd_num);
+		if (IS_ERR(mtd))
+			return mtd;
+	}
+
+	return mtd;
+}
+
 static int __init ubi_init(void)
 {
 	int err, i, k;
@@ -875,10 +946,21 @@ static int __init ubi_init(void)
 	/* Attach MTD devices */
 	for (i = 0; i < mtd_devs; i++) {
 		struct mtd_dev_param *p = &mtd_dev_param[i];
+		struct mtd_info *mtd;
 
 		cond_resched();
-		err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
-		if (err) {
+
+		mtd = open_mtd_device(p->name);
+		if (IS_ERR(mtd)) {
+			err = PTR_ERR(mtd);
+			goto out_detach;
+		}
+
+		mutex_lock(&ubi_devices_mutex);
+		err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs, p->data_offs);
+		mutex_unlock(&ubi_devices_mutex);
+		if (err < 0) {
+			put_mtd_device(mtd);
 			printk(KERN_ERR "UBI error: cannot attach %s\n",
 			       p->name);
 			goto out_detach;
@@ -889,7 +971,11 @@ static int __init ubi_init(void)
 
 out_detach:
 	for (k = 0; k < i; k++)
-		detach_mtd_dev(ubi_devices[k]);
+		if (ubi_devices[k]) {
+			mutex_lock(&ubi_devices_mutex);
+			ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+			mutex_unlock(&ubi_devices_mutex);
+		}
 	kmem_cache_destroy(ubi_wl_entry_slab);
 out_ltree:
 	kmem_cache_destroy(ubi_ltree_slab);
@@ -911,8 +997,11 @@ static void __exit ubi_exit(void)
 	int i;
 
 	for (i = 0; i < UBI_MAX_DEVICES; i++)
-		if (ubi_devices[i])
-			detach_mtd_dev(ubi_devices[i]);
+		if (ubi_devices[i]) {
+			mutex_lock(&ubi_devices_mutex);
+			ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+			mutex_unlock(&ubi_devices_mutex);
+		}
 	kmem_cache_destroy(ubi_wl_entry_slab);
 	kmem_cache_destroy(ubi_ltree_slab);
 	device_unregister(&ubi_ctrl_dev);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 91fde0e..25ff15a 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -404,6 +404,7 @@ extern struct file_operations ubi_ctrl_cdev_operations;
 extern struct file_operations ubi_cdev_operations;
 extern struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
+extern struct mutex ubi_devices_mutex;
 
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -462,6 +463,7 @@ int ubi_wl_flush(struct ubi_device *ubi);
 int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
 int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
 void ubi_wl_close(struct ubi_device *ubi);
+int ubi_thread(void *u);
 
 /* io.c */
 int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
@@ -481,6 +483,9 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
 			 struct ubi_vid_hdr *vid_hdr);
 
 /* build.c */
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset,
+		       int data_offset);
+int ubi_detach_mtd_dev(int ubi_num, int anyway);
 struct ubi_device *ubi_get_device(int ubi_num);
 void ubi_put_device(struct ubi_device *ubi);
 struct ubi_device *ubi_get_by_major(int major);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index bfc64c8..1142aab 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1356,7 +1356,7 @@ static void tree_destroy(struct rb_root *root)
  * ubi_thread - UBI background thread.
  * @u: the UBI device description object pointer
  */
-static int ubi_thread(void *u)
+int ubi_thread(void *u)
 {
 	int failures = 0;
 	struct ubi_device *ubi = u;
@@ -1454,18 +1454,10 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
 
 	sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
 
-	ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
-	if (IS_ERR(ubi->bgt_thread)) {
-		err = PTR_ERR(ubi->bgt_thread);
-		ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
-			err);
-		return err;
-	}
-
 	err = -ENOMEM;
 	ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL);
 	if (!ubi->lookuptbl)
-		goto out_free;
+		return err;
 
 	list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
 		cond_resched();
@@ -1598,10 +1590,6 @@ static void protection_trees_destroy(struct ubi_device *ubi)
  */
 void ubi_wl_close(struct ubi_device *ubi)
 {
-	dbg_wl("disable \"%s\"", ubi->bgt_name);
-	if (ubi->bgt_thread)
-		kthread_stop(ubi->bgt_thread);
-
 	dbg_wl("close the UBI wear-leveling unit");
 
 	cancel_pending(ubi);
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 4/6] UBI: UBI: remove data_offset
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
                   ` (2 preceding siblings ...)
  2007-12-20 14:23 ` [PATCH v2 3/6] UBI: prepare attach and detach functions Artem Bityutskiy
@ 2007-12-20 14:23 ` Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 5/6] UBI: introduce attach ioctls Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 5/6] UBI: handle attach ioctl Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:23 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From 09610a4ca122838a1292ec919ac2d05cf499a140 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Wed, 19 Dec 2007 21:43:32 +0200
Subject: [PATCH] UBI: remove data_offset

'data_offset' parameter does not really make sense and it is not
needed. Get rid of it.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/build.c |   42 +++++++++++++++---------------------------
 drivers/mtd/ubi/ubi.h   |    3 +--
 2 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 8f6aef6..5045588 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -49,13 +49,11 @@
  * struct mtd_dev_param - MTD device parameter description data structure.
  * @name: MTD device name or number string
  * @vid_hdr_offs: VID header offset
- * @data_offs: data offset
  */
 struct mtd_dev_param
 {
 	char name[MTD_PARAM_LEN_MAX];
 	int vid_hdr_offs;
-	int data_offs;
 };
 
 /* Numbers of elements set in the @mtd_dev_param array */
@@ -513,7 +511,7 @@ static int io_init(struct ubi_device *ubi)
 		return -EINVAL;
 	}
 
-	if (ubi->vid_hdr_offset < 0 || ubi->leb_start < ubi->vid_hdr_offset)
+	if (ubi->vid_hdr_offset < 0)
 		return -EINVAL;
 
 	/*
@@ -563,10 +561,8 @@ static int io_init(struct ubi_device *ubi)
 	}
 
 	/* Similar for the data offset */
-	if (ubi->leb_start == 0) {
-		ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
-		ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
-	}
+	ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
+	ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
 
 	dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
 	dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
@@ -627,7 +623,6 @@ static int io_init(struct ubi_device *ubi)
  * ubi_attach_mtd_dev - attach an MTD device.
  * @mtd_dev: MTD device description object
  * @vid_hdr_offset: VID header offset
- * @data_offset: data offset
  *
  * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
  * MTD device name, and tries to open it by this name. If it is unable to open,
@@ -638,8 +633,7 @@ static int io_init(struct ubi_device *ubi)
  * Note, the invocations of this function has to be serialized by the
  * @ubi_devices_mutex.
  */
-int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset,
-		       int data_offset)
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset)
 {
 	struct ubi_device *ubi;
 	int i, err;
@@ -675,10 +669,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset,
 	ubi->mtd = mtd;
 	ubi->ubi_num = i;
 	ubi->vid_hdr_offset = vid_hdr_offset;
-	ubi->leb_start = data_offset;
 
-	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
-		mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset);
+	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
+		mtd->index, ubi->ubi_num, vid_hdr_offset);
 
 	err = io_init(ubi);
 	if (err)
@@ -957,7 +950,7 @@ static int __init ubi_init(void)
 		}
 
 		mutex_lock(&ubi_devices_mutex);
-		err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs, p->data_offs);
+		err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs);
 		mutex_unlock(&ubi_devices_mutex);
 		if (err < 0) {
 			put_mtd_device(mtd);
@@ -1111,13 +1104,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
 	if (tokens[1])
 		p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
-	if (tokens[2])
-		p->data_offs = bytes_str_to_int(tokens[2]);
 
 	if (p->vid_hdr_offs < 0)
 		return p->vid_hdr_offs;
-	if (p->data_offs < 0)
-		return p->data_offs;
 
 	mtd_devs += 1;
 	return 0;
@@ -1125,16 +1114,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
 module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
 MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
-		      "mtd=<name|num>[,<vid_hdr_offs>,<data_offs>]. "
+		      "mtd=<name|num>[,<vid_hdr_offs>].\n"
 		      "Multiple \"mtd\" parameters may be specified.\n"
-		      "MTD devices may be specified by their number or name. "
-		      "Optional \"vid_hdr_offs\" and \"data_offs\" parameters "
-		      "specify UBI VID header position and data starting "
-		      "position to be used by UBI.\n"
-		      "Example: mtd=content,1984,2048 mtd=4 - attach MTD device"
-		      "with name content using VID header offset 1984 and data "
-		      "start 2048, and MTD device number 4 using default "
-		      "offsets");
+		      "MTD devices may be specified by their number or name.\n"
+		      "Optional \"vid_hdr_offs\" parameter specifies UBI VID "
+		      "header position and data starting position to be used "
+		      "by UBI.\n"
+		      "Example: mtd=content,1984 mtd=4 - attach MTD device"
+		      "with name \"content\" using VID header offset 1984, and "
+		      "MTD device number 4 with default VID header offset.");
 
 MODULE_VERSION(__stringify(UBI_VERSION));
 MODULE_DESCRIPTION("UBI - Unsorted Block Images");
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 25ff15a..4c3607e 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -483,8 +483,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
 			 struct ubi_vid_hdr *vid_hdr);
 
 /* build.c */
-int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset,
-		       int data_offset);
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset);
 int ubi_detach_mtd_dev(int ubi_num, int anyway);
 struct ubi_device *ubi_get_device(int ubi_num);
 void ubi_put_device(struct ubi_device *ubi);
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 5/6] UBI: introduce attach ioctls
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
                   ` (3 preceding siblings ...)
  2007-12-20 14:23 ` [PATCH v2 4/6] UBI: UBI: remove data_offset Artem Bityutskiy
@ 2007-12-20 14:23 ` Artem Bityutskiy
  2007-12-20 14:23 ` [PATCH v2 5/6] UBI: handle attach ioctl Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:23 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From 9143611137b01d56137c3b21b2b360e7e38cee9a Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Tue, 18 Dec 2007 18:22:16 +0200
Subject: [PATCH] UBI: introduce attach ioctls

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 include/mtd/ubi-user.h |   69 ++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h
index fe06ded..c3a1331 100644
--- a/include/mtd/ubi-user.h
+++ b/include/mtd/ubi-user.h
@@ -22,6 +22,21 @@
 #define __UBI_USER_H__
 
 /*
+ * UBI device creation (the same as MTD device attachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
+ * control device. The caller has to properly fill and pass
+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in
+ * the request and return the newly created UBI device number as the ioctl
+ * return value.
+ *
+ * UBI device deletion (the same as MTD device detachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
+ * control device.
+ *
  * UBI volume creation
  * ~~~~~~~~~~~~~~~~~~~
  *
@@ -80,6 +95,15 @@
 /* Re-size an UBI volume */
 #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
 
+/* IOCTL commands of the UBI control character device */
+
+#define UBI_CTRL_IOC_MAGIC 'o'
+
+/* Attach an MTD device */
+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
+/* Detach an MTD device */
+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
+
 /* IOCTL commands of UBI volume character devices */
 
 #define UBI_VOL_IOC_MAGIC 'O'
@@ -89,6 +113,9 @@
 /* An eraseblock erasure command, used for debugging, disabled by default */
 #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
 
+/* Maximum MTD device name length supported by UBI */
+#define MAX_UBI_MTD_NAME_LEN 127
+
 /*
  * UBI volume type constants.
  *
@@ -97,19 +124,51 @@
  */
 enum {
 	UBI_DYNAMIC_VOLUME = 3,
-	UBI_STATIC_VOLUME = 4
+	UBI_STATIC_VOLUME = 4,
+};
+
+/**
+ * struct ubi_attach_req - attach MTD device request.
+ * @vid_hdr_offset: VID header offset (use defaults if %0)
+ * @mtd_num: MTD device number to attach
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * This data structure is used to specify MTD device UBI has to attach and the
+ * parameters it has to use. The "attach MTD device" ioctl returns the number
+ * of the newly created UBI device as the return value.
+ *
+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default
+ * offset of the VID header within physical eraseblocks. The default offset is
+ * the next min. I/O unit after the EC header. For example, it will be offset
+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
+ *
+ * But in rare cases, if this optimizes things, the VID header may be placed to
+ * a different offset. For example, the boot-loader might do things faster if the
+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As
+ * the boot-loader would not normally need to read EC headers (unless it needs
+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example,
+ * but it real-life example. So, in this example, @vid_hdr_offer would be
+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page
+ * of the first page and add needed padding.
+ */
+struct ubi_attach_req {
+	int32_t vid_hdr_offset;
+	int32_t mtd_num;
+	uint8_t padding[12];
 };
 
 /**
  * struct ubi_mkvol_req - volume description data structure used in
- * volume creation requests.
+ *                        volume creation requests.
  * @vol_id: volume number
  * @alignment: volume alignment
  * @bytes: volume size in bytes
  * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @padding1: reserved for future, not used
+ * @padding1: reserved for future, not used, has to be zeroed
  * @name_len: volume name length
- * @padding2: reserved for future, not used
+ * @padding2: reserved for future, not used, has to be zeroed
  * @name: volume name
  *
  * This structure is used by userspace programs when creating new volumes. The
@@ -139,7 +198,7 @@ struct ubi_mkvol_req {
 	int8_t padding1;
 	int16_t name_len;
 	int8_t padding2[4];
-	char name[UBI_MAX_VOLUME_NAME+1];
+	char name[UBI_MAX_VOLUME_NAME + 1];
 } __attribute__ ((packed));
 
 /**
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 5/6] UBI: handle attach ioctl
  2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
                   ` (4 preceding siblings ...)
  2007-12-20 14:23 ` [PATCH v2 5/6] UBI: introduce attach ioctls Artem Bityutskiy
@ 2007-12-20 14:23 ` Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2007-12-20 14:23 UTC (permalink / raw)
  To: linux-mtd; +Cc: Frank Haverkamp, Arnd Bergmann, Andreas Arnez

>From f3a2178d8b632f712992d5a62f5d4b78440df527 Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date: Tue, 18 Dec 2007 18:23:39 +0200
Subject: [PATCH] UBI: handle attach ioctl

Actually implement the MTD device attach/detach handlers.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/cdev.c |   84 +++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 69 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 01978b5..493bfb9 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -44,17 +44,6 @@
 #include <asm/div64.h>
 #include "ubi.h"
 
-/*
- * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
- * logical eraseblock erase is a debug-only feature).
- */
-#define UBI_CDEV_IOC_MAX_SEQ 2
-#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
-#define VOL_CDEV_IOC_MAX_SEQ 1
-#else
-#define VOL_CDEV_IOC_MAX_SEQ 2
-#endif
-
 /**
  * get_exclusive - get exclusive access to an UBI volume.
  * @desc: volume descriptor
@@ -582,8 +571,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 		struct ubi_mkvol_req req;
 
 		dbg_msg("create volume");
-		err = copy_from_user(&req, argp,
-				       sizeof(struct ubi_mkvol_req));
+		err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
 		if (err) {
 			err = -EFAULT;
 			break;
@@ -647,8 +635,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 		struct ubi_rsvol_req req;
 
 		dbg_msg("re-size volume");
-		err = copy_from_user(&req, argp,
-				       sizeof(struct ubi_rsvol_req));
+		err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
 		if (err) {
 			err = -EFAULT;
 			break;
@@ -684,8 +671,75 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 	return err;
 }
 
+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	void __user *argp = (void __user *)arg;
+
+	if (!capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+
+	switch (cmd) {
+	/* Attach an MTD device command */
+	case UBI_IOCATT:
+	{
+		struct ubi_attach_req req;
+		struct mtd_info *mtd;
+
+		dbg_msg("attach MTD device");
+		err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (req.mtd_num < 0)
+			return -EINVAL;
+
+		mtd = get_mtd_device(NULL, req.mtd_num);
+		if (IS_ERR(mtd))
+			return PTR_ERR(mtd);
+
+		/* Note, request verification is done by the attach function */
+		mutex_lock(&ubi_devices_mutex);
+		err = ubi_attach_mtd_dev(mtd, req.vid_hdr_offset,
+					 req.data_offset);
+		mutex_unlock(&ubi_devices_mutex);
+		if (err < 0)
+			put_mtd_device(mtd);
+		break;
+	}
+
+	/* Detach an MTD device command */
+	case UBI_IOCDET:
+	{
+		int ubi_num;
+
+		dbg_msg("dettach MTD device");
+		err = get_user(ubi_num, (__user int32_t *)argp);
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		mutex_lock(&ubi_devices_mutex);
+		err = ubi_detach_mtd_dev(ubi_num, 0);
+		mutex_unlock(&ubi_devices_mutex);
+		break;
+	}
+
+	default:
+		err = -ENOTTY;
+		break;
+	}
+
+	return err;
+}
+
 /* UBI control character device operations */
 struct file_operations ubi_ctrl_cdev_operations = {
+	.ioctl = ctrl_cdev_ioctl,
 	.owner = THIS_MODULE,
 };
 
-- 
1.5.3.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2007-12-20 12:57 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-20 14:22 [PATCH v2 0/6] UBI: make UBI devices dynamic Artem Bityutskiy
2007-12-20 14:22 ` [PATCH v2 1/6] UBI: add UBI control device Artem Bityutskiy
2007-12-20 14:23 ` [PATCH v2 2/6] UBI: add UBI devices reference counting Artem Bityutskiy
2007-12-20 14:23 ` [PATCH v2 3/6] UBI: prepare attach and detach functions Artem Bityutskiy
2007-12-20 14:23 ` [PATCH v2 4/6] UBI: UBI: remove data_offset Artem Bityutskiy
2007-12-20 14:23 ` [PATCH v2 5/6] UBI: introduce attach ioctls Artem Bityutskiy
2007-12-20 14:23 ` [PATCH v2 5/6] UBI: handle attach ioctl Artem Bityutskiy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.