Patchwork [UBI] 1/4 UBI volume notifications - UBI changes

login
register
mail settings
Submitter dmitry pervushin
Date Dec. 8, 2008, 5:59 p.m.
Message ID <1228759160.7622.28.camel@hp.diimka.lan>
Download mbox | patch
Permalink /patch/12812/
State New
Headers show

Comments

dmitry pervushin - Dec. 8, 2008, 5:59 p.m.
Signed-off-by: dmitry pervushin <dimka@embeddedalley.com>

---
 drivers/mtd/ubi/build.c |   32 ++++++++++++++++++++++-
 drivers/mtd/ubi/cdev.c  |    2 +-
 drivers/mtd/ubi/kapi.c  |   29 +++++++++++++++++++++
 drivers/mtd/ubi/ubi.h   |   64 +++++++++++++++++++++++++++-------------------
 drivers/mtd/ubi/vmt.c   |   39 +++++++++++-----------------
 include/linux/mtd/ubi.h |   17 ++++++++++++
 6 files changed, 130 insertions(+), 53 deletions(-)
Artem Bityutskiy - Dec. 9, 2008, 10:36 a.m.
On Mon, 2008-12-08 at 20:59 +0300, dmitry pervushin wrote:
<snip>
>  /**
> + * ubi_enum_volumes - enumerate all existing volumes
> + */
> +int ubi_enum_volumes(void *context,
> +	void (*enumerator)(void *context, int ubi, const char *volume_name))
> +{
> +	int ubi_num, i, count = 0;
> +	struct ubi_device *ubi;
> +
> +	spin_lock(&ubi_devices_lock);
> +	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
> +		ubi = ubi_devices[ubi_num];
> +		if (!ubi)
> +			continue;
> +		spin_lock(&ubi->volumes_lock);
> +		for (i = 0; i < ubi->vtbl_slots; i++) {
> +			if (!ubi->volumes[i])
> +				continue;
> +			enumerator(context, ubi_num, ubi->volumes[i]->name);
> +			count++;
> +		}
> +		spin_unlock(&ubi->volumes_lock);
> +	}
> +	spin_unlock(&ubi_devices_lock);
> +	return count;
> +}

Could you please initialize 'struct ubi_volume_notification' straight in
this function, instead of having 'enumerator' call-back? I think this
would be much more readable. I do not see the reason for this
complexity.

<snip>
> +/**
>   * ubi_get_device - get UBI device.
>   * @ubi_num: UBI device number
>   *
> @@ -842,6 +870,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
>  			goto out_detach;
>  	}
>  
> +	/* when processing uif_init, we already might want to open the volume */
> +	ubi_devices[ubi_num] = ubi;
>  	err = uif_init(ubi);
>  	if (err)
>  		goto out_nofree;

I do not understand this change. The point is to prevent anyone from
opening the volume before it is completely initialized. What you do -
you allow the volume to be opened while it is in the middle of
initialization, which is wrong. E.g., what if the initialization fails
at some point?

And this change does not seem to be relevant to this patch.

<snip>
> --- a/drivers/mtd/ubi/cdev.c
> +++ b/drivers/mtd/ubi/cdev.c
> @@ -395,7 +395,7 @@ 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_VOLUME_CHANGED, ubi->ubi_num, vol->name);
>  		revoke_exclusive(desc, UBI_READWRITE);
>  	}

Could you please remove gluebi as a separate patch?

> diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
<snip>
> +
> +static void do_notify_added(void *context, int ubi, const char *name)
> +{
> +	struct notifier_block *nb = context;
> +	struct ubi_volume_notification nt;
> +
> +	nt.ubi_device = ubi;
> +	nt.volume_name = name;
> +	nb->notifier_call(context, UBI_VOLUME_ADDED, &nt);
> +}

As I said above, this call-back function does not seem to be reasonable.

> diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
<snip>
> -#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
>  };

Similar. May this stuff be removed in a separate patch please? It'll
make things easier to review.

