All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [UBI] [1/3] ubi notifications API
@ 2009-04-29 15:29 dmitry pervushin
  2009-05-06  6:31 ` Artem Bityutskiy
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: dmitry pervushin @ 2009-04-29 15:29 UTC (permalink / raw)
  To: dedekind; +Cc: linux-mtd

UBI volume notifications are intended to create the API to get clients
notified about volume creation/deletion, renaming and changing(actually,
resizing). A client can subscribe to these notifications using
ubi_volume_register and cancel the subscription using
ubi_volume_unregister. When UBI volume change occurs, the atomic
notifier will be called. Client also can request "added" event on all
volumes that existed before client subscribed to the notifications.

Using notifications instead of calling functions ubi_gluebi_xxx allows
MTD emulation layer to be more flexible; say, now is it possible to
build it as a module and load/unload it on demand.

Thanks Artem Bityutskiy for reviewing the patch and many very valuable
comments.

Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
---
 drivers/mtd/ubi/build.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++--
 drivers/mtd/ubi/cdev.c  |    2 +
 drivers/mtd/ubi/kapi.c  |   46 +++++++++++++++++++++++++++
 drivers/mtd/ubi/ubi.h   |   24 ++++++++++++++
 drivers/mtd/ubi/vmt.c   |    7 ++++
 include/linux/mtd/ubi.h |   35 +++++++++++++++++++++
 6 files changed, 191 insertions(+), 3 deletions(-)

Index: linux-2.6-arm/drivers/mtd/ubi/build.c
===================================================================
--- linux-2.6-arm.orig/drivers/mtd/ubi/build.c
+++ linux-2.6-arm/drivers/mtd/ubi/build.c
@@ -122,6 +122,76 @@ static struct device_attribute dev_mtd_n
 	__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
 
 /**
+ * ubi_enum_volumes - "enumerate" volumes.
+ * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
+ * @ubi: UBI device description object
+ * @nb: notifier to be called or %NULL to send to system-wide notification
+ *
+ * This function walks all volumes of UBI device @ubi and sends the
+ * notification specified by @ntype. Returns number of sent notifications.
+ */
+int ubi_enum_volumes(int ntype, struct ubi_device *ubi,
+		     struct notifier_block *nb)
+{
+	struct ubi_volume_notification nt;
+	int i, count = 0;
+
+	nt.ubi_num = ubi->ubi_num;
+
+	spin_lock(&ubi->volumes_lock);
+	for (i = 0; i < ubi->vtbl_slots; i++) {
+		if (!ubi->volumes[i])
+			continue;
+		nt.vol_id = ubi->volumes[i]->vol_id;
+		get_device(&ubi->volumes[i]->dev);
+		ubi->volumes[i]->ref_count += 1;
+		spin_unlock(&ubi->volumes_lock);
+		if (nb)
+			nb->notifier_call(nb, ntype, &nt);
+		else
+			blocking_notifier_call_chain(&ubi_notifiers,
+						     ntype, &nt);
+		count++;
+		spin_lock(&ubi->volumes_lock);
+		ubi->volumes[i]->ref_count -= 1;
+		put_device(&ubi->volumes[i]->dev);
+	}
+	spin_unlock(&ubi->volumes_lock);
+
+	return count;
+}
+
+/**
+ * ubi_enum_all_volumes - enumerate all existing volumes and send notification.
+ * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
+ * @nb: notifier to be called, or %NULL to send to system-wide notification
+ *
+ * This function walks all UBI devices and all volumes on the device, and sends
+ * the notification specified by @ntype. Returns number of sent notifications.
+ */
+int ubi_enum_all_volumes(int ntype, struct notifier_block *nb)
+{
+	struct ubi_device *ubi;
+	int i, count = 0;
+
+	spin_lock(&ubi_devices_lock);
+	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+		ubi = ubi_devices[i];
+		if (!ubi)
+			continue;
+		ubi->ref_count += 1;
+		get_device(&ubi->dev);
+		spin_unlock(&ubi_devices_lock);
+		count += ubi_enum_volumes(ntype, ubi, nb);
+		spin_lock(&ubi_devices_lock);
+		put_device(&ubi->dev);
+		ubi->ref_count -= 1;
+	}
+	spin_unlock(&ubi_devices_lock);
+	return count;
+}
+
+/**
  * ubi_get_device - get UBI device.
  * @ubi_num: UBI device number
  *
@@ -877,6 +947,7 @@ int ubi_attach_mtd_dev(struct mtd_info *
 	wake_up_process(ubi->bgt_thread);
 
 	ubi_devices[ubi_num] = ubi;
+	ubi_enum_volumes(UBI_VOLUME_ADDED, ubi, NULL);
 	return ubi_num;
 
 out_uif:
@@ -919,16 +990,18 @@ int ubi_detach_mtd_dev(int ubi_num, int
 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
 		return -EINVAL;
 
-	spin_lock(&ubi_devices_lock);
-	ubi = ubi_devices[ubi_num];
-	if (!ubi) {
-		spin_unlock(&ubi_devices_lock);
+	ubi = ubi_get_device(ubi_num);
+	if (!ubi)
 		return -EINVAL;
-	}
+	ubi_enum_volumes(UBI_VOLUME_DELETED, ubi, NULL);
 
+	spin_lock(&ubi_devices_lock);
+	put_device(&ubi->dev);
+	ubi->ref_count -= 1;
 	if (ubi->ref_count) {
 		if (!anyway) {
 			spin_unlock(&ubi_devices_lock);
+			ubi_enum_volumes(UBI_VOLUME_ADDED, ubi, NULL);
 			return -EBUSY;
 		}
 		/* This may only happen if there is a bug */
Index: linux-2.6-arm/drivers/mtd/ubi/cdev.c
===================================================================
--- linux-2.6-arm.orig/drivers/mtd/ubi/cdev.c
+++ linux-2.6-arm/drivers/mtd/ubi/cdev.c
@@ -394,6 +394,8 @@ static ssize_t vol_cdev_write(struct fil
 		}
 		vol->checked = 1;
 		ubi_gluebi_updated(vol);
+		ubi_volume_notify(UBI_VOLUME_CHANGED,
+				ubi->ubi_num, vol->vol_id);
 		revoke_exclusive(desc, UBI_READWRITE);
 	}
 
Index: linux-2.6-arm/drivers/mtd/ubi/kapi.c
===================================================================
--- linux-2.6-arm.orig/drivers/mtd/ubi/kapi.c
+++ linux-2.6-arm/drivers/mtd/ubi/kapi.c
@@ -656,3 +656,49 @@ int ubi_sync(int ubi_num)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_sync);
+
+BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
+
+/**
+ * ubi_register_volume_notifier - register the volume notification function.
+ * @nb: pointer to the filled struct &notifier_block
+ * @ignore_existing: boolean flag; if set to 1, UBI will not send notifications
+ * 		     about ADDing existing volumes
+ *
+ * The function @nb.notifier_call will be called when volume is added,
+ * removed, resized or renamed. Its first parameter is &enum
+ * ubi_volume_notification_type, and the second points to the structure
+ * that contains information about "changed" volume - ubi_num and
+ * volume_id. When the notifier is called, it is safe to use all UBI API.
+ *
+ * Returns %0 on success, error code otherwise.
+ */
+int ubi_register_volume_notifier(struct notifier_block *nb,
+				 int ignore_existing)
+{
+	int err;
+
+	err = blocking_notifier_chain_register(&ubi_notifiers, nb);
+	if (err != 0)
+		return err;
+	if (ignore_existing)
+		return err;
+	down_read(&ubi_notifiers.rwsem);
+
+	ubi_enum_all_volumes(UBI_VOLUME_ADDED, nb);
+	up_read(&ubi_notifiers.rwsem);
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_register_volume_notifier);
+
+/**
+ * ubi_unregister_volume_notifier - unregister the volume notifier.
+ * @nb: pointer to the filled struct &notifier_block
+ *
+ * Returns %0 on success, error code otherwise
+ */
+int ubi_unregister_volume_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&ubi_notifiers, nb);
+}
+EXPORT_SYMBOL_GPL(ubi_unregister_volume_notifier);
Index: linux-2.6-arm/drivers/mtd/ubi/ubi.h
===================================================================
--- linux-2.6-arm.orig/drivers/mtd/ubi/ubi.h
+++ linux-2.6-arm/drivers/mtd/ubi/ubi.h
@@ -38,6 +38,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/ubi.h>
+#include <linux/notifier.h>
 
 #include "ubi-media.h"
 #include "scan.h"
@@ -457,6 +458,7 @@ extern const struct file_operations ubi_
 extern const struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
 extern struct mutex ubi_devices_mutex;
+extern struct blocking_notifier_head ubi_notifiers;
 
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -549,6 +551,9 @@ struct ubi_device *ubi_get_device(int ub
 void ubi_put_device(struct ubi_device *ubi);
 struct ubi_device *ubi_get_by_major(int major);
 int ubi_major2num(int major);
+int ubi_enum_volumes(int ntype, struct ubi_device *ubi,
+		     struct notifier_block *nb);
+int ubi_enum_all_volumes(int ntype, struct notifier_block *nb);
 
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
@@ -564,6 +569,25 @@ int ubi_major2num(int major);
 	     rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
 
 /**
+ * ubi_volume_notify - notify all registered clients about volume changes.
+ * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
+ * @ubi_num: UBI device number
+ * @vol_id: ID of the created/removed/changed volume
+ *
+ * This is a helper function which notifies all subscribers about a volume
+ * change event. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static inline int ubi_volume_notify(int ntype, int ubi_num, int vol_id)
+{
+       struct ubi_volume_notification nt;
+
+       nt.ubi_num = ubi_num;
+       nt.vol_id = vol_id;
+       return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
+}
+
+/**
  * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
  * @ubi: UBI device description object
  * @gfp_flags: GFP flags to allocate with
Index: linux-2.6-arm/drivers/mtd/ubi/vmt.c
===================================================================
--- linux-2.6-arm.orig/drivers/mtd/ubi/vmt.c
+++ linux-2.6-arm/drivers/mtd/ubi/vmt.c
@@ -358,6 +358,7 @@ int ubi_create_volume(struct ubi_device
 	ubi->vol_count += 1;
 	spin_unlock(&ubi->volumes_lock);
 
+	ubi_volume_notify(UBI_VOLUME_ADDED, ubi->ubi_num, vol->vol_id);
 	err = paranoid_check_volumes(ubi);
 	return err;
 
@@ -419,6 +420,8 @@ int ubi_remove_volume(struct ubi_volume_
 	if (ubi->ro_mode)
 		return -EROFS;
 
+	ubi_volume_notify(UBI_VOLUME_DELETED, ubi->ubi_num, vol_id);
+
 	spin_lock(&ubi->volumes_lock);
 	if (vol->ref_count > 1) {
 		/*
@@ -475,6 +478,7 @@ out_err:
 	ubi->volumes[vol_id] = vol;
 out_unlock:
 	spin_unlock(&ubi->volumes_lock);
+	ubi_volume_notify(UBI_VOLUME_ADDED, ubi->ubi_num, vol_id);
 	return err;
 }
 
@@ -587,6 +591,7 @@ int ubi_resize_volume(struct ubi_volume_
 			(long long)vol->used_ebs * vol->usable_leb_size;
 	}
 
+	ubi_volume_notify(UBI_VOLUME_CHANGED, ubi->ubi_num, vol->vol_id);
 	err = paranoid_check_volumes(ubi);
 	return err;
 
@@ -632,6 +637,8 @@ int ubi_rename_volumes(struct ubi_device
 			vol->name_len = re->new_name_len;
 			memcpy(vol->name, re->new_name, re->new_name_len + 1);
 			spin_unlock(&ubi->volumes_lock);
+			ubi_volume_notify(UBI_VOLUME_RENAMED,
+					  ubi->ubi_num, vol->vol_id);
 		}
 	}
 
Index: linux-2.6-arm/include/linux/mtd/ubi.h
===================================================================
--- linux-2.6-arm.orig/include/linux/mtd/ubi.h
+++ linux-2.6-arm/include/linux/mtd/ubi.h
@@ -132,6 +132,37 @@ struct ubi_device_info {
 	dev_t cdev;
 };
 
+/*
+ * struct ubi_volume_notification - information about changed volume.
+ * @ubi_num: UBI device number where the changed volume persists
+ * @vol_id: changed volume id
+ *
+ * Each notification about changed volume takes two parameters - first one
+ * indicates the type of volume change, and the second parameter is a pointer
+ * to the &struct ubi_volume_notification and describes the subject of change.
+ */
+struct ubi_volume_notification {
+	int ubi_num;
+	int vol_id;
+};
+
+/*
+ * enum - type of volume_change.
+ * @UBI_VOLUME_ADDED: volume has been added
+ * @UBI_VOLUME_DELETED: volume has been deleted
+ * @UBI_VOLUME_CHANGED: volume size has been changed
+ * @UBI_VOLUME_RENAMED: volume name has been changed
+ *
+ * Variable of this type is passed as the first parameter to the notification
+ * function.
+ */
+enum {
+	UBI_VOLUME_ADDED,
+	UBI_VOLUME_DELETED,
+	UBI_VOLUME_CHANGED,
+	UBI_VOLUME_RENAMED,
+};
+
 /* UBI descriptor given to users when they open UBI volumes */
 struct ubi_volume_desc;
 
@@ -141,6 +172,10 @@ void ubi_get_volume_info(struct ubi_volu
 struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode);
 struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 					   int mode);
+int ubi_register_volume_notifier(struct notifier_block *nb,
+				 int ignore_existing);
+int ubi_unregister_volume_notifier(struct notifier_block *nb);
+
 void ubi_close_volume(struct ubi_volume_desc *desc);
 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		 int len, int check);

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

* Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-04-29 15:29 [PATCH] [UBI] [1/3] ubi notifications API dmitry pervushin
@ 2009-05-06  6:31 ` Artem Bityutskiy
  2009-05-07  6:14 ` Artem Bityutskiy
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-06  6:31 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Wed, 2009-04-29 at 19:29 +0400, dmitry pervushin wrote:
> UBI volume notifications are intended to create the API to get clients
> notified about volume creation/deletion, renaming and changing(actually,
> resizing). A client can subscribe to these notifications using
> ubi_volume_register and cancel the subscription using
> ubi_volume_unregister. When UBI volume change occurs, the atomic
> notifier will be called. Client also can request "added" event on all
> volumes that existed before client subscribed to the notifications.
> 
> Using notifications instead of calling functions ubi_gluebi_xxx allows
> MTD emulation layer to be more flexible; say, now is it possible to
> build it as a module and load/unload it on demand.
> 
> Thanks Artem Bityutskiy for reviewing the patch and many very valuable
> comments.
> 
> Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
> ---
>  drivers/mtd/ubi/build.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++--
>  drivers/mtd/ubi/cdev.c  |    2 +
>  drivers/mtd/ubi/kapi.c  |   46 +++++++++++++++++++++++++++
>  drivers/mtd/ubi/ubi.h   |   24 ++++++++++++++
>  drivers/mtd/ubi/vmt.c   |    7 ++++
>  include/linux/mtd/ubi.h |   35 +++++++++++++++++++++
>  6 files changed, 191 insertions(+), 3 deletions(-)
> 
> Index: linux-2.6-arm/drivers/mtd/ubi/build.c
> ===================================================================
> --- linux-2.6-arm.orig/drivers/mtd/ubi/build.c
> +++ linux-2.6-arm/drivers/mtd/ubi/build.c
> @@ -122,6 +122,76 @@ static struct device_attribute dev_mtd_n
>  	__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
>  
>  /**
> + * ubi_enum_volumes - "enumerate" volumes.
> + * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
> + * @ubi: UBI device description object
> + * @nb: notifier to be called or %NULL to send to system-wide notification
> + *
> + * This function walks all volumes of UBI device @ubi and sends the
> + * notification specified by @ntype. Returns number of sent notifications.
> + */
> +int ubi_enum_volumes(int ntype, struct ubi_device *ubi,
> +		     struct notifier_block *nb)
> +{
> +	struct ubi_volume_notification nt;
> +	int i, count = 0;
> +
> +	nt.ubi_num = ubi->ubi_num;
> +
> +	spin_lock(&ubi->volumes_lock);
> +	for (i = 0; i < ubi->vtbl_slots; i++) {
> +		if (!ubi->volumes[i])
> +			continue;
> +		nt.vol_id = ubi->volumes[i]->vol_id;
> +		get_device(&ubi->volumes[i]->dev);
> +		ubi->volumes[i]->ref_count += 1;
> +		spin_unlock(&ubi->volumes_lock);
> +		if (nb)
> +			nb->notifier_call(nb, ntype, &nt);
> +		else
> +			blocking_notifier_call_chain(&ubi_notifiers,
> +						     ntype, &nt);
> +		count++;
> +		spin_lock(&ubi->volumes_lock);
> +		ubi->volumes[i]->ref_count -= 1;
> +		put_device(&ubi->volumes[i]->dev);
> +	}
> +	spin_unlock(&ubi->volumes_lock);
> +
> +	return count;
> +}
> +
> +/**
> + * ubi_enum_all_volumes - enumerate all existing volumes and send notification.
> + * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
> + * @nb: notifier to be called, or %NULL to send to system-wide notification
> + *
> + * This function walks all UBI devices and all volumes on the device, and sends
> + * the notification specified by @ntype. Returns number of sent notifications.
> + */
> +int ubi_enum_all_volumes(int ntype, struct notifier_block *nb)
> +{
> +	struct ubi_device *ubi;
> +	int i, count = 0;
> +
> +	spin_lock(&ubi_devices_lock);
> +	for (i = 0; i < UBI_MAX_DEVICES; i++) {
> +		ubi = ubi_devices[i];
> +		if (!ubi)
> +			continue;
> +		ubi->ref_count += 1;
> +		get_device(&ubi->dev);
> +		spin_unlock(&ubi_devices_lock);
> +		count += ubi_enum_volumes(ntype, ubi, nb);
> +		spin_lock(&ubi_devices_lock);
> +		put_device(&ubi->dev);
> +		ubi->ref_count -= 1;
> +	}
> +	spin_unlock(&ubi_devices_lock);
> +	return count;
> +}

The locking is still screwed. I do not think the code will work
when enumeration races with volume creation/deletion etc,
or when it races with device detach. And I do not think the
subscribers will get sensible sequence of events in this
case.

The right solution would be to re-work locking, and use mutexes
instead of this (not very sane) "exlusive" flag.

Roughly, I believe there should be 2 mutexes:

1. global "devices mutex" - locked when whole MTD device is
   attached/detached.
2. per-UBI device "device mutex" - locked when volumes belonging
   to this device are created/removed/resized/renamed.

And this "exlusive" open mode should go away.

I'll see what I can do. I'll try to prepare new locking
for you. Will let you know.

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

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

* Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-04-29 15:29 [PATCH] [UBI] [1/3] ubi notifications API dmitry pervushin
  2009-05-06  6:31 ` Artem Bityutskiy
