[PATCH] [UBI] 1/5 - UBI notifications, take two
dmitry pervushin
dpervushin at gmail.com
Mon Dec 15 06:13:55 EST 2008
Implement notifications about UBI volume changes
Signed-off-by: dmitry pervushin <dimka at embeddedalley.com>
---
drivers/mtd/ubi/build.c | 39 +++++++++++++++++++++++++++++++++++++++
drivers/mtd/ubi/cdev.c | 2 ++
drivers/mtd/ubi/kapi.c | 25 +++++++++++++++++++++++++
drivers/mtd/ubi/ubi.h | 35 +++++++++++++++++++++++++++++++++++
drivers/mtd/ubi/vmt.c | 8 ++++++++
include/linux/mtd/ubi.h | 16 ++++++++++++++++
6 files changed, 125 insertions(+)
Index: ubifs-2.6/drivers/mtd/ubi/build.c
===================================================================
--- ubifs-2.6.orig/drivers/mtd/ubi/build.c
+++ ubifs-2.6/drivers/mtd/ubi/build.c
@@ -122,6 +122,51 @@ static struct device_attribute dev_mtd_n
__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
/**
+ * ubi_enum_volumes - enumerate all existing volumes and send notification
+ *
+ * @t: notification type to send
+ * @ubi: UBI device number
+ * @nb: notifier to be called
+ *
+ * Walk on volume list that are created on device @ubi, or if @ubi < 0, on all
+ * available UBI devices. For each volume, send the notification - either
+ * system-wide if @nb is NULL, or only to the registered @nb
+ *
+ * Returns number of volumes processed
+ */
+int ubi_enum_volumes(enum ubi_volume_notification_type t, int ubi,
+ struct notifier_block *nb)
+{
+ int ubi_num, i, count = 0;
+ struct ubi_device *ubi_dev;
+ struct ubi_volume_notification nt;
+
+ ubi_num = ubi < 0 ? 0 : ubi;
+ spin_lock(&ubi_devices_lock);
+ do {
+ nt.ubi_num = ubi_num++;
+ ubi_dev = ubi_devices[nt.ubi_num];
+ if (!ubi_dev)
+ continue;
+ spin_lock(&ubi_dev->volumes_lock);
+ for (i = 0; i < ubi_dev->vtbl_slots; i++) {
+ if (!ubi_dev->volumes[i])
+ continue;
+ nt.vol_id = ubi_dev->volumes[i]->vol_id;
+ if (nb)
+ nb->notifier_call(nb, t, &nt);
+ else
+ blocking_notifier_call_chain(&ubi_notifiers,
+ t, &nt);
+ count++;
+ }
+ spin_unlock(&ubi_dev->volumes_lock);
+ } while (ubi < 0 && ubi_num < UBI_MAX_DEVICES);
+ spin_unlock(&ubi_devices_lock);
+ return count;
+}
+
+/**
* ubi_get_device - get UBI device.
* @ubi_num: UBI device number
*
@@ -876,6 +921,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_num, NULL);
return ubi_num;
out_uif:
@@ -937,6 +983,8 @@ int ubi_detach_mtd_dev(int ubi_num, int
ubi_devices[ubi_num] = NULL;
spin_unlock(&ubi_devices_lock);
+ ubi_enum_volumes(UBI_VOLUME_DELETED, ubi_num, NULL);
+
ubi_assert(ubi_num == ubi->ubi_num);
dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
Index: ubifs-2.6/drivers/mtd/ubi/cdev.c
===================================================================
--- ubifs-2.6.orig/drivers/mtd/ubi/cdev.c
+++ ubifs-2.6/drivers/mtd/ubi/cdev.c
@@ -396,6 +396,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: ubifs-2.6/drivers/mtd/ubi/kapi.c
===================================================================
--- ubifs-2.6.orig/drivers/mtd/ubi/kapi.c
+++ ubifs-2.6/drivers/mtd/ubi/kapi.c
@@ -656,3 +656,52 @@ 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 ¬ifier_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_device_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 r;
+
+ r = blocking_notifier_chain_register(&ubi_notifiers, nb);
+ if (!r)
+ goto out;
+ if (ignore_existing)
+ goto out;
+ down_read(&ubi_notifiers.rwsem);
+ ubi_enum_volumes(UBI_VOLUME_ADDED, -1, nb);
+ up_read(&ubi_notifiers.rwsem);
+out:
+ return r;
+}
+EXPORT_SYMBOL_GPL(ubi_register_volume_notifier);
+
+/**
+ * ubi_unregister_volume_notifier - unregister the volume notifier registered
+ * by ubi_register_volume_notifier
+ *
+ * @nb: pointer to the filled struct ¬ifier_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: ubifs-2.6/drivers/mtd/ubi/ubi.h
===================================================================
--- ubifs-2.6.orig/drivers/mtd/ubi/ubi.h
+++ ubifs-2.6/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"
@@ -447,6 +448,7 @@ extern struct file_operations ubi_cdev_o
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,
@@ -539,7 +541,40 @@ 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(enum ubi_volume_notification_type t,
+ int ubi_num, struct notifier_block *nb);
+static inline char *ubi_notification(enum ubi_volume_notification_type t)
+{
+ static char *nstr[] = {
+ [UBI_VOLUME_ADDED] = "Added",
+ [UBI_VOLUME_DELETED] = "Deleted",
+ [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_num, int volume_id)
+{
+ struct ubi_volume_notification nt;
+
+ nt.ubi_num = ubi_num;
+ nt.vol_id = volume_id;
+ dbg_gen("%s: %s volume id %d on device %d\n",
+ __func__,
+ ubi_notification(t),
+ volume_id,
+ ubi_num);
+ 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
Index: ubifs-2.6/drivers/mtd/ubi/vmt.c
===================================================================
--- ubifs-2.6.orig/drivers/mtd/ubi/vmt.c
+++ ubifs-2.6/drivers/mtd/ubi/vmt.c
@@ -361,6 +361,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;
@@ -431,6 +432,7 @@ int ubi_remove_volume(struct ubi_volume_
err = -EBUSY;
goto out_unlock;
}
+ ubi_volume_notify(UBI_VOLUME_DELETED, ubi->ubi_num, vol->vol_id);
ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
@@ -473,6 +475,7 @@ int ubi_remove_volume(struct ubi_volume_
return err;
out_err:
+ ubi_volume_notify(UBI_VOLUME_ADDED, ubi->ubi_num, vol->vol_id);
ubi_err("cannot remove volume %d, error %d", vol_id, err);
spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = vol;
@@ -590,6 +593,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;
@@ -635,6 +639,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: ubifs-2.6/include/linux/mtd/ubi.h
===================================================================
--- ubifs-2.6.orig/include/linux/mtd/ubi.h
+++ ubifs-2.6/include/linux/mtd/ubi.h
@@ -184,4 +184,20 @@ static inline int ubi_change(struct ubi_
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_num;
+ int vol_id;
+};
+
+enum ubi_volume_notification_type {
+ UBI_VOLUME_ADDED,
+ UBI_VOLUME_DELETED,
+ UBI_VOLUME_CHANGED,
+ UBI_VOLUME_RENAMED,
+};
+
#endif /* !__LINUX_UBI_H__ */
More information about the linux-mtd
mailing list