<snip>
> +int ubi_register_volume_notifier(struct notifier_block *nb,
> +		int ignore_existing);
> +int ubi_unregister_volume_notifier(struct notifier_block *nb);
> +
> +struct ubi_volume_notification {
> +	int ubi_device;
> +	const char *volume_name;
> +};

This should have volume ID instead of name. Indeed, the ID is unique and
never changes, while name may change, so ID is better for volume
identification purposes.

<snip>
> +enum ubi_volume_notification_type {
> +	UBI_VOLUME_ADDED,
> +	UBI_VOLUME_DELETED,
> +	UBI_VOLUME_CHANGED,
> +	UBI_VOLUME_RENAMING,
> +	UBI_VOLUME_RENAMED,
> +};

I do not see a reason for 2 rename notifications. Why? For me it looks
like one is enough.
dmitry pervushin - Dec. 10, 2008, 7:50 p.m.
On Tue, 2008-12-09 at 12:36 +0200, Artem Bityutskiy wrote:

Thanks for your review, my the only comment is inlined below.

[skipped]
> <snip>
> > +/**
> >   * ubi_get_device - get UBI device.
> >   * @ubi_num: UBI device number
> >   *
> > @@ -842,6 +870,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
> >  			goto out_detach;
> >  	}
> >  
> > +	/* when processing uif_init, we already might want to open the volume */
> > +	ubi_devices[ubi_num] = ubi;
> >  	err = uif_init(ubi);
> >  	if (err)
> >  		goto out_nofree;
> 
> I do not understand this change. The point is to prevent anyone from
> opening the volume before it is completely initialized. What you do -
> you allow the volume to be opened while it is in the middle of
> initialization, which is wrong. E.g., what if the initialization fails
> at some point?
> 
> And this change does not seem to be relevant to this patch.
This change is absolutely needed :)
Well, the sequence of steps is as follows:
1. uif_init calls ubi_add_volume
2. ubi_add_volume notifies everyone about volume adding
3. (successful exit is not interested to us)
4. in case of errors reported by uif_init ubi_attach_mtd_dev calls
ubi_kill_volumes
5. ubi_kill_volumes calls ubi_free_volume, which notifies everyone about
volume deleting.

In current version, "notifies about volume adding" corresponds to
ubi_create_gluebi and "...deleting" means ubi_destory_gluebi"

Does this sound right? OK, then I am replacing ubi_create_gluebi with
notification, notification function tries to open new (just appeared)
volume... and fails, because ubi_open_volume tries to ubi_get_device.
It, in turn checks the "ubi_devices[ubi_num]" which is not filled yet.

So, I do insist on the change.
Artem Bityutskiy - Dec. 11, 2008, 6:07 a.m.
On Wed, 2008-12-10 at 22:50 +0300, dmitry pervushin wrote:
> On Tue, 2008-12-09 at 12:36 +0200, Artem Bityutskiy wrote:
> 
> Thanks for your review, my the only comment is inlined below.
> 
> [skipped]
> > <snip>
> > > +/**
> > >   * ubi_get_device - get UBI device.
> > >   * @ubi_num: UBI device number
> > >   *
> > > @@ -842,6 +870,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
> > >  			goto out_detach;
> > >  	}
> > >  
> > > +	/* when processing uif_init, we already might want to open the volume */
> > > +	ubi_devices[ubi_num] = ubi;
> > >  	err = uif_init(ubi);
> > >  	if (err)
> > >  		goto out_nofree;
> > 
> > I do not understand this change. The point is to prevent anyone from
> > opening the volume before it is completely initialized. What you do -
> > you allow the volume to be opened while it is in the middle of
> > initialization, which is wrong. E.g., what if the initialization fails
> > at some point?
> > 
> > And this change does not seem to be relevant to this patch.
> This change is absolutely needed :)
> Well, the sequence of steps is as follows:
> 1. uif_init calls ubi_add_volume
> 2. ubi_add_volume notifies everyone about volume adding
> 3. (successful exit is not interested to us)
> 4. in case of errors reported by uif_init ubi_attach_mtd_dev calls
> ubi_kill_volumes
> 5. ubi_kill_volumes calls ubi_free_volume, which notifies everyone about
> volume deleting.