@ 2009-05-07  6:14 ` Artem Bityutskiy
  2009-05-18  8:05 ` Artem Bityutskiy
  2009-05-18 15:22 ` Artem Bityutskiy
  3 siblings, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-07  6:14 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Wed, 2009-04-29 at 19:29 +0400, dmitry pervushin wrote:
> +/**
> + * ubi_enum_all_volumes - enumerate all existing volumes and send notification.
> + * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
> + * @nb: notifier to be called, or %NULL to send to system-wide notification
> + *
> + * This function walks all UBI devices and all volumes on the device, and sends
> + * the notification specified by @ntype. Returns number of sent notifications.
> + */
> +int ubi_enum_all_volumes(int ntype, struct notifier_block *nb)
> +{
> +	struct ubi_device *ubi;
> +	int i, count = 0;
> +
> +	spin_lock(&ubi_devices_lock);
> +	for (i = 0; i < UBI_MAX_DEVICES; i++) {
> +		ubi = ubi_devices[i];
> +		if (!ubi)
> +			continue;
> +		ubi->ref_count += 1;
> +		get_device(&ubi->dev);
> +		spin_unlock(&ubi_devices_lock);
> +		count += ubi_enum_volumes(ntype, ubi, nb);
> +		spin_lock(&ubi_devices_lock);
> +		put_device(&ubi->dev);
> +		ubi->ref_count -= 1;
> +	}
> +	spin_unlock(&ubi_devices_lock);
> +	return count;
> +}

OK. For this we have ubi_devices_mutex. If you take it,
you prevent UBI devices from being created/removed. So
you do not need the references here, just take the mutex.

Something similar should be done for volume, I'm looking
at this.

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

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

* Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-04-29 15:29 [PATCH] [UBI] [1/3] ubi notifications API dmitry pervushin
  2009-05-06  6:31 ` Artem Bityutskiy
  2009-05-07  6:14 ` Artem Bityutskiy
@ 2009-05-18  8:05 ` Artem Bityutskiy
  2009-05-18 15:22 ` Artem Bityutskiy
  3 siblings, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-18  8:05 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Wed, 2009-04-29 at 19:29 +0400, dmitry pervushin wrote:
> +/**
> + * ubi_register_volume_notifier - register the volume notification function.
> + * @nb: pointer to the filled struct &notifier_block
> + * @ignore_existing: boolean flag; if set to 1, UBI will not send notifications
> + * 		     about ADDing existing volumes
> + *
> + * The function @nb.notifier_call will be called when volume is added,
> + * removed, resized or renamed. Its first parameter is &enum
> + * ubi_volume_notification_type, and the second points to the structure
> + * that contains information about "changed" volume - ubi_num and
> + * volume_id. When the notifier is called, it is safe to use all UBI API.
> + *
> + * Returns %0 on success, error code otherwise.
> + */
> +int ubi_register_volume_notifier(struct notifier_block *nb,
> +				 int ignore_existing)
> +{
> +	int err;
> +
> +	err = blocking_notifier_chain_register(&ubi_notifiers, nb);
> +	if (err != 0)
> +		return err;
> +	if (ignore_existing)
> +		return err;
> +	down_read(&ubi_notifiers.rwsem);
> +
> +	ubi_enum_all_volumes(UBI_VOLUME_ADDED, nb);
> +	up_read(&ubi_notifiers.rwsem);
> +	return err;
> +}

You take the rwsem here. Then:
'ubi_enum_all_volumes()' ->
'ubi_enum_volumes()' ->
'blocking_notifier_call_chain()' ->
'blocking_notifier_call_chain()'

and down_read(&nh->rwsem);

Deadlock. Have you tested your code?

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

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

* Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-04-29 15:29 [PATCH] [UBI] [1/3] ubi notifications API dmitry pervushin
                   ` (2 preceding siblings ...)
  2009-05-18  8:05 ` Artem Bityutskiy
@ 2009-05-18 15:22 ` Artem Bityutskiy
  2009-05-18 15:26   ` [PATCH] UBI: add notification API Artem Bityutskiy
  2009-05-18 15:39   ` [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
  3 siblings, 2 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-18 15:22 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

Dmitry,

I've re-work the first patch of yours. I think the locking should
be correct now. The commit message shortly list the changes I've
done.

I also send the second patch. The only thing I fixed there was
the spelling of your name - I made it start with a capital letter.
I hope you do not mind.

Please, provide the third patch. You should not try to open an
UBI volume from within a notifier, because it won't work. I
think you simply did not test your patches before sending.
Neither did I. But please, this time, do test the patches.
It is very easy to do with nansim.

I'll send the patches as 2 follow-up e-mail for your review.

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

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

* [PATCH] UBI: add notification API
  2009-05-18 15:22 ` Artem Bityutskiy
@ 2009-05-18 15:26   ` Artem Bityutskiy
  2009-05-18 15:28     ` [PATCH] UBI: remove built-in gluebi Artem Bityutskiy
  2009-05-18 15:39   ` [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
  1 sibling, 1 reply; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-18 15:26 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

From: Dmitry Pervushin <dpervushin@embeddedalley.com>
Date: Wed, 29 Apr 2009 19:29:38 +0400
Subject: [PATCH] UBI: add notification API

UBI volume notifications are intended to create the API to get clients
notified about volume creation/deletion, renaming and re-sizing. A
client can subscribe to these notifications using 'ubi_volume_register()'
and cancel the subscription using 'ubi_volume_unregister()'. When UBI
volumes change, a blocking notifier is called. Clients also can request
"added" events on all volumes that existed before client subscribed
to the notifications.

If we use notifications instead of calling functions like 'ubi_gluebi_xxx()',
we can make the MTD emulation layer to be more flexible: build it as a
separate module and load/unload it on demand.

[Artem: many cleanups, rework locking, add "updated" event, provide
 device/volume info in notifiers]

Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/build.c |  100 +++++++++++++++++++++++++++++++++++++++++--
 drivers/mtd/ubi/cdev.c  |    1 +
 drivers/mtd/ubi/kapi.c  |  108 ++++++++++++++++++++++++++++++++++++++++-------
 drivers/mtd/ubi/ubi.h   |   12 +++++
 drivers/mtd/ubi/vmt.c   |    4 ++
 include/linux/mtd/ubi.h |   37 ++++++++++++++++
 6 files changed, 241 insertions(+), 21 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 2c3269e..2dd203d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -122,6 +122,94 @@ static struct device_attribute dev_mtd_num =
 	__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
 
 /**
+ * ubi_volume_notify - send a volume change notification.
+ * @ubi: UBI device description object
+ * @vol: volume description object of the changed volume
+ * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
+ *
+ * This is a helper function which notifies all subscribers about a volume
+ * change event (creation, removal, re-sizing, re-naming, updating). Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype)
+{
+	struct ubi_notification nt;
+
+	ubi_do_get_device_info(ubi, &nt.di);
+	ubi_do_get_volume_info(ubi, vol, &nt.vi);
+	return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
+}
+
+/**
+ * ubi_notify_all - send a notification to all volumes.
+ * @ubi: UBI device description object
+ * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
+ * @nb: the notifier to call
+ *
+ * This function walks all volumes of UBI device @ubi and sends the @ntype
+ * notification for each volume. If @nb is %NULL, then all registered notifiers
+ * are called, otherwise only the @nb notifier is called. Returns the number of
+ * sent notifications.
+ */
+int ubi_notify_all(struct ubi_device *ubi, int ntype, struct notifier_block *nb)
+{
+	struct ubi_notification nt;
+	int i, count = 0;
+
+	ubi_do_get_device_info(ubi, &nt.di);
+
+	mutex_lock(&ubi->device_mutex);
+	for (i = 0; i < ubi->vtbl_slots; i++) {
+		/*
+		 * Since the @ubi->device is locked, and we are not going to
+		 * change @ubi->volumes, we do not have to lock
+		 * @ubi->volumes_lock.
+		 */
+		if (!ubi->volumes[i])
+			continue;
+
+		ubi_do_get_volume_info(ubi, ubi->volumes[i], &nt.vi);
+		if (nb)
+			nb->notifier_call(nb, ntype, &nt);
+		else
+			blocking_notifier_call_chain(&ubi_notifiers, ntype,
+						     &nt);
+		count += 1;
+	}
+	mutex_unlock(&ubi->device_mutex);
+
+	return count;
+}
+
+/**
+ * ubi_enumerate_volumes - send "add" notification for all existing volumes.
+ * @nb: the notifier to call
+ *
+ * This function walks all UBI devices and volumes and sends the
+ * %UBI_VOLUME_ADDED notification for each volume. If @nb is %NULL, then all
+ * registered notifiers are called, otherwise only the @nb notifier is called.
+ * Returns the number of sent notifications.
+ */
+int ubi_enumerate_volumes(struct notifier_block *nb)
+{
+	int i, count = 0;
+
+	/*
+	 * Since the @ubi_devices_mutex is locked, and we are not going to
+	 * change @ubi_devices, we do not have to lock @ubi_devices_lock.
+	 */
+	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+		struct ubi_device *ubi = ubi_devices[i];
+
+		if (!ubi)
+			continue;
+		count += ubi_notify_all(ubi, UBI_VOLUME_ADDED, nb);
+	}
+
+	return count;
+}
+
+/**
  * ubi_get_device - get UBI device.
  * @ubi_num: UBI device number
  *
@@ -876,6 +964,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 	wake_up_process(ubi->bgt_thread);
 
 	ubi_devices[ubi_num] = ubi;
+	ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
 	return ubi_num;
 
 out_uif:
@@ -918,13 +1007,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
 		return -EINVAL;
 
-	spin_lock(&ubi_devices_lock);
-	ubi = ubi_devices[ubi_num];
-	if (!ubi) {
-		spin_unlock(&ubi_devices_lock);
+	ubi = ubi_get_device(ubi_num);
+	if (!ubi)
 		return -EINVAL;
-	}
 
+	spin_lock(&ubi_devices_lock);
+	put_device(&ubi->dev);
+	ubi->ref_count -= 1;
 	if (ubi->ref_count) {
 		if (!anyway) {
 			spin_unlock(&ubi_devices_lock);
@@ -938,6 +1027,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
 	spin_unlock(&ubi_devices_lock);
 
 	ubi_assert(ubi_num == ubi->ubi_num);
+	ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL);
 	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
 
 	/*
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 9a2b217..6319836 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -396,6 +396,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
 		}
 		vol->checked = 1;
 		ubi_gluebi_updated(vol);
+		ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
 		revoke_exclusive(desc, UBI_READWRITE);
 	}
 
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 2675207..88a72e9 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -26,6 +26,24 @@
 #include "ubi.h"
 
 /**
+ * ubi_do_get_device_info - get information about UBI device.
+ * @ubi: UBI device description object
+ * @di: the information is stored here
+ *
+ * This function is the same as 'ubi_get_device_info()', but it assumes the UBI
+ * device is locked and cannot disappear.
+ */
+void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di)
+{
+	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;
+}
+EXPORT_SYMBOL_GPL(ubi_do_get_device_info);
+
+/**
  * ubi_get_device_info - get information about UBI device.
  * @ubi_num: UBI device number
  * @di: the information is stored here
@@ -39,33 +57,24 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
 
 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
 		return -EINVAL;
-
 	ubi = ubi_get_device(ubi_num);
 	if (!ubi)
 		return -ENODEV;
-
-	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_do_get_device_info(ubi, di);
 	ubi_put_device(ubi);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
 
 /**
- * ubi_get_volume_info - get information about UBI volume.
- * @desc: volume descriptor
+ * ubi_do_get_volume_info - get information about UBI volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
  * @vi: the information is stored here
  */