What may happen is

1. You make the UBI device visible by doing 'ubi_devices[ubi_num] =
ubi'.
2. You call 'uif_init()' which starts adding volumes. Suppose it added N
volumes out of M (M > N).
3. Some other task opens the UBI device, opens volume L (L <= N), and
starts utilizing it. E.g., it might mounted by UBIFS.
4. 'uif_init()' fails to add volume S (S > N <= M), and all resources,
including the opened volume L will be freed, and the system is in
trouble.

> In current version, "notifies about volume adding" corresponds to
> ubi_create_gluebi and "...deleting" means ubi_destory_gluebi"
> 
> Does this sound right? OK, then I am replacing ubi_create_gluebi with
> notification, notification function tries to open new (just appeared)
> volume... and fails, because ubi_open_volume tries to ubi_get_device.
> It, in turn checks the "ubi_devices[ubi_num]" which is not filled yet.

I think the solution is to call notifiers _after_ _everything_ is
successfully initialized and has no chances to fail anymore, i.e., at
the very end of 'ubi_attach_mtd_dev()' function.
dmitry pervushin - Dec. 11, 2008, 9:25 a.m.
On Thu, 2008-12-11 at 08:07 +0200, Artem Bityutskiy wrote:
> > [skipped]
> > > <snip>
> > > > +/**
> > > >   * ubi_get_device - get UBI device.
> > > >   * @ubi_num: UBI device number
> > > >   *
> > > > @@ -842,6 +870,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
> > > >  			goto out_detach;
> > > >  	}
> > > >  
> > > > +	/* when processing uif_init, we already might want to open the volume */
> > > > +	ubi_devices[ubi_num] = ubi;
> > > >  	err = uif_init(ubi);
> > > >  	if (err)
> > > >  		goto out_nofree;
> > > 
> > > I do not understand this change. The point is to prevent anyone from
> > > opening the volume before it is completely initialized. What you do -
> > > you allow the volume to be opened while it is in the middle of
> > > initialization, which is wrong. E.g., what if the initialization fails
> > > at some point?
> > > 
> > > And this change does not seem to be relevant to this patch.
> > This change is absolutely needed :)
> > Well, the sequence of steps is as follows:
> > 1. uif_init calls ubi_add_volume
> > 2. ubi_add_volume notifies everyone about volume adding
> > 3. (successful exit is not interested to us)
> > 4. in case of errors reported by uif_init ubi_attach_mtd_dev calls
> > ubi_kill_volumes
> > 5. ubi_kill_volumes calls ubi_free_volume, which notifies everyone about
> > volume deleting.

Isn't it better then to protect the critical section in uif_init and
open_volume by mutexes? Now it looks as you are adding volumes on
non-existing-yet device.

> What may happen is
> 
> 1. You make the UBI device visible by doing 'ubi_devices[ubi_num] =
> ubi'.
> 2. You call 'uif_init()' which starts adding volumes. Suppose it added N
> volumes out of M (M > N).
> 3. Some other task opens the UBI device, opens volume L (L <= N), and
> starts utilizing it. E.g., it might mounted by UBIFS.
> 4. 'uif_init()' fails to add volume S (S > N <= M), and all resources,
> including the opened volume L will be freed, and the system is in
> trouble.
> 
> > In current version, "notifies about volume adding" corresponds to
> > ubi_create_gluebi and "...deleting" means ubi_destory_gluebi"
> > 
> > Does this sound right? OK, then I am replacing ubi_create_gluebi with
> > notification, notification function tries to open new (just appeared)
> > volume... and fails, because ubi_open_volume tries to ubi_get_device.
> > It, in turn checks the "ubi_devices[ubi_num]" which is not filled yet.
> 
> I think the solution is to call notifiers _after_ _everything_ is
> successfully initialized and has no chances to fail anymore, i.e., at
> the very end of 'ubi_attach_mtd_dev()' function.
>
Artem Bityutskiy - Dec. 11, 2008, 7:20 p.m.
On Thu, 2008-12-11 at 12:25 +0300, dmitry pervushin wrote:
> > > > I do not understand this change. The point is to prevent anyone from
> > > > opening the volume before it is completely initialized. What you do -
> > > > you allow the volume to be opened while it is in the middle of
> > > > initialization, which is wrong. E.g., what if the initialization fails
> > > > at some point?
> > > > 
> > > > And this change does not seem to be relevant to this patch.
> > > This change is absolutely needed :)
> > > Well, the sequence of steps is as follows:
> > > 1. uif_init calls ubi_add_volume
> > > 2. ubi_add_volume notifies everyone about volume adding
> > > 3. (successful exit is not interested to us)
> > > 4. in case of errors reported by uif_init ubi_attach_mtd_dev calls
> > > ubi_kill_volumes
> > > 5. ubi_kill_volumes calls ubi_free_volume, which notifies everyone about
> > > volume deleting.
> 
> Isn't it better then to protect the critical section in uif_init and
> open_volume by mutexes?

May be. If you need this, feel free to send a patch. But it would not
give you much, because you would have to call your notifiers _outside_
the mutexes, i.e. at the very end of the attach function.

>  Now it looks as you are adding volumes on
> non-existing-yet device.

Right. For a short period of time during the attach process you may see
volumes which you cannot really open (you get -ENODEV). That was not a
problem so far, and it was just easier to implement things this way.

If you want to improve this and make the opening processes wait on a
mutex - please, go ahead. But I doubt you really need this.
dmitry pervushin - Dec. 15, 2008, 11:13 a.m.
On Thu, 2008-12-11 at 21:20 +0200, Artem Bityutskiy wrote:
> On Thu, 2008-12-11 at 12:25 +0300, dmitry pervushin wrote:
> > > > > I do not understand this change. The point is to prevent anyone from
> > > > > opening the volume before it is completely initialized. What you do -
> > > > > you allow the volume to be opened while it is in the middle of
> > > > > initialization, which is wrong. E.g., what if the initialization fails
> > > > > at some point?
> > > > > 
> > > > > And this change does not seem to be relevant to this patch.
> > > > This change is absolutely needed :)
> > > > Well, the sequence of steps is as follows:
> > > > 1. uif_init calls ubi_add_volume
> > > > 2. ubi_add_volume notifies everyone about volume adding
> > > > 3. (successful exit is not interested to us)
> > > > 4. in case of errors reported by uif_init ubi_attach_mtd_dev calls
> > > > ubi_kill_volumes
> > > > 5. ubi_kill_volumes calls ubi_free_volume, which notifies everyone about
> > > > volume deleting.
> > 
> > Isn't it better then to protect the critical section in uif_init and
> > open_volume by mutexes?
> 
> May be. If you need this, feel free to send a patch. But it would not
> give you much, because you would have to call your notifiers _outside_
> the mutexes, i.e. at the very end of the attach function.
> 
> >  Now it looks as you are adding volumes on
> > non-existing-yet device.
> 
> Right. For a short period of time during the attach process you may see
> volumes which you cannot really open (you get -ENODEV). That was not a
> problem so far, and it was just easier to implement things this way.
> 
> If you want to improve this and make the opening processes wait on a
> mutex - please, go ahead. But I doubt you really need this.
Well, agreed. It makes sense. I am attaching new serie of patches:

ubi-notifications.patch		- ubi notifications
remove-gluebi.patch		- removes current mtd emulation
gluebi.patch			- adds notification-based one
mtdblkdevs.patch		- changes MTD blkdevs to accept NULL mtd and allow
dynamic major number assignment
ubiblock.patch			- simple FTL