-void ubi_get_volume_info(struct ubi_volume_desc *desc,
-			 struct ubi_volume_info *vi)
+void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
+			    struct ubi_volume_info *vi)
 {
-	const struct ubi_volume *vol = desc->vol;
-	const struct ubi_device *ubi = vol->ubi;
-
 	vi->vol_id = vol->vol_id;
 	vi->ubi_num = ubi->ubi_num;
 	vi->size = vol->reserved_pebs;
@@ -79,6 +88,17 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc,
 	vi->name = vol->name;
 	vi->cdev = vol->cdev.dev;
 }
+
+/**
+ * ubi_get_volume_info - get information about UBI volume.
+ * @desc: volume descriptor
+ * @vi: the information is stored here
+ */
+void ubi_get_volume_info(struct ubi_volume_desc *desc,
+			 struct ubi_volume_info *vi)
+{
+	ubi_do_get_volume_info(desc->vol->ubi, desc->vol, vi);
+}
 EXPORT_SYMBOL_GPL(ubi_get_volume_info);
 
 /**
@@ -561,7 +581,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
 EXPORT_SYMBOL_GPL(ubi_leb_unmap);
 
 /**
- * ubi_leb_map - map logical erasblock to a physical eraseblock.
+ * ubi_leb_map - map logical eraseblock to a physical eraseblock.
  * @desc: volume descriptor
  * @lnum: logical eraseblock number
  * @dtype: expected data type
@@ -659,3 +679,59 @@ int ubi_sync(int ubi_num)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_sync);
+
+BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
+
+/**
+ * ubi_register_volume_notifier - register a volume notifier.
+ * @nb: the notifier description object
+ * @ignore_existing: if non-zero, do not send "added" notification for all
+ *                   already existing volumes
+ *
+ * This function registers a volume notifier, which means that
+ * 'nb->notifier_call()' will be invoked when an UBI  volume is created,
+ * removed, re-sized, re-named, or updated. The first argument of the function
+ * is the notification type. The second argument is pointer to a
+ * &struct ubi_notification object which describes the notification event.
+ * Using UBI API from the volume notifier is prohibited.
+ *
+ * This function returns zero in case of success and a negative error code
+ * in case of failure.
+ */
+int ubi_register_volume_notifier(struct notifier_block *nb,
+				 int ignore_existing)
+{
+	int err;
+
+	err = blocking_notifier_chain_register(&ubi_notifiers, nb);
+	if (err != 0)
+		return err;
+	if (ignore_existing)
+		return 0;
+
+	/*
+	 * We are going to walk all UBI devices and all volumes, and
+	 * notify the user about existing volumes by the %UBI_VOLUME_ADDED
+	 * event. We have to lock the @ubi_devices_mutex to make sure UBI
+	 * devices do not disappear.
+	 */
+	mutex_lock(&ubi_devices_mutex);
+	ubi_enumerate_volumes(nb);
+	mutex_unlock(&ubi_devices_mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_register_volume_notifier);
+
+/**
+ * ubi_unregister_volume_notifier - unregister the volume notifier.
+ * @nb: the notifier description object
+ *
+ * This function unregisters volume notifier @nm and returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_unregister_volume_notifier(struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&ubi_notifiers, nb);
+}
+EXPORT_SYMBOL_GPL(ubi_unregister_volume_notifier);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 749007e..b5441db 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -38,6 +38,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/ubi.h>
+#include <linux/notifier.h>
 
 #include "ubi-media.h"
 #include "scan.h"
@@ -455,6 +456,7 @@ extern const struct file_operations ubi_cdev_operations;
 extern const struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
 extern struct mutex ubi_devices_mutex;
+extern struct blocking_notifier_head ubi_notifiers;
 
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -547,6 +549,16 @@ 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);
+int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
+		      int ntype);
+int ubi_notify_all(struct ubi_device *ubi, int ntype,
+		   struct notifier_block *nb);
+int ubi_enumerate_volumes(struct notifier_block *nb);
+
+/* kapi.c */
+void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
+void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
+			    struct ubi_volume_info *vi);
 
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 8e8d6fa..e151862 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -358,6 +358,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 	ubi->vol_count += 1;
 	spin_unlock(&ubi->volumes_lock);
 
+	ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
 	if (paranoid_check_volumes(ubi))
 		dbg_err("check failed while creating volume %d", vol_id);
 	return err;
@@ -466,6 +467,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
 	ubi->vol_count -= 1;
 	spin_unlock(&ubi->volumes_lock);
 
+	ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
 	if (!no_vtbl && paranoid_check_volumes(ubi))
 		dbg_err("check failed while removing volume %d", vol_id);
 
@@ -589,6 +591,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
 			(long long)vol->used_ebs * vol->usable_leb_size;
 	}
 
+	ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
 	if (paranoid_check_volumes(ubi))
 		dbg_err("check failed while re-sizing volume %d", vol_id);
 	return err;
@@ -635,6 +638,7 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
 			vol->name_len = re->new_name_len;
 			memcpy(vol->name, re->new_name, re->new_name_len + 1);
 			spin_unlock(&ubi->volumes_lock);
+			ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED);
 		}
 	}
 
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index 6316faf..6913b71 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -132,6 +132,39 @@ struct ubi_device_info {
 	dev_t cdev;
 };
 
+/*
+ * enum - volume notification types.
+ * @UBI_VOLUME_ADDED: volume has been added
+ * @UBI_VOLUME_REMOVED: start volume volume
+ * @UBI_VOLUME_RESIZED: volume size has been re-sized
+ * @UBI_VOLUME_RENAMED: volume name has been re-named
+ * @UBI_VOLUME_UPDATED: volume name has been updated
+ *
+ * These constants define which type of event has happened when a volume
+ * notification function is invoked.
+ */
+enum {
+	UBI_VOLUME_ADDED,
+	UBI_VOLUME_REMOVED,
+	UBI_VOLUME_RESIZED,
+	UBI_VOLUME_RENAMED,
+	UBI_VOLUME_UPDATED,
+};
+
+/*
+ * struct ubi_notification - UBI notification description structure.
+ * @di: UBI device description object
+ * @vi: UBI volume description object
+ *
+ * UBI notifiers are called with a pointer to an object of this type. The
+ * object describes the notification. Namely, it provides a description of the
+ * UBI device and UBI volume the notification informs about.
+ */
+struct ubi_notification {
+	struct ubi_device_info di;
+	struct ubi_volume_info vi;
+};
+
 /* UBI descriptor given to users when they open UBI volumes */
 struct ubi_volume_desc;
 
@@ -141,6 +174,10 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc,
 struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode);
 struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 					   int mode);
+int ubi_register_volume_notifier(struct notifier_block *nb,
+				 int ignore_existing);
+int ubi_unregister_volume_notifier(struct notifier_block *nb);
+
 void ubi_close_volume(struct ubi_volume_desc *desc);
 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		 int len, int check);
-- 
1.6.0.6

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

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

* [PATCH] UBI: remove built-in gluebi
  2009-05-18 15:26   ` [PATCH] UBI: add notification API Artem Bityutskiy
@ 2009-05-18 15:28     ` Artem Bityutskiy
  0 siblings, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-18 15:28 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

From: Dmitry Pervushin <dpervushin@embeddedalley.com>
Date: Wed, 29 Apr 2009 19:29:44 +0400
Subject: [PATCH] UBI: remove built-in gluebi

Remove built-in gluebi support. This is a preparation for a
standalone glubi module support

Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/cdev.c |    1 -
 drivers/mtd/ubi/ubi.h  |   26 --------------------------
 drivers/mtd/ubi/vmt.c  |   26 ++------------------------
 3 files changed, 2 insertions(+), 51 deletions(-)

diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 6319836..f237ddb 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -395,7 +395,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
 			vol->corrupted = 1;
 		}
 		vol->checked = 1;
-		ubi_gluebi_updated(vol);
 		ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
 		revoke_exclusive(desc, UBI_READWRITE);
 	}
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index b5441db..7847369 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -209,10 +209,6 @@ struct ubi_volume_desc;
  * @changing_leb: %1 if the atomic LEB change ioctl command is in progress
  * @direct_writes: %1 if direct writes are enabled for this volume
  *
- * @gluebi_desc: gluebi UBI volume descriptor
- * @gluebi_refcount: reference count of the gluebi MTD device
- * @gluebi_mtd: MTD device description object of the gluebi MTD device
- *
  * The @corrupted field indicates that the volume's contents is corrupted.
  * Since UBI protects only static volumes, this field is not relevant to
  * dynamic volumes - it is user's responsibility to assure their data
@@ -256,17 +252,6 @@ struct ubi_volume {
 	unsigned int updating:1;
 	unsigned int changing_leb:1;
 	unsigned int direct_writes:1;
-
-#ifdef CONFIG_MTD_UBI_GLUEBI
-	/*
-	 * Gluebi-related stuff may be compiled out.
-	 * Note: this should not be built into UBI but should be a separate
-	 * ubimtd driver which works on top of UBI and emulates MTD devices.
-	 */
-	struct ubi_volume_desc *gluebi_desc;
-	int gluebi_refcount;
-	struct mtd_info gluebi_mtd;
-#endif
 };
 
 /**
@@ -489,17 +474,6 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
 int ubi_check_volume(struct ubi_device *ubi, int vol_id);
 void ubi_calculate_reserved(struct ubi_device *ubi);
 
-/* gluebi.c */
-#ifdef CONFIG_MTD_UBI_GLUEBI
-int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
-int ubi_destroy_gluebi(struct ubi_volume *vol);
-void ubi_gluebi_updated(struct ubi_volume *vol);
-#else
-#define ubi_create_gluebi(ubi, vol) 0
-#define ubi_destroy_gluebi(vol) 0
-#define ubi_gluebi_updated(vol)
-#endif
-
 /* eba.c */
 int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
 		      int lnum);
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index e151862..ab64cb5 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -317,10 +317,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 		goto out_mapping;
 	}
 
-	err = ubi_create_gluebi(ubi, vol);
-	if (err)
-		goto out_cdev;
-
 	vol->dev.release = vol_release;
 	vol->dev.parent = &ubi->dev;
 	vol->dev.devt = dev;
@@ -330,7 +326,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 	err = device_register(&vol->dev);
 	if (err) {
 		ubi_err("cannot register device");
-		goto out_gluebi;
+		goto out_cdev;
 	}
 
 	err = volume_sysfs_init(ubi, vol);
@@ -375,10 +371,6 @@ out_sysfs:
 	do_free = 0;
 	get_device(&vol->dev);
 	volume_sysfs_close(vol);
-out_gluebi:
-	if (ubi_destroy_gluebi(vol))
-		dbg_err("cannot destroy gluebi for volume %d:%d",
-			ubi->ubi_num, vol_id);
 out_cdev:
 	cdev_del(&vol->cdev);
 out_mapping:
@@ -433,10 +425,6 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
 	ubi->volumes[vol_id] = NULL;
 	spin_unlock(&ubi->volumes_lock);
 
-	err = ubi_destroy_gluebi(vol);
-	if (err)
-		goto out_err;
-
 	if (!no_vtbl) {
 		err = ubi_change_vtbl_record(ubi, vol_id, NULL);
 		if (err)
@@ -674,10 +662,6 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 		return err;
 	}
 
-	err = ubi_create_gluebi(ubi, vol);
-	if (err)
-		goto out_cdev;
-
 	vol->dev.release = vol_release;
 	vol->dev.parent = &ubi->dev;
 	vol->dev.devt = dev;
@@ -685,12 +669,11 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
 	err = device_register(&vol->dev);
 	if (err)
-		goto out_gluebi;
+		goto out_cdev;
 
 	err = volume_sysfs_init(ubi, vol);
 	if (err) {
 		cdev_del(&vol->cdev);
-		err = ubi_destroy_gluebi(vol);
 		volume_sysfs_close(vol);
 		return err;
 	}
@@ -699,8 +682,6 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 		dbg_err("check failed while adding volume %d", vol_id);
 	return err;
 
-out_gluebi:
-	err = ubi_destroy_gluebi(vol);
 out_cdev:
 	cdev_del(&vol->cdev);
 	return err;
@@ -716,12 +697,9 @@ out_cdev:
  */
 void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 {
-	int err;
-
 	dbg_gen("free volume %d", vol->vol_id);
 
 	ubi->volumes[vol->vol_id] = NULL;
-	err = ubi_destroy_gluebi(vol);
 	cdev_del(&vol->cdev);
 	volume_sysfs_close(vol);
 }
-- 
1.6.0.6

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

* Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-05-18 15:22 ` Artem Bityutskiy
  2009-05-18 15:26   ` [PATCH] UBI: add notification API Artem Bityutskiy
@ 2009-05-18 15:39   ` Artem Bityutskiy
  2009-05-29 19:27     ` [PATCH] 3/3 ubi notification API " dmitry pervushin
  1 sibling, 1 reply; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-18 15:39 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Mon, 2009-05-18 at 18:22 +0300, Artem Bityutskiy wrote:
> Dmitry,
> 
> I've re-work the first patch of yours. I think the locking should
> be correct now. The commit message shortly list the changes I've
> done.
> 
> I also send the second patch. The only thing I fixed there was
> the spelling of your name - I made it start with a capital letter.
> I hope you do not mind.
> 
> Please, provide the third patch. You should not try to open an
> UBI volume from within a notifier, because it won't work. I
> think you simply did not test your patches before sending.
> Neither did I. But please, this time, do test the patches.
> It is very easy to do with nansim.
> 
> I'll send the patches as 2 follow-up e-mail for your review.

I've also created an "experimental" branch in the ubi-2.6.git
tree for your convenience:

http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
git://git.infradead.org/ubi-2.6.git experimental

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

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