Patch

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 634e2e8..fe9e329 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -122,6 +122,34 @@  static struct device_attribute dev_mtd_num =
 	__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
 
 /**
+ * ubi_enum_volumes - enumerate all existing volumes
+ */
+int ubi_enum_volumes(void *context,
+	void (*enumerator)(void *context, int ubi, const char *volume_name))
+{
+	int ubi_num, i, count = 0;
+	struct ubi_device *ubi;
+
+	spin_lock(&ubi_devices_lock);
+	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
+		ubi = ubi_devices[ubi_num];
+		if (!ubi)
+			continue;
+		spin_lock(&ubi->volumes_lock);
+		for (i = 0; i < ubi->vtbl_slots; i++) {
+			if (!ubi->volumes[i])
+				continue;
+			enumerator(context, ubi_num, ubi->volumes[i]->name);
+			count++;
+		}
+		spin_unlock(&ubi->volumes_lock);
+	}
+	spin_unlock(&ubi_devices_lock);
+	return count;
+}
+
+
+/**
  * ubi_get_device - get UBI device.
  * @ubi_num: UBI device number
  *
@@ -842,6 +870,8 @@  int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 			goto out_detach;
 	}
 
+	/* when processing uif_init, we already might want to open the volume */
+	ubi_devices[ubi_num] = ubi;
 	err = uif_init(ubi);
 	if (err)
 		goto out_nofree;
@@ -874,12 +904,12 @@  int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 		ubi->thread_enabled = 1;
 	wake_up_process(ubi->bgt_thread);
 
-	ubi_devices[ubi_num] = ubi;
 	return ubi_num;
 
 out_uif:
 	uif_close(ubi);
 out_nofree:
+	ubi_devices[ubi_num] = NULL;
 	do_free = 0;
 out_detach:
 	ubi_wl_close(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index b30a0b8..64a5398 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -395,7 +395,7 @@  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_VOLUME_CHANGED, ubi->ubi_num, vol->name);
 		revoke_exclusive(desc, UBI_READWRITE);
 	}
 
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 5d9bcf1..0f3256b 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -656,3 +656,32 @@  int ubi_sync(int ubi_num)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_sync);
+
+BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
+
+static void do_notify_added(void *context, int ubi, const char *name)
+{
+	struct notifier_block *nb = context;
+	struct ubi_volume_notification nt;
+
+	nt.ubi_device = ubi;
+	nt.volume_name = name;
+	nb->notifier_call(context, UBI_VOLUME_ADDED, &nt);
+}
+
+int ubi_register_volume_notifier(struct notifier_block *nb, int ignore_existing)
+{
+	if (!ignore_existing) {
+	       down_read(&ubi_notifiers.rwsem);
+	       ubi_enum_volumes(nb, do_notify_added);
+	       up_read(&ubi_notifiers.rwsem);
+	}
+	return blocking_notifier_chain_register(&ubi_notifiers, nb);
+}
+EXPORT_SYMBOL_GPL(ubi_register_volume_notifier);
+
+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 1c3fa18..b82aaf0 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"
@@ -196,10 +197,6 @@  struct ubi_volume_desc;
  * @updating: %1 if the volume is being updated
  * @changing_leb: %1 if the atomic LEB change ioctl command is in progress
  *
- * @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
@@ -242,17 +239,6 @@  struct ubi_volume {
 	unsigned int upd_marker:1;
 	unsigned int updating:1;
 	unsigned int changing_leb: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
 };
 
 /**
@@ -447,6 +433,7 @@  extern struct file_operations ubi_cdev_operations;
 extern struct file_operations ubi_vol_cdev_operations;
 extern struct class *ubi_class;
 extern struct mutex ubi_devices_mutex;
+extern struct blocking_notifier_head ubi_notifiers;
 
 /* vtbl.c */
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -479,17 +466,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);
@@ -539,7 +515,41 @@  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_enum_volumes(void *context,
+       void (*enumerator)(void *context, int ubi, const char *volume_name));
 