* [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-05-18 15:39   ` [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
@ 2009-05-29 19:27     ` dmitry pervushin
  2009-05-31 13:52       ` Artem Bityutskiy
  2009-05-31 14:06       ` [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
  0 siblings, 2 replies; 15+ messages in thread
From: dmitry pervushin @ 2009-05-29 19:27 UTC (permalink / raw)
  To: dedekind; +Cc: linux-mtd

On Mon, 2009-05-18 at 18:39 +0300, Artem Bityutskiy wrote:
> On Mon, 2009-05-18 at 18:22 +0300, Artem Bityutskiy wrote:
> > Dmitry,
> > 
> > I've re-work the first patch of yours. I think the locking should
> > be correct now. The commit message shortly list the changes I've
> > done.
> > 
> > I also send the second patch. The only thing I fixed there was
> > the spelling of your name - I made it start with a capital letter.
> > I hope you do not mind.
> > 
> > Please, provide the third patch. You should not try to open an
> > UBI volume from within a notifier, because it won't work. I
> > think you simply did not test your patches before sending.
> > Neither did I. But please, this time, do test the patches.
> > It is very easy to do with nansim.
> > 
> > I'll send the patches as 2 follow-up e-mail for your review.
> 
> I've also created an "experimental" branch in the ubi-2.6.git
> tree for your convenience:
> 
> http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
> git://git.infradead.org/ubi-2.6.git experimental
Sorry for late response; I reviewed your changes, and although
prohibiting of using ubi api from within notifiers does not look very
amazing to me... but it seems that it is the only robust way. The 3rd
patch from the serie is inlined below (tested on the stmp378x board as
well as on nandsim)

The standalone gluebi support that uses UBI notifications.

Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>

---
 drivers/mtd/ubi/Kconfig  |    2 
 drivers/mtd/ubi/Makefile |    2 
 drivers/mtd/ubi/gluebi.c |  217 +++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 183 insertions(+), 38 deletions(-)

Index: linux-2.6/drivers/mtd/ubi/Kconfig
===================================================================
--- linux-2.6.orig/drivers/mtd/ubi/Kconfig
+++ linux-2.6/drivers/mtd/ubi/Kconfig
@@ -49,7 +49,7 @@ config MTD_UBI_BEB_RESERVE
 	  reserved. Leave the default value if unsure.
 
 config MTD_UBI_GLUEBI
-	bool "Emulate MTD devices"
+	tristate "Emulate MTD devices"
 	default n
 	depends on MTD_UBI
 	help
Index: linux-2.6/drivers/mtd/ubi/Makefile
===================================================================
--- linux-2.6.orig/drivers/mtd/ubi/Makefile
+++ linux-2.6/drivers/mtd/ubi/Makefile
@@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev
 ubi-y += misc.o
 
 ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
-ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
Index: linux-2.6/drivers/mtd/ubi/gluebi.c
===================================================================
--- linux-2.6.orig/drivers/mtd/ubi/gluebi.c
+++ linux-2.6/drivers/mtd/ubi/gluebi.c
@@ -31,6 +31,32 @@
 #include <linux/math64.h>
 #include "ubi.h"
 
+struct ubi_gluebi_volume {
+	struct mtd_info gluebi_mtd;
+	int gluebi_refcount;
+	struct ubi_volume_desc *gluebi_desc;
+	int ubi_num;
+	int vol_id;
+	struct list_head list;
+};
+
+static LIST_HEAD(ubi_gluebi_mtds);
+static DEFINE_SPINLOCK(ubi_gluebi_lock);
+
+static struct ubi_gluebi_volume *ubi_gluebi_find(int ubi_num, int vol_id)
+{
+	struct ubi_gluebi_volume *pos = NULL;
+
+	spin_lock(&ubi_gluebi_lock);
+	list_for_each_entry(pos, &ubi_gluebi_mtds, list)
+		if (pos->ubi_num == ubi_num && pos->vol_id == vol_id) {
+			spin_unlock(&ubi_gluebi_lock);
+			return pos;
+		}
+	spin_unlock(&ubi_gluebi_lock);
+	return NULL;
+}
+
 /**
  * gluebi_get_device - get MTD device reference.
  * @mtd: the MTD device description object
@@ -41,9 +67,13 @@
  */
 static int gluebi_get_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
+	struct ubi_gluebi_volume *vol;
+	int ubi_mode = UBI_READWRITE;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		ubi_mode = UBI_READONLY;
+
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
 	/*
 	 * We do not introduce locks for gluebi reference count because the
@@ -66,8 +96,7 @@ static int gluebi_get_device(struct mtd_
 	 * This is the first reference to this UBI volume via the MTD device
 	 * interface. Open the corresponding volume in read-write mode.
 	 */
-	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
-					   UBI_READWRITE);
+	vol->gluebi_desc = ubi_open_volume(vol->ubi_num, vol->vol_id, ubi_mode);
 	if (IS_ERR(vol->gluebi_desc))
 		return PTR_ERR(vol->gluebi_desc);
 	vol->gluebi_refcount += 1;
@@ -83,9 +112,9 @@ static int gluebi_get_device(struct mtd_
  */
 static void gluebi_put_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
+	struct ubi_gluebi_volume *vol;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 	vol->gluebi_refcount -= 1;
 	ubi_assert(vol->gluebi_refcount >= 0);
 	if (vol->gluebi_refcount == 0)
@@ -107,16 +136,14 @@ static int gluebi_read(struct mtd_info *
 		       size_t *retlen, unsigned char *buf)
 {
 	int err = 0, lnum, offs, total_read;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("read %zd bytes from offset %lld", len, from);
 
 	if (len < 0 || from < 0 || from + len > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
 	lnum = div_u64_rem(from, mtd->erasesize, &offs);
 	total_read = len;
@@ -126,7 +153,7 @@ static int gluebi_read(struct mtd_info *
 		if (to_read > total_read)
 			to_read = total_read;
 
-		err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);
+		err = ubi_read(vol->gluebi_desc, lnum, buf, offs, to_read);
 		if (err)
 			break;
 
@@ -155,18 +182,16 @@ static int gluebi_write(struct mtd_info
 		       size_t *retlen, const u_char *buf)
 {
 	int err = 0, lnum, offs, total_written;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("write %zd bytes to offset %lld", len, to);
 
 	if (len < 0 || to < 0 || len + to > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
 	lnum = div_u64_rem(to, mtd->erasesize, &offs);
@@ -181,8 +206,7 @@ static int gluebi_write(struct mtd_info
 		if (to_write > total_written)
 			to_write = total_written;
 
-		err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,
-					UBI_UNKNOWN);
+		err = ubi_write(vol->gluebi_desc, lnum, buf, offs, to_write);
 		if (err)
 			break;
 
@@ -207,8 +231,7 @@ static int gluebi_write(struct mtd_info
 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	int err, i, lnum, count;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
 		 (unsigned long long)instr->addr);
@@ -225,23 +248,24 @@ static int gluebi_erase(struct mtd_info
 	lnum = mtd_div_by_eb(instr->addr, mtd);
 	count = mtd_div_by_eb(instr->len, mtd);
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
-	for (i = 0; i < count; i++) {
-		err = ubi_eba_unmap_leb(ubi, vol, lnum + i);
+	for (i = 0; i < count - 1; i++) {
+		err = ubi_leb_unmap(vol->gluebi_desc, lnum + i);
 		if (err)
 			goto out_err;
 	}
-
 	/*
 	 * MTD erase operations are synchronous, so we have to make sure the
 	 * physical eraseblock is wiped out.
+	 *
+	 * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
+	 * will wait for the end of operations
 	 */
-	err = ubi_wl_flush(ubi);
+	err = ubi_leb_erase(vol->gluebi_desc, lnum + i);
 	if (err)
 		goto out_err;
 
@@ -264,13 +288,28 @@ out_err:
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
+static int ubi_create_gluebi(struct ubi_device_info *ubi,
+			     struct ubi_volume_info *vol)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *v;
+	struct mtd_info *mtd;
+
+	v = kzalloc(sizeof(*v), GFP_KERNEL);
+	if (!v) {
+		ubi_err("Cannot allocate ubi_gluebi_vol");
+		return -ENOMEM;
+	}
+
+	mtd = &v->gluebi_mtd;
 
 	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
-	if (!mtd->name)
+	if (!mtd->name) {
+		ubi_err("Cannot allocate mtd->name");
+		kfree(v);
 		return -ENOMEM;
+	}
+
+	v->vol_id = vol->vol_id;
 
 	mtd->type = MTD_UBIVOLUME;
 	if (!ubi->ro_mode)
@@ -290,16 +329,21 @@ int ubi_create_gluebi(struct ubi_device
 	 * bytes.
 	 */
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
-		mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
+		mtd->size = (long long)vol->usable_leb_size * vol->size;
 	else
 		mtd->size = vol->used_bytes;
 
 	if (add_mtd_device(mtd)) {
 		ubi_err("cannot not add MTD device");
 		kfree(mtd->name);
+		kfree(v);
 		return -ENFILE;
 	}
 
+	spin_lock(&ubi_gluebi_lock);
+	list_add_tail(&v->list, &ubi_gluebi_mtds);
+	spin_unlock(&ubi_gluebi_lock);
+
 	dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
 		mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
 	return 0;
@@ -313,16 +357,28 @@ int ubi_create_gluebi(struct ubi_device
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_destroy_gluebi(struct ubi_volume *vol)
+static int ubi_destroy_gluebi(int ubi_num, int ubi_vol_id)
 {
 	int err;
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *vol;
+	struct mtd_info *mtd;
+
+	vol = ubi_gluebi_find(ubi_num, ubi_vol_id);
+	if (!vol)
+		return -ENOENT;
 
+	mtd = &vol->gluebi_mtd;
 	dbg_gen("remove mtd%d", mtd->index);
 	err = del_mtd_device(mtd);
 	if (err)
 		return err;
 	kfree(mtd->name);
+
+	spin_lock(&ubi_gluebi_lock);
+	list_del(&vol->list);
+	spin_unlock(&ubi_gluebi_lock);
+
+	kfree(vol);
 	return 0;
 }
 
@@ -335,10 +391,98 @@ int ubi_destroy_gluebi(struct ubi_volume
  * volume is static. This is needed because static volumes cannot be read past
  * data they contain.
  */
-void ubi_gluebi_updated(struct ubi_volume *vol)
+static void ubi_gluebi_updated(struct ubi_volume_info *vol)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *gluebi_vol;
+
+	gluebi_vol = ubi_gluebi_find(vol->ubi_num, vol->vol_id);
+	if (!vol)
+		return /* -ENOENT */;
 
 	if (vol->vol_type == UBI_STATIC_VOLUME)
-		mtd->size = vol->used_bytes;
+		gluebi_vol->gluebi_mtd.size = vol->used_bytes;
 }
+
+/**
+ * ubi_gluebi_openvol - open the volume and get volume_info.
+ * @ubi_num: UBI device number
+ * @volume_id: volume id
+ * @vol: volume_desc for new opened volume will be stored here
+ * @vi: volume info will be stored here
+ */
+static int ubi_gluebi_openvol(int ubi_num, int volume_id,
+			      struct ubi_volume_desc **vol,
+			      struct ubi_volume_info *vi)
+{
+	BUG_ON(!vol || !vi);
+	*vol = ubi_open_volume(ubi_num, volume_id,
+			UBI_READONLY);
+	if (IS_ERR(vol)) {
+		dbg_gen("ubi_open_volume error %ld\n", PTR_ERR(vol));
+		return PTR_ERR(vol);
+	}
+	ubi_get_volume_info(*vol, vi);
+	return 0;
+}
+
+/**
+ * ubi_gluebi_notify - notification handler.
+ * @nb: the registered notifier_block
+ * @l: notification type
+ * @ns_ptr: pointer to the &struct ubi_volume_notification
+ */
+static int ubi_gluebi_notify(struct notifier_block *nb,
+			     unsigned long l, void *ns_ptr)
+{
+	struct ubi_device_info di;
+	struct ubi_volume_info vi;
+	struct ubi_volume_desc *vol = NULL;
+	struct ubi_volume_notification *ns = ns_ptr;
+
+	switch (l) {
+	case UBI_VOLUME_ADDED:
+		if (ubi_gluebi_openvol(ns->ubi_num, ns->vol_id,
+				       &vol, &vi))
+			return NOTIFY_OK;
+		ubi_get_device_info(ns->ubi_num, &di);
+		ubi_create_gluebi(&di, &vi);
+		break;
+	case UBI_VOLUME_DELETED:
+		ubi_destroy_gluebi(ns->ubi_num, ns->vol_id);
+		break;
+	case UBI_VOLUME_CHANGED:
+		if (ubi_gluebi_openvol(ns->ubi_num, ns->vol_id,
+				       &vol, &vi))
+			return NOTIFY_OK;
+		ubi_gluebi_updated(&vi);
+		break;
+	case UBI_VOLUME_RENAMED:
+		break;
+	}
+
+	if (vol)
+		ubi_close_volume(vol);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ubi_gluebi_notifier = {
+	.notifier_call	= ubi_gluebi_notify,
+};
+
+static int __init ubi_gluebi_init(void)
+{
+	spin_lock_init(&ubi_gluebi_lock);
+	return ubi_register_volume_notifier(&ubi_gluebi_notifier, 0);
+}
+
+static void __exit ubi_gluebi_exit(void)
+{
+	ubi_unregister_volume_notifier(&ubi_gluebi_notifier);
+}
+
+module_init(ubi_gluebi_init);
+module_exit(ubi_gluebi_exit);
+MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
+MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
+MODULE_LICENSE("GPL");

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

* Re: [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-05-29 19:27     ` [PATCH] 3/3 ubi notification API " dmitry pervushin
@ 2009-05-31 13:52       ` Artem Bityutskiy
  2009-05-31 14:32         ` [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API) dmitry pervushin
  2009-05-31 14:06       ` [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
  1 sibling, 1 reply; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-31 13:52 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Fri, 2009-05-29 at 23:27 +0400, dmitry pervushin wrote:
> > I've also created an "experimental" branch in the ubi-2.6.git
> > tree for your convenience:
> > 
> > http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
> > git://git.infradead.org/ubi-2.6.git experimental
> Sorry for late response; I reviewed your changes, and although
> prohibiting of using ubi api from within notifiers does not look very
> amazing to me... but it seems that it is the only robust way. The 3rd
> patch from the serie is inlined below (tested on the stmp378x board as
> well as on nandsim)
> 
> The standalone gluebi support that uses UBI notifications.
> 
> Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>

Just applied this to
git://git.infradead.org/ubi-2.6.git experimental

and got:

[dedekind@eru ubi-2.6]$ make -j8
scripts/kconfig/conf -s arch/x86/Kconfig
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  SYMLINK include/asm -> include/asm-x86
  CALL    scripts/checksyscalls.sh
  CHK     include/linux/compile.h
  CC [M]  drivers/mtd/ubi/gluebi.o
drivers/mtd/ubi/gluebi.c: In function ‘ubi_gluebi_notify’:
drivers/mtd/ubi/gluebi.c:444: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:444: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:447: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:450: error: ‘UBI_VOLUME_DELETED’ undeclared (first use in this function)
drivers/mtd/ubi/gluebi.c:450: error: (Each undeclared identifier is reported only once
drivers/mtd/ubi/gluebi.c:450: error: for each function it appears in.)
drivers/mtd/ubi/gluebi.c:451: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:451: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:453: error: ‘UBI_VOLUME_CHANGED’ undeclared (first use in this function)
drivers/mtd/ubi/gluebi.c:454: error: dereferencing pointer to incomplete type
drivers/mtd/ubi/gluebi.c:454: error: dereferencing pointer to incomplete type
make[3]: *** [drivers/mtd/ubi/gluebi.o] Error 1
make[2]: *** [drivers/mtd/ubi] Error 2
make[1]: *** [drivers/mtd] Error 2
make[1]: *** Waiting for unfinished jobs....
make: *** [drivers] Error 2

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

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

* Re: [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API
  2009-05-29 19:27     ` [PATCH] 3/3 ubi notification API " dmitry pervushin
  2009-05-31 13:52       ` Artem Bityutskiy
@ 2009-05-31 14:06       ` Artem Bityutskiy
  1 sibling, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-05-31 14:06 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Fri, 2009-05-29 at 23:27 +0400, dmitry pervushin wrote:
> On Mon, 2009-05-18 at 18:39 +0300, Artem Bityutskiy wrote:
> > On Mon, 2009-05-18 at 18:22 +0300, Artem Bityutskiy wrote:
> > > Dmitry,
> > > 
> > > I've re-work the first patch of yours. I think the locking should
> > > be correct now. The commit message shortly list the changes I've
> > > done.
> > > 
> > > I also send the second patch. The only thing I fixed there was
> > > the spelling of your name - I made it start with a capital letter.
> > > I hope you do not mind.
> > > 
> > > Please, provide the third patch. You should not try to open an
> > > UBI volume from within a notifier, because it won't work. I
> > > think you simply did not test your patches before sending.
> > > Neither did I. But please, this time, do test the patches.
> > > It is very easy to do with nansim.
> > > 
> > > I'll send the patches as 2 follow-up e-mail for your review.
> > 
> > I've also created an "experimental" branch in the ubi-2.6.git
> > tree for your convenience:
> > 
> > http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
> > git://git.infradead.org/ubi-2.6.git experimental
> Sorry for late response; I reviewed your changes, and although
> prohibiting of using ubi api from within notifiers does not look very
> amazing to me... but it seems that it is the only robust way. The 3rd
> patch from the serie is inlined below (tested on the stmp378x board as
> well as on nandsim)

Well. I assume that:

1. when gluebi is notified, it creates its data structures without
   opening the UBI volume;
2. when a gluebi /dev/mtdX device is being opened, the the corresponding
   UBI volume is opened as well.

At least for gluebi's purposes it seems to be enough. Recursions are
painful and I would keep things simple, unless we have more complex
use-cases where we would have to invent something trickier.

But anyway, AFAIR I re-named many constants and strictures in your
original patces to make them a bit more consistent/shorter. But your new
patch N.3 does not seem to be against those 2 patches I sent you (and
also put to the "experimental" branch).

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

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

* Re: [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API)
  2009-05-31 13:52       ` Artem Bityutskiy
@ 2009-05-31 14:32         ` dmitry pervushin
  2009-06-01 16:48           ` Artem Bityutskiy
  0 siblings, 1 reply; 15+ messages in thread
From: dmitry pervushin @ 2009-05-31 14:32 UTC (permalink / raw)
  To: dedekind; +Cc: linux-mtd

On Sun, 2009-05-31 at 16:52 +0300, Artem Bityutskiy wrote: 
> On Fri, 2009-05-29 at 23:27 +0400, dmitry pervushin wrote:
> > > I've also created an "experimental" branch in the ubi-2.6.git
> > > tree for your convenience:
> > > 
> > > http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
> > > git://git.infradead.org/ubi-2.6.git experimental
> > Sorry for late response; I reviewed your changes, and although
> > prohibiting of using ubi api from within notifiers does not look very
> > amazing to me... but it seems that it is the only robust way. The 3rd
> > patch from the serie is inlined below (tested on the stmp378x board as
> > well as on nandsim)
> > 
> > The standalone gluebi support that uses UBI notifications.
> > 
> > Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
> 
> Just applied this to
> git://git.infradead.org/ubi-2.6.git experimental
> 
> and got:
> 
Oh, shame on me. I attached the patch with the same name from the wrong
directory; below is the correct one.

Signed-off-by: dmitry pervushin <dpervushin@embeddedalley.com>

---
 drivers/mtd/ubi/Kconfig  |    2 
 drivers/mtd/ubi/Makefile |    2 
 drivers/mtd/ubi/gluebi.c |  191 ++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 152 insertions(+), 43 deletions(-)

Index: experimental/drivers/mtd/ubi/Kconfig
===================================================================
--- experimental.orig/drivers/mtd/ubi/Kconfig
+++ experimental/drivers/mtd/ubi/Kconfig
@@ -49,7 +49,7 @@ config MTD_UBI_BEB_RESERVE
 	  reserved. Leave the default value if unsure.
 
 config MTD_UBI_GLUEBI
-	bool "Emulate MTD devices"
+	tristate "Emulate MTD devices"
 	default n
 	depends on MTD_UBI
 	help
Index: experimental/drivers/mtd/ubi/Makefile
===================================================================
--- experimental.orig/drivers/mtd/ubi/Makefile
+++ experimental/drivers/mtd/ubi/Makefile
@@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev
 ubi-y += misc.o
 
 ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
-ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
Index: experimental/drivers/mtd/ubi/gluebi.c
===================================================================
--- experimental.orig/drivers/mtd/ubi/gluebi.c
+++ experimental/drivers/mtd/ubi/gluebi.c
@@ -31,6 +31,32 @@
 #include <linux/math64.h>
 #include "ubi.h"
 
+struct ubi_gluebi_volume {
+	struct mtd_info gluebi_mtd;
+	int gluebi_refcount;
+	struct ubi_volume_desc *gluebi_desc;
+	int ubi_num;
+	int vol_id;
+	struct list_head list;
+};
+
+static LIST_HEAD(ubi_gluebi_mtds);
+static DEFINE_SPINLOCK(ubi_gluebi_lock);
+
+static struct ubi_gluebi_volume *ubi_gluebi_find(int ubi_num, int vol_id)
+{
+	struct ubi_gluebi_volume *pos = NULL;
+
+	spin_lock(&ubi_gluebi_lock);
+	list_for_each_entry(pos, &ubi_gluebi_mtds, list)
+		if (pos->ubi_num == ubi_num && pos->vol_id == vol_id) {
+			spin_unlock(&ubi_gluebi_lock);
+			return pos;
+		}
+	spin_unlock(&ubi_gluebi_lock);
+	return NULL;
+}
+
 /**
  * gluebi_get_device - get MTD device reference.
  * @mtd: the MTD device description object
@@ -41,9 +67,13 @@
  */
 static int gluebi_get_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
+	struct ubi_gluebi_volume *vol;
+	int ubi_mode = UBI_READONLY;
+
+	if (mtd->flags & MTD_WRITEABLE)
+		ubi_mode = UBI_READWRITE;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
 	/*
 	 * We do not introduce locks for gluebi reference count because the
@@ -66,8 +96,7 @@ static int gluebi_get_device(struct mtd_
 	 * This is the first reference to this UBI volume via the MTD device
 	 * interface. Open the corresponding volume in read-write mode.
 	 */
-	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
-					   UBI_READWRITE);
+	vol->gluebi_desc = ubi_open_volume(vol->ubi_num, vol->vol_id, ubi_mode);
 	if (IS_ERR(vol->gluebi_desc))
 		return PTR_ERR(vol->gluebi_desc);
 	vol->gluebi_refcount += 1;
@@ -83,9 +112,9 @@ static int gluebi_get_device(struct mtd_
  */
 static void gluebi_put_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
+	struct ubi_gluebi_volume *vol;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 	vol->gluebi_refcount -= 1;
 	ubi_assert(vol->gluebi_refcount >= 0);
 	if (vol->gluebi_refcount == 0)
@@ -107,16 +136,14 @@ static int gluebi_read(struct mtd_info *
 		       size_t *retlen, unsigned char *buf)
 {
 	int err = 0, lnum, offs, total_read;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("read %zd bytes from offset %lld", len, from);
 
 	if (len < 0 || from < 0 || from + len > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
 	lnum = div_u64_rem(from, mtd->erasesize, &offs);
 	total_read = len;
@@ -126,7 +153,7 @@ static int gluebi_read(struct mtd_info *
 		if (to_read > total_read)
 			to_read = total_read;
 
-		err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);
+		err = ubi_read(vol->gluebi_desc, lnum, buf, offs, to_read);
 		if (err)
 			break;
 
@@ -152,21 +179,19 @@ static int gluebi_read(struct mtd_info *
  * case of failure.
  */
 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
-		       size_t *retlen, const u_char *buf)
+			size_t *retlen, const u_char *buf)
 {
 	int err = 0, lnum, offs, total_written;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("write %zd bytes to offset %lld", len, to);
 
 	if (len < 0 || to < 0 || len + to > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
 	lnum = div_u64_rem(to, mtd->erasesize, &offs);
@@ -181,8 +206,7 @@ static int gluebi_write(struct mtd_info
 		if (to_write > total_written)
 			to_write = total_written;
 
-		err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,
-					UBI_UNKNOWN);
+		err = ubi_write(vol->gluebi_desc, lnum, buf, offs, to_write);
 		if (err)
 			break;
 
@@ -207,8 +231,7 @@ static int gluebi_write(struct mtd_info
 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	int err, i, lnum, count;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
+	struct ubi_gluebi_volume *vol;
 
 	dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
 		 (unsigned long long)instr->addr);
@@ -225,23 +248,24 @@ static int gluebi_erase(struct mtd_info
 	lnum = mtd_div_by_eb(instr->addr, mtd);
 	count = mtd_div_by_eb(instr->len, mtd);
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	vol = container_of(mtd, struct ubi_gluebi_volume, gluebi_mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
-	for (i = 0; i < count; i++) {
-		err = ubi_eba_unmap_leb(ubi, vol, lnum + i);
+	for (i = 0; i < count - 1; i++) {
+		err = ubi_leb_unmap(vol->gluebi_desc, lnum + i);
 		if (err)
 			goto out_err;
 	}
-
 	/*
 	 * MTD erase operations are synchronous, so we have to make sure the
 	 * physical eraseblock is wiped out.
+	 *
+	 * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
+	 * will wait for the end of operations
 	 */
-	err = ubi_wl_flush(ubi);
+	err = ubi_leb_erase(vol->gluebi_desc, lnum + i);
 	if (err)
 		goto out_err;
 
@@ -264,13 +288,28 @@ out_err:
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
+static int ubi_create_gluebi(struct ubi_device_info *ubi,
+			     struct ubi_volume_info *vol)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *v;
+	struct mtd_info *mtd;
+
+	v = kzalloc(sizeof(*v), GFP_KERNEL);
+	if (!v) {
+		ubi_err("Cannot allocate ubi_gluebi_vol");
+		return -ENOMEM;
+	}
+
+	mtd = &v->gluebi_mtd;
 
 	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
-	if (!mtd->name)
+	if (!mtd->name) {
+		ubi_err("Cannot allocate mtd->name");
+		kfree(v);
 		return -ENOMEM;
+	}
+
+	v->vol_id = vol->vol_id;
 
 	mtd->type = MTD_UBIVOLUME;
 	if (!ubi->ro_mode)
@@ -290,16 +329,21 @@ int ubi_create_gluebi(struct ubi_device
 	 * bytes.
 	 */
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
-		mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
+		mtd->size = (long long)vol->usable_leb_size * vol->size;
 	else
 		mtd->size = vol->used_bytes;
 
 	if (add_mtd_device(mtd)) {
-		ubi_err("cannot not add MTD device");
+		ubi_err("cannot add MTD device");
 		kfree(mtd->name);
+		kfree(v);
 		return -ENFILE;
 	}
 
+	spin_lock(&ubi_gluebi_lock);
+	list_add_tail(&v->list, &ubi_gluebi_mtds);
+	spin_unlock(&ubi_gluebi_lock);
+
 	dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
 		mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
 	return 0;
@@ -307,38 +351,103 @@ int ubi_create_gluebi(struct ubi_device
 
 /**
  * ubi_destroy_gluebi - close gluebi for an UBI volume.
- * @vol: volume description object
+ * @vi: volume info structure
  *
  * This function is called when an UBI volume is removed in order to remove
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_destroy_gluebi(struct ubi_volume *vol)
+static int ubi_destroy_gluebi(struct ubi_volume_info *vi)
 {
 	int err;
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *gluebi_vol;
+	struct mtd_info *mtd;
+
+	gluebi_vol = ubi_gluebi_find(vi->ubi_num, vi->vol_id);
+	if (!gluebi_vol)
+		return -ENOENT;
 
+	mtd = &gluebi_vol->gluebi_mtd;
 	dbg_gen("remove mtd%d", mtd->index);
 	err = del_mtd_device(mtd);
 	if (err)
 		return err;
 	kfree(mtd->name);
+
+	spin_lock(&ubi_gluebi_lock);
+	list_del(&gluebi_vol->list);
+	spin_unlock(&ubi_gluebi_lock);
+
+	kfree(gluebi_vol);
 	return 0;
 }
 
 /**
  * ubi_gluebi_updated - UBI volume was updated notifier.
- * @vol: volume description object
+ * @vi: volume info structure
  *
  * This function is called every time an UBI volume is updated. This function
  * does nothing if volume @vol is dynamic, and changes MTD device size if the
  * volume is static. This is needed because static volumes cannot be read past
  * data they contain.
  */
-void ubi_gluebi_updated(struct ubi_volume *vol)
+static void ubi_gluebi_updated(struct ubi_volume_info *vi)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_gluebi_volume *gluebi_vol;
 
-	if (vol->vol_type == UBI_STATIC_VOLUME)
-		mtd->size = vol->used_bytes;
+	gluebi_vol = ubi_gluebi_find(vi->ubi_num, vi->vol_id);
+	if (!gluebi_vol)
+		return /* -ENOENT */;
+
+	if (vi->vol_type == UBI_STATIC_VOLUME)
+		gluebi_vol->gluebi_mtd.size = vi->used_bytes;
+}
+
+/**
+ * ubi_gluebi_notify - notification handler.
+ * @nb: the registered notifier_block
+ * @l: notification type
+ * @ns_ptr: pointer to the &struct ubi_volume_notification
+ */
+static int ubi_gluebi_notify(struct notifier_block *nb,
+			     unsigned long l, void *ns_ptr)
+{
+	struct ubi_notification *ns = ns_ptr;
+
+	switch (l) {
+	case UBI_VOLUME_ADDED:
+		ubi_create_gluebi(&ns->di, &ns->vi);
+		break;
+	case UBI_VOLUME_REMOVED:
+		ubi_destroy_gluebi(&ns->vi);
+		break;
+	case UBI_VOLUME_RESIZED:
+		ubi_gluebi_updated(&ns->vi);
+		break;
+	case UBI_VOLUME_RENAMED:
+	case UBI_VOLUME_UPDATED:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ubi_gluebi_notifier = {
+	.notifier_call	= ubi_gluebi_notify,
+};
+
+static int __init ubi_gluebi_init(void)
+{
+	spin_lock_init(&ubi_gluebi_lock);
+	return ubi_register_volume_notifier(&ubi_gluebi_notifier, false);
 }
+
+static void __exit ubi_gluebi_exit(void)
+{
+	ubi_unregister_volume_notifier(&ubi_gluebi_notifier);
+}
+
+module_init(ubi_gluebi_init);
+module_exit(ubi_gluebi_exit);
+MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
+MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
+MODULE_LICENSE("GPL");

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

* Re: [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API)
  2009-05-31 14:32         ` [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API) dmitry pervushin
@ 2009-06-01 16:48           ` Artem Bityutskiy
  2009-06-01 17:07             ` dmitry pervushin
  0 siblings, 1 reply; 15+ messages in thread
From: Artem Bityutskiy @ 2009-06-01 16:48 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Sun, 2009-05-31 at 18:32 +0400, dmitry pervushin wrote:
> On Sun, 2009-05-31 at 16:52 +0300, Artem Bityutskiy wrote: 
> > On Fri, 2009-05-29 at 23:27 +0400, dmitry pervushin wrote:
> > > > I've also created an "experimental" branch in the ubi-2.6.git
> > > > tree for your convenience:
> > > > 
> > > > http://git.infradead.org/ubi-2.6.git?a=shortlog;h=refs/heads/experimental
> > > > git://git.infradead.org/ubi-2.6.git experimental
> > > Sorry for late response; I reviewed your changes, and although
> > > prohibiting of using ubi api from within notifiers does not look very
> > > amazing to me... but it seems that it is the only robust way. The 3rd
> > > patch from the serie is inlined below (tested on the stmp378x board as
> > > well as on nandsim)
> > > 
> > > The standalone gluebi support that uses UBI notifications.
> > > 
> > > Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
> > 
> > Just applied this to
> > git://git.infradead.org/ubi-2.6.git experimental
> > 
> > and got:
> > 
> Oh, shame on me. I attached the patch with the same name from the wrong
> directory; below is the correct one.
> 
> Signed-off-by: dmitry pervushin <dpervushin@embeddedalley.com>
> 

I've re-worked your patch. I make it release resources when the module
is unloaded, made it do proper module referencing, made it really
independent on UBI, tested it with the UBI test-suite which can be
found in ubi-2.6.git/tests/ubi-tests, re-named most of the 
funcs/variables to get rid of the "ubi" word and make names consistent.

Patch is below as well as at the same "experimental" branch. If you
are OK with this, I'll push it forward.

>From 855ef5c35df22a056fd6f76f0785726a64a664fa Mon Sep 17 00:00:00 2001
From: Dmitry Pervushin <dpervushin@embeddedalley.com>
Date: Sun, 31 May 2009 18:32:59 +0400
Subject: [PATCH] UBI: make gluebi a separate module

Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 drivers/mtd/ubi/Kconfig  |   13 +-
 drivers/mtd/ubi/Makefile |    2 +-
 drivers/mtd/ubi/gluebi.c |  375 +++++++++++++++++++++++++++++++++++-----------
 3 files changed, 292 insertions(+), 98 deletions(-)

diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 3f06310..b1cd7a1 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -49,15 +49,16 @@ config MTD_UBI_BEB_RESERVE
 	  reserved. Leave the default value if unsure.
 
 config MTD_UBI_GLUEBI
-	bool "Emulate MTD devices"
+	tristate "MTD devices emulation driver (gluebi)"
 	default n
 	depends on MTD_UBI
 	help
-	   This option enables MTD devices emulation on top of UBI volumes: for
-	   each UBI volumes an MTD device is created, and all I/O to this MTD
-	   device is redirected to the UBI volume. This is handy to make
-	   MTD-oriented software (like JFFS2) work on top of UBI. Do not enable
-	   this if no legacy software will be used.
+	   This option enables gluebi - an additional driver which emulates MTD
+	   devices on top of UBI volumes: for each UBI volumes an MTD device is
+	   created, and all I/O to this MTD device is redirected to the UBI
+	   volume. This is handy to make MTD-oriented software (like JFFS2)
+	   work on top of UBI. Do not enable this unless you use legacy
+	   software.
 
 source "drivers/mtd/ubi/Kconfig.debug"
 endmenu
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index dd834e0..c9302a5 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
 ubi-y += misc.o
 
 ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
-ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 49cd55a..fa61a3a 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -19,17 +19,68 @@
  */
 
 /*
- * This file includes implementation of fake MTD devices for each UBI volume.
- * This sounds strange, but it is in fact quite useful to make MTD-oriented
- * software (including all the legacy software) to work on top of UBI.
+ * This is a small driver which implements fake MTD devices on top of UBI
+ * volumes. This sounds strange, but it is in fact quite useful to make
+ * MTD-oriented software (including all the legacy software) work on top of
+ * UBI.
  *
  * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
- * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The
+ * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The
  * eraseblock size is equivalent to the logical eraseblock size of the volume.
  */
 
+#include <linux/sched.h>
 #include <linux/math64.h>
-#include "ubi.h"
+#include <linux/module.h>
+#include <linux/mtd/ubi.h>
+#include <linux/mtd/mtd.h>
+#include "ubi-media.h"
+
+#define err_msg(fmt, ...)                                   \
+	printk(KERN_DEBUG "gluebi (pid %d): %s: " fmt "\n", \
+	       current->pid, __func__, ##__VA_ARGS__)
+
+/**
+ * struct gluebi_device - a gluebi device description data structure.
+ * @mtd: emulated MTD device description object
+ * @refcnt: gluebi device reference count
+ * @desc: UBI volume descriptor
+ * @ubi_num: UBI device number this gluebi device works on
+ * @vol_id: ID of UBI volume this gluebi device works on
+ * @list: link in a list of gluebi devices
+ */
+struct gluebi_device {
+	struct mtd_info mtd;
+	int refcnt;
+	struct ubi_volume_desc *desc;
+	int ubi_num;
+	int vol_id;
+	struct list_head list;
+};
+
+/* List of all gluebi devices */
+static LIST_HEAD(gluebi_devices);
+static DEFINE_MUTEX(devices_mutex);
+
+/**
+ * find_gluebi_nolock - find a gluebi device.
+ * @ubi_num: UBI device number
+ * @vol_id: volume ID
+ *
+ * This function seraches for gluebi device corresponding to UBI device
+ * @ubi_num and UBI volume @vol_id. Returns the gluebi device description
+ * object in case of success and %NULL in case of failure. The caller has to
+ * have the &devices_mutex locked.
+ */
+static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id)
+{
+	struct gluebi_device *gluebi;
+
+	list_for_each_entry(gluebi, &gluebi_devices, list)
+		if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id)
+			return gluebi;
+	return NULL;
+}
 
 /**
  * gluebi_get_device - get MTD device reference.
@@ -41,15 +92,18 @@
  */
 static int gluebi_get_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
+	struct gluebi_device *gluebi;
+	int ubi_mode = UBI_READONLY;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
 
-	/*
-	 * We do not introduce locks for gluebi reference count because the
-	 * get_device()/put_device() calls are already serialized at MTD.
-	 */
-	if (vol->gluebi_refcount > 0) {
+	if (mtd->flags & MTD_WRITEABLE)
+		ubi_mode = UBI_READWRITE;
+
+	gluebi = container_of(mtd, struct gluebi_device, mtd);
+	mutex_lock(&devices_mutex);
+	if (gluebi->refcnt > 0) {
 		/*
 		 * The MTD device is already referenced and this is just one
 		 * more reference. MTD allows many users to open the same
@@ -58,7 +112,8 @@ static int gluebi_get_device(struct mtd_info *mtd)
 		 * open the UBI volume again - just increase the reference
 		 * counter and return.
 		 */
-		vol->gluebi_refcount += 1;
+		gluebi->refcnt += 1;
+		mutex_unlock(&devices_mutex);
 		return 0;
 	}
 
@@ -66,11 +121,15 @@ static int gluebi_get_device(struct mtd_info *mtd)
 	 * This is the first reference to this UBI volume via the MTD device
 	 * interface. Open the corresponding volume in read-write mode.
 	 */
-	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
-					   UBI_READWRITE);
-	if (IS_ERR(vol->gluebi_desc))
-		return PTR_ERR(vol->gluebi_desc);
-	vol->gluebi_refcount += 1;
+	gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id,
+				       ubi_mode);
+	if (IS_ERR(gluebi->desc)) {
+		mutex_unlock(&devices_mutex);
+		module_put(THIS_MODULE);
+		return PTR_ERR(gluebi->desc);
+	}
+	gluebi->refcnt += 1;
+	mutex_unlock(&devices_mutex);
 	return 0;
 }
 
@@ -83,13 +142,15 @@ static int gluebi_get_device(struct mtd_info *mtd)
  */
 static void gluebi_put_device(struct mtd_info *mtd)
 {
-	struct ubi_volume *vol;
-
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	vol->gluebi_refcount -= 1;
-	ubi_assert(vol->gluebi_refcount >= 0);
-	if (vol->gluebi_refcount == 0)
-		ubi_close_volume(vol->gluebi_desc);
+	struct gluebi_device *gluebi;
+
+	gluebi = container_of(mtd, struct gluebi_device, mtd);
+	mutex_lock(&devices_mutex);
+	gluebi->refcnt -= 1;
+	if (gluebi->refcnt == 0)
+		ubi_close_volume(gluebi->desc);
+	module_put(THIS_MODULE);
+	mutex_unlock(&devices_mutex);
 }
 
 /**
@@ -107,16 +168,12 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
 		       size_t *retlen, unsigned char *buf)
 {
 	int err = 0, lnum, offs, total_read;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
-
-	dbg_gen("read %zd bytes from offset %lld", len, from);
+	struct gluebi_device *gluebi;
 
 	if (len < 0 || from < 0 || from + len > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	gluebi = container_of(mtd, struct gluebi_device, mtd);
 
 	lnum = div_u64_rem(from, mtd->erasesize, &offs);
 	total_read = len;
@@ -126,7 +183,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
 		if (to_read > total_read)
 			to_read = total_read;
 
-		err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);
+		err = ubi_read(gluebi->desc, lnum, buf, offs, to_read);
 		if (err)
 			break;
 
@@ -152,21 +209,17 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
  * case of failure.
  */
 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
-		       size_t *retlen, const u_char *buf)
+			size_t *retlen, const u_char *buf)
 {
 	int err = 0, lnum, offs, total_written;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
-
-	dbg_gen("write %zd bytes to offset %lld", len, to);
+	struct gluebi_device *gluebi;
 
 	if (len < 0 || to < 0 || len + to > mtd->size)
 		return -EINVAL;
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	gluebi = container_of(mtd, struct gluebi_device, mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
 	lnum = div_u64_rem(to, mtd->erasesize, &offs);
@@ -181,8 +234,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
 		if (to_write > total_written)
 			to_write = total_written;
 
-		err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,
-					UBI_UNKNOWN);
+		err = ubi_write(gluebi->desc, lnum, buf, offs, to_write);
 		if (err)
 			break;
 
@@ -207,41 +259,36 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
 static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	int err, i, lnum, count;
-	struct ubi_volume *vol;
-	struct ubi_device *ubi;
-
-	dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
-		 (unsigned long long)instr->addr);
+	struct gluebi_device *gluebi;
 
 	if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
 		return -EINVAL;
-
 	if (instr->len < 0 || instr->addr + instr->len > mtd->size)
 		return -EINVAL;
-
 	if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
 		return -EINVAL;
 
 	lnum = mtd_div_by_eb(instr->addr, mtd);
 	count = mtd_div_by_eb(instr->len, mtd);
 
-	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
-	ubi = vol->ubi;
+	gluebi = container_of(mtd, struct gluebi_device, mtd);
 
-	if (ubi->ro_mode)
+	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
 
-	for (i = 0; i < count; i++) {
-		err = ubi_eba_unmap_leb(ubi, vol, lnum + i);
+	for (i = 0; i < count - 1; i++) {
+		err = ubi_leb_unmap(gluebi->desc, lnum + i);
 		if (err)
 			goto out_err;
 	}
-
 	/*
 	 * MTD erase operations are synchronous, so we have to make sure the
 	 * physical eraseblock is wiped out.
+	 *
+	 * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
+	 * will wait for the end of operations
 	 */
-	err = ubi_wl_flush(ubi);
+	err = ubi_leb_erase(gluebi->desc, lnum + i);
 	if (err)
 		goto out_err;
 
@@ -256,28 +303,38 @@ out_err:
 }
 
 /**
- * ubi_create_gluebi - initialize gluebi for an UBI volume.
- * @ubi: UBI device description object
- * @vol: volume description object
+ * gluebi_create - create a gluebi device for an UBI volume.
+ * @di: UBI device description object
+ * @vi: UBI volume description object
  *
- * This function is called when an UBI volume is created in order to create
+ * This function is called when a new UBI volume is created in order to create
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
+static int gluebi_create(struct ubi_device_info *di,
+			 struct ubi_volume_info *vi)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct gluebi_device *gluebi, *g;
+	struct mtd_info *mtd;
 
-	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
-	if (!mtd->name)
+	gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL);
+	if (!gluebi)
 		return -ENOMEM;
 
+	mtd = &gluebi->mtd;
+	mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL);
+	if (!mtd->name) {
+		kfree(gluebi);
+		return -ENOMEM;
+	}
+
+	gluebi->vol_id = vi->vol_id;
 	mtd->type = MTD_UBIVOLUME;
-	if (!ubi->ro_mode)
+	if (!di->ro_mode)
 		mtd->flags = MTD_WRITEABLE;
-	mtd->writesize  = ubi->min_io_size;
 	mtd->owner      = THIS_MODULE;
-	mtd->erasesize  = vol->usable_leb_size;
+	mtd->writesize  = di->min_io_size;
+	mtd->erasesize  = vi->usable_leb_size;
 	mtd->read       = gluebi_read;
 	mtd->write      = gluebi_write;
 	mtd->erase      = gluebi_erase;
@@ -285,60 +342,196 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
 	mtd->put_device = gluebi_put_device;
 
 	/*
-	 * In case of dynamic volume, MTD device size is just volume size. In
+	 * In case of dynamic a volume, MTD device size is just volume size. In
 	 * case of a static volume the size is equivalent to the amount of data
 	 * bytes.
 	 */
-	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
-		mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
+	if (vi->vol_type == UBI_DYNAMIC_VOLUME)
+		mtd->size = (unsigned long long)vi->usable_leb_size * vi->size;
 	else
-		mtd->size = vol->used_bytes;
+		mtd->size = vi->used_bytes;
+
+	/* Just a sanity check - make sure this gluebi device does not exist */
+	mutex_lock(&devices_mutex);
+	g = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
+	if (g)
+		err_msg("gluebi MTD device %d form UBI device %d volume %d "
+			"already exists", g->mtd.index, vi->ubi_num,
+			vi->vol_id);
+	mutex_unlock(&devices_mutex);
 
 	if (add_mtd_device(mtd)) {
-		ubi_err("cannot not add MTD device");
+		err_msg("cannot add MTD device");
 		kfree(mtd->name);
+		kfree(gluebi);
 		return -ENFILE;
 	}
 
-	dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
-		mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
+	mutex_lock(&devices_mutex);
+	list_add_tail(&gluebi->list, &gluebi_devices);
+	mutex_unlock(&devices_mutex);
 	return 0;
 }
 
 /**
- * ubi_destroy_gluebi - close gluebi for an UBI volume.
- * @vol: volume description object
+ * gluebi_remove - remove a gluebi device.
+ * @vi: UBI volume description object
  *
- * This function is called when an UBI volume is removed in order to remove
+ * This function is called when an UBI volume is removed and it removes
  * corresponding fake MTD device. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_destroy_gluebi(struct ubi_volume *vol)
+static int gluebi_remove(struct ubi_volume_info *vi)
 {
-	int err;
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	int err = 0;
+	struct mtd_info *mtd;
+	struct gluebi_device *gluebi;
+
+	mutex_lock(&devices_mutex);
+	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
+	if (!gluebi) {
+		err_msg("got remove notification for unknown UBI device %d "
+			"volume %d", vi->ubi_num, vi->vol_id);
+		err = -ENOENT;
+	} else if (gluebi->refcnt)
+		err = -EBUSY;
+	else
+		list_del(&gluebi->list);
+	mutex_unlock(&devices_mutex);
+	if (err)
+		return err;
 
-	dbg_gen("remove mtd%d", mtd->index);
+	mtd = &gluebi->mtd;
 	err = del_mtd_device(mtd);
-	if (err)
+	if (err) {
+		err_msg("cannot remove fake MTD device %d, UBI device %d, "
+			"volume %d, error %d", mtd->index, gluebi->ubi_num,
+			gluebi->vol_id, err);
+		mutex_lock(&devices_mutex);
+		list_add_tail(&gluebi->list, &gluebi_devices);
+		mutex_unlock(&devices_mutex);
 		return err;
+	}
+
 	kfree(mtd->name);
+	kfree(gluebi);
 	return 0;
 }
 
 /**
- * ubi_gluebi_updated - UBI volume was updated notifier.
- * @vol: volume description object
+ * gluebi_updated - UBI volume was updated notifier.
+ * @vi: volume info structure
  *
- * This function is called every time an UBI volume is updated. This function
- * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * This function is called every time an UBI volume is updated. It does nothing
+ * if te volume @vol is dynamic, and changes MTD device size if the
  * volume is static. This is needed because static volumes cannot be read past
- * data they contain.
+ * data they contain. This function returns zero in case of success and a
+ * negative error code in case of error.
+ */
+static int gluebi_updated(struct ubi_volume_info *vi)
+{
+	struct gluebi_device *gluebi;
+
+	mutex_lock(&devices_mutex);
+	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
+	if (!gluebi) {
+		mutex_unlock(&devices_mutex);
+		err_msg("got update notification for unknown UBI device %d "
+			"volume %d", vi->ubi_num, vi->vol_id);
+		return -ENOENT;
+	}
+
+	if (vi->vol_type == UBI_STATIC_VOLUME)
+		gluebi->mtd.size = vi->used_bytes;
+	mutex_unlock(&devices_mutex);
+	return 0;
+}
+
+/**
+ * gluebi_resized - UBI volume was re-sized notifier.
+ * @vi: volume info structure
+ *
+ * This function is called every time an UBI volume is re-size. It changes the
+ * corresponding fake MTD device size. This function returns zero in case of
+ * success and a negative error code in case of error.
+ */
+static int gluebi_resized(struct ubi_volume_info *vi)
+{
+	struct gluebi_device *gluebi;
+
+	mutex_lock(&devices_mutex);
+	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
+	if (!gluebi) {
+		mutex_unlock(&devices_mutex);
+		err_msg("got update notification for unknown UBI device %d "
+			"volume %d", vi->ubi_num, vi->vol_id);
+		return -ENOENT;
+	}
+	gluebi->mtd.size = vi->used_bytes;
+	mutex_unlock(&devices_mutex);
+	return 0;
+}
+
+/**
+ * gluebi_notify - UBI notification handler.
+ * @nb: registered notifier block
+ * @l: notification type
+ * @ptr: pointer to the &struct ubi_notification object
  */
-void ubi_gluebi_updated(struct ubi_volume *vol)
+static int gluebi_notify(struct notifier_block *nb, unsigned long l,
+			 void *ns_ptr)
 {
-	struct mtd_info *mtd = &vol->gluebi_mtd;
+	struct ubi_notification *nt = ns_ptr;
+
+	switch (l) {
+	case UBI_VOLUME_ADDED:
+		gluebi_create(&nt->di, &nt->vi);
+		break;
+	case UBI_VOLUME_REMOVED:
+		gluebi_remove(&nt->vi);
+		break;
+	case UBI_VOLUME_RESIZED:
+		gluebi_resized(&nt->vi);
+		break;
+	case UBI_VOLUME_UPDATED:
+		gluebi_updated(&nt->vi);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
 
-	if (vol->vol_type == UBI_STATIC_VOLUME)
-		mtd->size = vol->used_bytes;
+static struct notifier_block gluebi_notifier = {
+	.notifier_call	= gluebi_notify,
+};
+
+static int __init ubi_gluebi_init(void)
+{
+	return ubi_register_volume_notifier(&gluebi_notifier, 0);
 }
+
+static void __exit ubi_gluebi_exit(void)
+{
+	struct gluebi_device *gluebi, *g;
+
+	list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) {
+		int err;
+		struct mtd_info *mtd = &gluebi->mtd;
+
+		err = del_mtd_device(mtd);
+		if (err)
+			err_msg("error %d while removing gluebi MTD device %d, "
+				"UBI device %d, volume %d - ignoring", err,
+				mtd->index, gluebi->ubi_num, gluebi->vol_id);
+		kfree(mtd->name);
+		kfree(gluebi);
+	}
+	ubi_unregister_volume_notifier(&gluebi_notifier);
+}
+
+module_init(ubi_gluebi_init);
+module_exit(ubi_gluebi_exit);
+MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
+MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
+MODULE_LICENSE("GPL");
-- 
1.6.0.6

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

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

* Re: [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API)
  2009-06-01 16:48           ` Artem Bityutskiy
@ 2009-06-01 17:07             ` dmitry pervushin
  2009-06-02  6:40               ` Artem Bityutskiy
  0 siblings, 1 reply; 15+ messages in thread
From: dmitry pervushin @ 2009-06-01 17:07 UTC (permalink / raw)
  To: dedekind; +Cc: linux-mtd

Hello Artem,

Thanks for paying attention on this; the patch looks ok for me.

> I've re-worked your patch. I make it release resources when the module
> is unloaded, made it do proper module referencing, made it really
> independent on UBI, tested it with the UBI test-suite which can be
> found in ubi-2.6.git/tests/ubi-tests, re-named most of the 
> funcs/variables to get rid of the "ubi" word and make names consistent.
> 
> Patch is below as well as at the same "experimental" branch. If you
> are OK with this, I'll push it forward.
> 
> >From 855ef5c35df22a056fd6f76f0785726a64a664fa Mon Sep 17 00:00:00 2001
> From: Dmitry Pervushin <dpervushin@embeddedalley.com>
> Date: Sun, 31 May 2009 18:32:59 +0400
> Subject: [PATCH] UBI: make gluebi a separate module
> 
> Signed-off-by: Dmitry Pervushin <dpervushin@embeddedalley.com>
> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
> ---
>  drivers/mtd/ubi/Kconfig  |   13 +-
>  drivers/mtd/ubi/Makefile |    2 +-
>  drivers/mtd/ubi/gluebi.c |  375 +++++++++++++++++++++++++++++++++++-----------
>  3 files changed, 292 insertions(+), 98 deletions(-)
> 
> diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
> index 3f06310..b1cd7a1 100644
> --- a/drivers/mtd/ubi/Kconfig
> +++ b/drivers/mtd/ubi/Kconfig
> @@ -49,15 +49,16 @@ config MTD_UBI_BEB_RESERVE
>  	  reserved. Leave the default value if unsure.
>  
>  config MTD_UBI_GLUEBI
> -	bool "Emulate MTD devices"
> +	tristate "MTD devices emulation driver (gluebi)"
>  	default n
>  	depends on MTD_UBI
>  	help
> -	   This option enables MTD devices emulation on top of UBI volumes: for
> -	   each UBI volumes an MTD device is created, and all I/O to this MTD
> -	   device is redirected to the UBI volume. This is handy to make
> -	   MTD-oriented software (like JFFS2) work on top of UBI. Do not enable
> -	   this if no legacy software will be used.
> +	   This option enables gluebi - an additional driver which emulates MTD
> +	   devices on top of UBI volumes: for each UBI volumes an MTD device is
> +	   created, and all I/O to this MTD device is redirected to the UBI
> +	   volume. This is handy to make MTD-oriented software (like JFFS2)
> +	   work on top of UBI. Do not enable this unless you use legacy
> +	   software.
>  
>  source "drivers/mtd/ubi/Kconfig.debug"
>  endmenu
> diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
> index dd834e0..c9302a5 100644
> --- a/drivers/mtd/ubi/Makefile
> +++ b/drivers/mtd/ubi/Makefile
> @@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
>  ubi-y += misc.o
>  
>  ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
> -ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
> +obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
> diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
> index 49cd55a..fa61a3a 100644
> --- a/drivers/mtd/ubi/gluebi.c
> +++ b/drivers/mtd/ubi/gluebi.c
> @@ -19,17 +19,68 @@
>   */
>  
>  /*
> - * This file includes implementation of fake MTD devices for each UBI volume.
> - * This sounds strange, but it is in fact quite useful to make MTD-oriented
> - * software (including all the legacy software) to work on top of UBI.
> + * This is a small driver which implements fake MTD devices on top of UBI
> + * volumes. This sounds strange, but it is in fact quite useful to make
> + * MTD-oriented software (including all the legacy software) work on top of
> + * UBI.
>   *
>   * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
> - * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The
> + * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The
>   * eraseblock size is equivalent to the logical eraseblock size of the volume.
>   */
>  
> +#include <linux/sched.h>
>  #include <linux/math64.h>
> -#include "ubi.h"
> +#include <linux/module.h>
> +#include <linux/mtd/ubi.h>
> +#include <linux/mtd/mtd.h>
> +#include "ubi-media.h"
> +
> +#define err_msg(fmt, ...)                                   \
> +	printk(KERN_DEBUG "gluebi (pid %d): %s: " fmt "\n", \
> +	       current->pid, __func__, ##__VA_ARGS__)
> +
> +/**
> + * struct gluebi_device - a gluebi device description data structure.
> + * @mtd: emulated MTD device description object
> + * @refcnt: gluebi device reference count
> + * @desc: UBI volume descriptor
> + * @ubi_num: UBI device number this gluebi device works on
> + * @vol_id: ID of UBI volume this gluebi device works on
> + * @list: link in a list of gluebi devices
> + */
> +struct gluebi_device {
> +	struct mtd_info mtd;
> +	int refcnt;
> +	struct ubi_volume_desc *desc;
> +	int ubi_num;
> +	int vol_id;
> +	struct list_head list;
> +};
> +
> +/* List of all gluebi devices */
> +static LIST_HEAD(gluebi_devices);
> +static DEFINE_MUTEX(devices_mutex);
> +
> +/**
> + * find_gluebi_nolock - find a gluebi device.
> + * @ubi_num: UBI device number
> + * @vol_id: volume ID
> + *
> + * This function seraches for gluebi device corresponding to UBI device
> + * @ubi_num and UBI volume @vol_id. Returns the gluebi device description
> + * object in case of success and %NULL in case of failure. The caller has to
> + * have the &devices_mutex locked.
> + */
> +static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id)
> +{
> +	struct gluebi_device *gluebi;
> +
> +	list_for_each_entry(gluebi, &gluebi_devices, list)
> +		if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id)
> +			return gluebi;
> +	return NULL;
> +}
>  
>  /**
>   * gluebi_get_device - get MTD device reference.
> @@ -41,15 +92,18 @@
>   */
>  static int gluebi_get_device(struct mtd_info *mtd)
>  {
> -	struct ubi_volume *vol;
> +	struct gluebi_device *gluebi;
> +	int ubi_mode = UBI_READONLY;
>  
> -	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
> +	if (!try_module_get(THIS_MODULE))
> +		return -ENODEV;
>  
> -	/*
> -	 * We do not introduce locks for gluebi reference count because the
> -	 * get_device()/put_device() calls are already serialized at MTD.
> -	 */
> -	if (vol->gluebi_refcount > 0) {
> +	if (mtd->flags & MTD_WRITEABLE)
> +		ubi_mode = UBI_READWRITE;
> +
> +	gluebi = container_of(mtd, struct gluebi_device, mtd);
> +	mutex_lock(&devices_mutex);
> +	if (gluebi->refcnt > 0) {
>  		/*
>  		 * The MTD device is already referenced and this is just one
>  		 * more reference. MTD allows many users to open the same
> @@ -58,7 +112,8 @@ static int gluebi_get_device(struct mtd_info *mtd)
>  		 * open the UBI volume again - just increase the reference
>  		 * counter and return.
>  		 */
> -		vol->gluebi_refcount += 1;
> +		gluebi->refcnt += 1;
> +		mutex_unlock(&devices_mutex);
>  		return 0;
>  	}
>  
> @@ -66,11 +121,15 @@ static int gluebi_get_device(struct mtd_info *mtd)
>  	 * This is the first reference to this UBI volume via the MTD device
>  	 * interface. Open the corresponding volume in read-write mode.
>  	 */
> -	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
> -					   UBI_READWRITE);
> -	if (IS_ERR(vol->gluebi_desc))
> -		return PTR_ERR(vol->gluebi_desc);
> -	vol->gluebi_refcount += 1;
> +	gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id,
> +				       ubi_mode);
> +	if (IS_ERR(gluebi->desc)) {
> +		mutex_unlock(&devices_mutex);
> +		module_put(THIS_MODULE);
> +		return PTR_ERR(gluebi->desc);
> +	}
> +	gluebi->refcnt += 1;
> +	mutex_unlock(&devices_mutex);
>  	return 0;
>  }
>  
> @@ -83,13 +142,15 @@ static int gluebi_get_device(struct mtd_info *mtd)
>   */
>  static void gluebi_put_device(struct mtd_info *mtd)
>  {
> -	struct ubi_volume *vol;
> -
> -	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
> -	vol->gluebi_refcount -= 1;
> -	ubi_assert(vol->gluebi_refcount >= 0);
> -	if (vol->gluebi_refcount == 0)
> -		ubi_close_volume(vol->gluebi_desc);
> +	struct gluebi_device *gluebi;
> +
> +	gluebi = container_of(mtd, struct gluebi_device, mtd);
> +	mutex_lock(&devices_mutex);
> +	gluebi->refcnt -= 1;
> +	if (gluebi->refcnt == 0)
> +		ubi_close_volume(gluebi->desc);
> +	module_put(THIS_MODULE);
> +	mutex_unlock(&devices_mutex);
>  }
>  
>  /**
> @@ -107,16 +168,12 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
>  		       size_t *retlen, unsigned char *buf)
>  {
>  	int err = 0, lnum, offs, total_read;
> -	struct ubi_volume *vol;
> -	struct ubi_device *ubi;
> -
> -	dbg_gen("read %zd bytes from offset %lld", len, from);
> +	struct gluebi_device *gluebi;
>  
>  	if (len < 0 || from < 0 || from + len > mtd->size)
>  		return -EINVAL;
>  
> -	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
> -	ubi = vol->ubi;
> +	gluebi = container_of(mtd, struct gluebi_device, mtd);
>  
>  	lnum = div_u64_rem(from, mtd->erasesize, &offs);
>  	total_read = len;
> @@ -126,7 +183,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
>  		if (to_read > total_read)
>  			to_read = total_read;
>  
> -		err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0);
> +		err = ubi_read(gluebi->desc, lnum, buf, offs, to_read);
>  		if (err)
>  			break;
>  
> @@ -152,21 +209,17 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
>   * case of failure.
>   */
>  static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
> -		       size_t *retlen, const u_char *buf)
> +			size_t *retlen, const u_char *buf)
>  {
>  	int err = 0, lnum, offs, total_written;
> -	struct ubi_volume *vol;
> -	struct ubi_device *ubi;
> -
> -	dbg_gen("write %zd bytes to offset %lld", len, to);
> +	struct gluebi_device *gluebi;
>  
>  	if (len < 0 || to < 0 || len + to > mtd->size)
>  		return -EINVAL;
>  
> -	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
> -	ubi = vol->ubi;
> +	gluebi = container_of(mtd, struct gluebi_device, mtd);
>  
> -	if (ubi->ro_mode)
> +	if (!(mtd->flags & MTD_WRITEABLE))
>  		return -EROFS;
>  
>  	lnum = div_u64_rem(to, mtd->erasesize, &offs);
> @@ -181,8 +234,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
>  		if (to_write > total_written)
>  			to_write = total_written;
>  
> -		err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write,
> -					UBI_UNKNOWN);
> +		err = ubi_write(gluebi->desc, lnum, buf, offs, to_write);
>  		if (err)
>  			break;
>  
> @@ -207,41 +259,36 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
>  static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
>  {
>  	int err, i, lnum, count;
> -	struct ubi_volume *vol;
> -	struct ubi_device *ubi;
> -
> -	dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
> -		 (unsigned long long)instr->addr);
> +	struct gluebi_device *gluebi;
>  
>  	if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
>  		return -EINVAL;
> -
>  	if (instr->len < 0 || instr->addr + instr->len > mtd->size)
>  		return -EINVAL;
> -
>  	if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
>  		return -EINVAL;
>  
>  	lnum = mtd_div_by_eb(instr->addr, mtd);
>  	count = mtd_div_by_eb(instr->len, mtd);
>  
> -	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
> -	ubi = vol->ubi;
> +	gluebi = container_of(mtd, struct gluebi_device, mtd);
>  
> -	if (ubi->ro_mode)
> +	if (!(mtd->flags & MTD_WRITEABLE))
>  		return -EROFS;
>  
> -	for (i = 0; i < count; i++) {
> -		err = ubi_eba_unmap_leb(ubi, vol, lnum + i);
> +	for (i = 0; i < count - 1; i++) {
> +		err = ubi_leb_unmap(gluebi->desc, lnum + i);
>  		if (err)
>  			goto out_err;
>  	}
> -
>  	/*
>  	 * MTD erase operations are synchronous, so we have to make sure the
>  	 * physical eraseblock is wiped out.
> +	 *
> +	 * Thus, perform leb_erase instead of leb_unmap operation - leb_erase
> +	 * will wait for the end of operations
>  	 */
> -	err = ubi_wl_flush(ubi);
> +	err = ubi_leb_erase(gluebi->desc, lnum + i);
>  	if (err)
>  		goto out_err;
>  
> @@ -256,28 +303,38 @@ out_err:
>  }
>  
>  /**
> - * ubi_create_gluebi - initialize gluebi for an UBI volume.
> - * @ubi: UBI device description object
> - * @vol: volume description object
> + * gluebi_create - create a gluebi device for an UBI volume.
> + * @di: UBI device description object
> + * @vi: UBI volume description object
>   *
> - * This function is called when an UBI volume is created in order to create
> + * This function is called when a new UBI volume is created in order to create
>   * corresponding fake MTD device. Returns zero in case of success and a
>   * negative error code in case of failure.
>   */
> -int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
> +static int gluebi_create(struct ubi_device_info *di,
> +			 struct ubi_volume_info *vi)
>  {
> -	struct mtd_info *mtd = &vol->gluebi_mtd;
> +	struct gluebi_device *gluebi, *g;
> +	struct mtd_info *mtd;
>  
> -	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
> -	if (!mtd->name)
> +	gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL);
> +	if (!gluebi)
>  		return -ENOMEM;
>  
> +	mtd = &gluebi->mtd;
> +	mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL);
> +	if (!mtd->name) {
> +		kfree(gluebi);
> +		return -ENOMEM;
> +	}
> +
> +	gluebi->vol_id = vi->vol_id;
>  	mtd->type = MTD_UBIVOLUME;
> -	if (!ubi->ro_mode)
> +	if (!di->ro_mode)
>  		mtd->flags = MTD_WRITEABLE;
> -	mtd->writesize  = ubi->min_io_size;
>  	mtd->owner      = THIS_MODULE;
> -	mtd->erasesize  = vol->usable_leb_size;
> +	mtd->writesize  = di->min_io_size;
> +	mtd->erasesize  = vi->usable_leb_size;
>  	mtd->read       = gluebi_read;
>  	mtd->write      = gluebi_write;
>  	mtd->erase      = gluebi_erase;
> @@ -285,60 +342,196 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
>  	mtd->put_device = gluebi_put_device;
>  
>  	/*
> -	 * In case of dynamic volume, MTD device size is just volume size. In
> +	 * In case of dynamic a volume, MTD device size is just volume size. In
>  	 * case of a static volume the size is equivalent to the amount of data
>  	 * bytes.
>  	 */
> -	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
> -		mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
> +	if (vi->vol_type == UBI_DYNAMIC_VOLUME)
> +		mtd->size = (unsigned long long)vi->usable_leb_size * vi->size;
>  	else
> -		mtd->size = vol->used_bytes;
> +		mtd->size = vi->used_bytes;
> +
> +	/* Just a sanity check - make sure this gluebi device does not exist */
> +	mutex_lock(&devices_mutex);
> +	g = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
> +	if (g)
> +		err_msg("gluebi MTD device %d form UBI device %d volume %d "
> +			"already exists", g->mtd.index, vi->ubi_num,
> +			vi->vol_id);
> +	mutex_unlock(&devices_mutex);
>  
>  	if (add_mtd_device(mtd)) {
> -		ubi_err("cannot not add MTD device");
> +		err_msg("cannot add MTD device");
>  		kfree(mtd->name);
> +		kfree(gluebi);
>  		return -ENFILE;
>  	}
>  
> -	dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
> -		mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
> +	mutex_lock(&devices_mutex);
> +	list_add_tail(&gluebi->list, &gluebi_devices);
> +	mutex_unlock(&devices_mutex);
>  	return 0;
>  }
>  
>  /**
> - * ubi_destroy_gluebi - close gluebi for an UBI volume.
> - * @vol: volume description object
> + * gluebi_remove - remove a gluebi device.
> + * @vi: UBI volume description object
>   *
> - * This function is called when an UBI volume is removed in order to remove
> + * This function is called when an UBI volume is removed and it removes
>   * corresponding fake MTD device. Returns zero in case of success and a
>   * negative error code in case of failure.
>   */
> -int ubi_destroy_gluebi(struct ubi_volume *vol)
> +static int gluebi_remove(struct ubi_volume_info *vi)
>  {
> -	int err;
> -	struct mtd_info *mtd = &vol->gluebi_mtd;
> +	int err = 0;
> +	struct mtd_info *mtd;
> +	struct gluebi_device *gluebi;
> +
> +	mutex_lock(&devices_mutex);
> +	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
> +	if (!gluebi) {
> +		err_msg("got remove notification for unknown UBI device %d "
> +			"volume %d", vi->ubi_num, vi->vol_id);
> +		err = -ENOENT;
> +	} else if (gluebi->refcnt)
> +		err = -EBUSY;
> +	else
> +		list_del(&gluebi->list);
> +	mutex_unlock(&devices_mutex);
> +	if (err)
> +		return err;
>  
> -	dbg_gen("remove mtd%d", mtd->index);
> +	mtd = &gluebi->mtd;
>  	err = del_mtd_device(mtd);
> -	if (err)
> +	if (err) {
> +		err_msg("cannot remove fake MTD device %d, UBI device %d, "
> +			"volume %d, error %d", mtd->index, gluebi->ubi_num,
> +			gluebi->vol_id, err);
> +		mutex_lock(&devices_mutex);
> +		list_add_tail(&gluebi->list, &gluebi_devices);
> +		mutex_unlock(&devices_mutex);
>  		return err;
> +	}
> +
>  	kfree(mtd->name);
> +	kfree(gluebi);
>  	return 0;
>  }
>  
>  /**
> - * ubi_gluebi_updated - UBI volume was updated notifier.
> - * @vol: volume description object
> + * gluebi_updated - UBI volume was updated notifier.
> + * @vi: volume info structure
>   *
> - * This function is called every time an UBI volume is updated. This function
> - * does nothing if volume @vol is dynamic, and changes MTD device size if the
> + * This function is called every time an UBI volume is updated. It does nothing
> + * if te volume @vol is dynamic, and changes MTD device size if the
>   * volume is static. This is needed because static volumes cannot be read past
> - * data they contain.
> + * data they contain. This function returns zero in case of success and a
> + * negative error code in case of error.
> + */
> +static int gluebi_updated(struct ubi_volume_info *vi)
> +{
> +	struct gluebi_device *gluebi;
> +
> +	mutex_lock(&devices_mutex);
> +	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
> +	if (!gluebi) {
> +		mutex_unlock(&devices_mutex);
> +		err_msg("got update notification for unknown UBI device %d "
> +			"volume %d", vi->ubi_num, vi->vol_id);
> +		return -ENOENT;
> +	}
> +
> +	if (vi->vol_type == UBI_STATIC_VOLUME)
> +		gluebi->mtd.size = vi->used_bytes;
> +	mutex_unlock(&devices_mutex);
> +	return 0;
> +}
> +
> +/**
> + * gluebi_resized - UBI volume was re-sized notifier.
> + * @vi: volume info structure
> + *
> + * This function is called every time an UBI volume is re-size. It changes the
> + * corresponding fake MTD device size. This function returns zero in case of
> + * success and a negative error code in case of error.
> + */
> +static int gluebi_resized(struct ubi_volume_info *vi)
> +{
> +	struct gluebi_device *gluebi;
> +
> +	mutex_lock(&devices_mutex);
> +	gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id);
> +	if (!gluebi) {
> +		mutex_unlock(&devices_mutex);
> +		err_msg("got update notification for unknown UBI device %d "
> +			"volume %d", vi->ubi_num, vi->vol_id);
> +		return -ENOENT;
> +	}
> +	gluebi->mtd.size = vi->used_bytes;
> +	mutex_unlock(&devices_mutex);
> +	return 0;
> +}
> +
> +/**
> + * gluebi_notify - UBI notification handler.
> + * @nb: registered notifier block
> + * @l: notification type
> + * @ptr: pointer to the &struct ubi_notification object
>   */
> -void ubi_gluebi_updated(struct ubi_volume *vol)
> +static int gluebi_notify(struct notifier_block *nb, unsigned long l,
> +			 void *ns_ptr)
>  {
> -	struct mtd_info *mtd = &vol->gluebi_mtd;
> +	struct ubi_notification *nt = ns_ptr;
> +
> +	switch (l) {
> +	case UBI_VOLUME_ADDED:
> +		gluebi_create(&nt->di, &nt->vi);
> +		break;
> +	case UBI_VOLUME_REMOVED:
> +		gluebi_remove(&nt->vi);
> +		break;
> +	case UBI_VOLUME_RESIZED:
> +		gluebi_resized(&nt->vi);
> +		break;
> +	case UBI_VOLUME_UPDATED:
> +		gluebi_updated(&nt->vi);
> +		break;
> +	default:
> +		break;
> +	}
> +	return NOTIFY_OK;
> +}
>  
> -	if (vol->vol_type == UBI_STATIC_VOLUME)
> -		mtd->size = vol->used_bytes;
> +static struct notifier_block gluebi_notifier = {
> +	.notifier_call	= gluebi_notify,
> +};
> +
> +static int __init ubi_gluebi_init(void)
> +{
> +	return ubi_register_volume_notifier(&gluebi_notifier, 0);
>  }
> +
> +static void __exit ubi_gluebi_exit(void)
> +{
> +	struct gluebi_device *gluebi, *g;
> +
> +	list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) {
> +		int err;
> +		struct mtd_info *mtd = &gluebi->mtd;
> +
> +		err = del_mtd_device(mtd);
> +		if (err)
> +			err_msg("error %d while removing gluebi MTD device %d, "
> +				"UBI device %d, volume %d - ignoring", err,
> +				mtd->index, gluebi->ubi_num, gluebi->vol_id);
> +		kfree(mtd->name);
> +		kfree(gluebi);
> +	}
> +	ubi_unregister_volume_notifier(&gluebi_notifier);
> +}
> +
> +module_init(ubi_gluebi_init);
> +module_exit(ubi_gluebi_exit);
> +MODULE_DESCRIPTION("MTD emulation layer over UBI volumes");
> +MODULE_AUTHOR("Artem Bityutskiy, Joern Engel");
> +MODULE_LICENSE("GPL");
> -- 
> 1.6.0.6
> 

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

* Re: [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API)
  2009-06-01 17:07             ` dmitry pervushin
@ 2009-06-02  6:40               ` Artem Bityutskiy
  0 siblings, 0 replies; 15+ messages in thread
From: Artem Bityutskiy @ 2009-06-02  6:40 UTC (permalink / raw)
  To: dpervushin; +Cc: linux-mtd

On Mon, 2009-06-01 at 21:07 +0400, dmitry pervushin wrote:
> Thanks for paying attention on this; the patch looks ok for me.

OK, thanks. Pushed the patches to ubi-2.6.git/master.

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

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

end of thread, other threads:[~2009-06-02  6:41 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-29 15:29 [PATCH] [UBI] [1/3] ubi notifications API dmitry pervushin
2009-05-06  6:31 ` Artem Bityutskiy
2009-05-07  6:14 ` Artem Bityutskiy
2009-05-18  8:05 ` Artem Bityutskiy
2009-05-18 15:22 ` Artem Bityutskiy
2009-05-18 15:26   ` [PATCH] UBI: add notification API Artem Bityutskiy
2009-05-18 15:28     ` [PATCH] UBI: remove built-in gluebi Artem Bityutskiy
2009-05-18 15:39   ` [PATCH] [UBI] [1/3] ubi notifications API Artem Bityutskiy
2009-05-29 19:27     ` [PATCH] 3/3 ubi notification API " dmitry pervushin
2009-05-31 13:52       ` Artem Bityutskiy
2009-05-31 14:32         ` [PATCH] 3/3 ubi notification API (was Re: [PATCH] [UBI] [1/3] ubi notifications API) dmitry pervushin
2009-06-01 16:48           ` Artem Bityutskiy
2009-06-01 17:07             ` dmitry pervushin
2009-06-02  6:40               ` Artem Bityutskiy
2009-05-31 14:06       ` [PATCH] 3/3 ubi notification API Re: [PATCH] [UBI] [1/3] ubi notifications API 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.