+static inline char *ubi_notification(enum ubi_volume_notification_type t)
+{
+	static char *nstr[] = { 
+	 [UBI_VOLUME_ADDED]	= "Added",
+	 [UBI_VOLUME_DELETED]	= "Deleted",
+	 [UBI_VOLUME_RENAMING]	= "Renaming",
+	 [UBI_VOLUME_RENAMED]	= "Renamed",
+	 [UBI_VOLUME_CHANGED]	= "Changed",
+	};
+	return nstr[t];
+}
+/**
+ * ubi_volume_notify - notify all registered clients about volume changes
+ *
+ * @t: notification type
+ * @ubi_device: device number
+ * @volume_name: name of created/removed/changed volume
+ */
+static inline int ubi_volume_notify(enum ubi_volume_notification_type t,
+		int ubi_device, char *volume_name)
+{
+       struct ubi_volume_notification nt;
+
+       nt.ubi_device = ubi_device;
+       nt.volume_name = volume_name;
+       dbg_gen("%s: %s volume %s on device %d\n",
+		       __func__,
+		       ubi_notification(t),
+		       volume_name,
+		       ubi_device);
+       return blocking_notifier_call_chain(&ubi_notifiers, t, &nt);
+}
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
  * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 3531ca9..e6bedaa 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -320,10 +320,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;
@@ -333,7 +329,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);
@@ -361,6 +357,8 @@  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_VOLUME_ADDED, ubi->ubi_num, vol->name);
+
 	err = paranoid_check_volumes(ubi);
 	return err;
 
@@ -376,10 +374,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:
@@ -431,13 +425,10 @@  int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
 		err = -EBUSY;
 		goto out_unlock;
 	}
+	ubi_volume_notify(UBI_VOLUME_DELETED, ubi->ubi_num, vol->name);
 	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)
@@ -473,6 +464,7 @@  int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
 	return err;
 
 out_err:
+	ubi_volume_notify(UBI_VOLUME_ADDED, ubi->ubi_num, vol->name);
 	ubi_err("cannot remove volume %d, error %d", vol_id, err);
 	spin_lock(&ubi->volumes_lock);
 	ubi->volumes[vol_id] = vol;
@@ -590,6 +582,8 @@  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_VOLUME_CHANGED, ubi->ubi_num, vol->name);
+
 	err = paranoid_check_volumes(ubi);
 	return err;
 
@@ -631,10 +625,14 @@  int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
 		} else {
 			struct ubi_volume *vol = re->desc->vol;
 
+			ubi_volume_notify(UBI_VOLUME_RENAMING,
+				ubi->ubi_num, vol->name);
 			spin_lock(&ubi->volumes_lock);
 			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->name);
 		}
 	}
 
@@ -670,10 +668,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;
@@ -681,21 +675,19 @@  int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
 	sprintf(&vol->dev.bus_id[0], "%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;
 	}
 
+	ubi_volume_notify(UBI_VOLUME_ADDED, ubi->ubi_num, vol->name);
 	err = paranoid_check_volumes(ubi);
 	return err;
 
-out_gluebi:
-	err = ubi_destroy_gluebi(vol);
 out_cdev:
 	cdev_del(&vol->cdev);
 	return err;
@@ -711,12 +703,11 @@  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_volume_notify(UBI_VOLUME_DELETED, ubi->ubi_num, vol->name);
+
 	ubi->volumes[vol->vol_id] = NULL;
-	err = ubi_destroy_gluebi(vol);
 	cdev_del(&vol->cdev);
 	volume_sysfs_close(vol);
 }
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index 6316faf..3eb3997 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -184,4 +184,21 @@  static inline int ubi_change(struct ubi_volume_desc *desc, int lnum,
 	return ubi_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
 }
 
+int ubi_register_volume_notifier(struct notifier_block *nb,
+		int ignore_existing);
+int ubi_unregister_volume_notifier(struct notifier_block *nb);
+
+struct ubi_volume_notification {
+	int ubi_device;
+	const char *volume_name;
+};
+
+enum ubi_volume_notification_type {
+	UBI_VOLUME_ADDED,
+	UBI_VOLUME_DELETED,
+	UBI_VOLUME_CHANGED,
+	UBI_VOLUME_RENAMING,
+	UBI_VOLUME_RENAMED,
+};
+
 #endif /* !__LINUX_UBI_H__ */