aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi
diff options
context:
space:
mode:
authorDmitry Pervushin <dpervushin@embeddedalley.com>2009-04-29 11:29:38 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-06-02 06:53:35 -0400
commit0e0ee1cc33de8f0cc603269b354085dee340afa0 (patch)
tree5dfd658b85eabadfbf0c94bee94d46f8d74b839b /drivers/mtd/ubi
parentb86a2c56e512f46d140a4bcb4e35e8a7d4a99a4b (diff)
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>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r--drivers/mtd/ubi/build.c100
-rw-r--r--drivers/mtd/ubi/cdev.c1
-rw-r--r--drivers/mtd/ubi/kapi.c108
-rw-r--r--drivers/mtd/ubi/ubi.h12
-rw-r--r--drivers/mtd/ubi/vmt.c4
5 files changed, 204 insertions, 21 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index d3da66682667..964a99d48bc4 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -122,6 +122,94 @@ static struct device_attribute dev_mtd_num =
122 __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); 122 __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
123 123
124/** 124/**
125 * ubi_volume_notify - send a volume change notification.
126 * @ubi: UBI device description object
127 * @vol: volume description object of the changed volume
128 * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
129 *
130 * This is a helper function which notifies all subscribers about a volume
131 * change event (creation, removal, re-sizing, re-naming, updating). Returns
132 * zero in case of success and a negative error code in case of failure.
133 */
134int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype)
135{
136 struct ubi_notification nt;
137
138 ubi_do_get_device_info(ubi, &nt.di);
139 ubi_do_get_volume_info(ubi, vol, &nt.vi);
140 return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
141}
142
143/**
144 * ubi_notify_all - send a notification to all volumes.
145 * @ubi: UBI device description object
146 * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc)
147 * @nb: the notifier to call
148 *
149 * This function walks all volumes of UBI device @ubi and sends the @ntype
150 * notification for each volume. If @nb is %NULL, then all registered notifiers
151 * are called, otherwise only the @nb notifier is called. Returns the number of
152 * sent notifications.
153 */
154int ubi_notify_all(struct ubi_device *ubi, int ntype, struct notifier_block *nb)
155{
156 struct ubi_notification nt;
157 int i, count = 0;
158
159 ubi_do_get_device_info(ubi, &nt.di);
160
161 mutex_lock(&ubi->device_mutex);
162 for (i = 0; i < ubi->vtbl_slots; i++) {
163 /*
164 * Since the @ubi->device is locked, and we are not going to
165 * change @ubi->volumes, we do not have to lock
166 * @ubi->volumes_lock.
167 */
168 if (!ubi->volumes[i])
169 continue;
170
171 ubi_do_get_volume_info(ubi, ubi->volumes[i], &nt.vi);
172 if (nb)
173 nb->notifier_call(nb, ntype, &nt);
174 else
175 blocking_notifier_call_chain(&ubi_notifiers, ntype,
176 &nt);
177 count += 1;
178 }
179 mutex_unlock(&ubi->device_mutex);
180
181 return count;
182}
183
184/**
185 * ubi_enumerate_volumes - send "add" notification for all existing volumes.
186 * @nb: the notifier to call
187 *
188 * This function walks all UBI devices and volumes and sends the
189 * %UBI_VOLUME_ADDED notification for each volume. If @nb is %NULL, then all
190 * registered notifiers are called, otherwise only the @nb notifier is called.
191 * Returns the number of sent notifications.
192 */
193int ubi_enumerate_volumes(struct notifier_block *nb)
194{
195 int i, count = 0;
196
197 /*
198 * Since the @ubi_devices_mutex is locked, and we are not going to
199 * change @ubi_devices, we do not have to lock @ubi_devices_lock.
200 */
201 for (i = 0; i < UBI_MAX_DEVICES; i++) {
202 struct ubi_device *ubi = ubi_devices[i];
203
204 if (!ubi)
205 continue;
206 count += ubi_notify_all(ubi, UBI_VOLUME_ADDED, nb);
207 }
208
209 return count;
210}
211
212/**
125 * ubi_get_device - get UBI device. 213 * ubi_get_device - get UBI device.
126 * @ubi_num: UBI device number 214 * @ubi_num: UBI device number
127 * 215 *
@@ -891,6 +979,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
891 spin_unlock(&ubi->wl_lock); 979 spin_unlock(&ubi->wl_lock);
892 980
893 ubi_devices[ubi_num] = ubi; 981 ubi_devices[ubi_num] = ubi;
982 ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
894 return ubi_num; 983 return ubi_num;
895 984
896out_uif: 985out_uif:
@@ -933,13 +1022,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
933 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) 1022 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
934 return -EINVAL; 1023 return -EINVAL;
935 1024
936 spin_lock(&ubi_devices_lock); 1025 ubi = ubi_get_device(ubi_num);
937 ubi = ubi_devices[ubi_num]; 1026 if (!ubi)
938 if (!ubi) {
939 spin_unlock(&ubi_devices_lock);
940 return -EINVAL; 1027 return -EINVAL;
941 }
942 1028
1029 spin_lock(&ubi_devices_lock);
1030 put_device(&ubi->dev);
1031 ubi->ref_count -= 1;
943 if (ubi->ref_count) { 1032 if (ubi->ref_count) {
944 if (!anyway) { 1033 if (!anyway) {
945 spin_unlock(&ubi_devices_lock); 1034 spin_unlock(&ubi_devices_lock);
@@ -953,6 +1042,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
953 spin_unlock(&ubi_devices_lock); 1042 spin_unlock(&ubi_devices_lock);
954 1043
955 ubi_assert(ubi_num == ubi->ubi_num); 1044 ubi_assert(ubi_num == ubi->ubi_num);
1045 ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL);
956 dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); 1046 dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
957 1047
958 /* 1048 /*
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 9a2b217941f7..631983615f11 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,
396 } 396 }
397 vol->checked = 1; 397 vol->checked = 1;
398 ubi_gluebi_updated(vol); 398 ubi_gluebi_updated(vol);
399 ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
399 revoke_exclusive(desc, UBI_READWRITE); 400 revoke_exclusive(desc, UBI_READWRITE);
400 } 401 }
401 402
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 2675207c5fe3..88a72e9c8beb 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -26,6 +26,24 @@
26#include "ubi.h" 26#include "ubi.h"
27 27
28/** 28/**
29 * ubi_do_get_device_info - get information about UBI device.
30 * @ubi: UBI device description object
31 * @di: the information is stored here
32 *
33 * This function is the same as 'ubi_get_device_info()', but it assumes the UBI
34 * device is locked and cannot disappear.
35 */
36void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di)
37{
38 di->ubi_num = ubi->ubi_num;
39 di->leb_size = ubi->leb_size;
40 di->min_io_size = ubi->min_io_size;
41 di->ro_mode = ubi->ro_mode;
42 di->cdev = ubi->cdev.dev;
43}
44EXPORT_SYMBOL_GPL(ubi_do_get_device_info);
45
46/**
29 * ubi_get_device_info - get information about UBI device. 47 * ubi_get_device_info - get information about UBI device.
30 * @ubi_num: UBI device number 48 * @ubi_num: UBI device number
31 * @di: the information is stored here 49 * @di: the information is stored here
@@ -39,33 +57,24 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
39 57
40 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) 58 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
41 return -EINVAL; 59 return -EINVAL;
42
43 ubi = ubi_get_device(ubi_num); 60 ubi = ubi_get_device(ubi_num);
44 if (!ubi) 61 if (!ubi)
45 return -ENODEV; 62 return -ENODEV;
46 63 ubi_do_get_device_info(ubi, di);
47 di->ubi_num = ubi->ubi_num;
48 di->leb_size = ubi->leb_size;
49 di->min_io_size = ubi->min_io_size;
50 di->ro_mode = ubi->ro_mode;
51 di->cdev = ubi->cdev.dev;
52
53 ubi_put_device(ubi); 64 ubi_put_device(ubi);
54 return 0; 65 return 0;
55} 66}
56EXPORT_SYMBOL_GPL(ubi_get_device_info); 67EXPORT_SYMBOL_GPL(ubi_get_device_info);
57 68
58/** 69/**
59 * ubi_get_volume_info - get information about UBI volume. 70 * ubi_do_get_volume_info - get information about UBI volume.
60 * @desc: volume descriptor 71 * @ubi: UBI device description object
72 * @vol: volume description object
61 * @vi: the information is stored here 73 * @vi: the information is stored here
62 */ 74 */
63void ubi_get_volume_info(struct ubi_volume_desc *desc, 75void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
64 struct ubi_volume_info *vi) 76 struct ubi_volume_info *vi)
65{ 77{
66 const struct ubi_volume *vol = desc->vol;
67 const struct ubi_device *ubi = vol->ubi;
68
69 vi->vol_id = vol->vol_id; 78 vi->vol_id = vol->vol_id;
70 vi->ubi_num = ubi->ubi_num; 79 vi->ubi_num = ubi->ubi_num;
71 vi->size = vol->reserved_pebs; 80 vi->size = vol->reserved_pebs;
@@ -79,6 +88,17 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc,
79 vi->name = vol->name; 88 vi->name = vol->name;
80 vi->cdev = vol->cdev.dev; 89 vi->cdev = vol->cdev.dev;
81} 90}
91
92/**
93 * ubi_get_volume_info - get information about UBI volume.
94 * @desc: volume descriptor
95 * @vi: the information is stored here
96 */
97void ubi_get_volume_info(struct ubi_volume_desc *desc,
98 struct ubi_volume_info *vi)
99{
100 ubi_do_get_volume_info(desc->vol->ubi, desc->vol, vi);
101}
82EXPORT_SYMBOL_GPL(ubi_get_volume_info); 102EXPORT_SYMBOL_GPL(ubi_get_volume_info);
83 103
84/** 104/**
@@ -561,7 +581,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
561EXPORT_SYMBOL_GPL(ubi_leb_unmap); 581EXPORT_SYMBOL_GPL(ubi_leb_unmap);
562 582
563/** 583/**
564 * ubi_leb_map - map logical erasblock to a physical eraseblock. 584 * ubi_leb_map - map logical eraseblock to a physical eraseblock.
565 * @desc: volume descriptor 585 * @desc: volume descriptor
566 * @lnum: logical eraseblock number 586 * @lnum: logical eraseblock number
567 * @dtype: expected data type 587 * @dtype: expected data type
@@ -659,3 +679,59 @@ int ubi_sync(int ubi_num)
659 return 0; 679 return 0;
660} 680}
661EXPORT_SYMBOL_GPL(ubi_sync); 681EXPORT_SYMBOL_GPL(ubi_sync);
682
683BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
684
685/**
686 * ubi_register_volume_notifier - register a volume notifier.
687 * @nb: the notifier description object
688 * @ignore_existing: if non-zero, do not send "added" notification for all
689 * already existing volumes
690 *
691 * This function registers a volume notifier, which means that
692 * 'nb->notifier_call()' will be invoked when an UBI volume is created,
693 * removed, re-sized, re-named, or updated. The first argument of the function
694 * is the notification type. The second argument is pointer to a
695 * &struct ubi_notification object which describes the notification event.
696 * Using UBI API from the volume notifier is prohibited.
697 *
698 * This function returns zero in case of success and a negative error code
699 * in case of failure.
700 */
701int ubi_register_volume_notifier(struct notifier_block *nb,
702 int ignore_existing)
703{
704 int err;
705
706 err = blocking_notifier_chain_register(&ubi_notifiers, nb);
707 if (err != 0)
708 return err;
709 if (ignore_existing)
710 return 0;
711
712 /*
713 * We are going to walk all UBI devices and all volumes, and
714 * notify the user about existing volumes by the %UBI_VOLUME_ADDED
715 * event. We have to lock the @ubi_devices_mutex to make sure UBI
716 * devices do not disappear.
717 */
718 mutex_lock(&ubi_devices_mutex);
719 ubi_enumerate_volumes(nb);
720 mutex_unlock(&ubi_devices_mutex);
721
722 return err;
723}
724EXPORT_SYMBOL_GPL(ubi_register_volume_notifier);
725
726/**
727 * ubi_unregister_volume_notifier - unregister the volume notifier.
728 * @nb: the notifier description object
729 *
730 * This function unregisters volume notifier @nm and returns zero in case of
731 * success and a negative error code in case of failure.
732 */
733int ubi_unregister_volume_notifier(struct notifier_block *nb)
734{
735 return blocking_notifier_chain_unregister(&ubi_notifiers, nb);
736}
737EXPORT_SYMBOL_GPL(ubi_unregister_volume_notifier);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 6d929329a8d5..86e1a4e0ab01 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -38,6 +38,7 @@
38#include <linux/vmalloc.h> 38#include <linux/vmalloc.h>
39#include <linux/mtd/mtd.h> 39#include <linux/mtd/mtd.h>
40#include <linux/mtd/ubi.h> 40#include <linux/mtd/ubi.h>
41#include <linux/notifier.h>
41 42
42#include "ubi-media.h" 43#include "ubi-media.h"
43#include "scan.h" 44#include "scan.h"
@@ -483,6 +484,7 @@ extern const struct file_operations ubi_cdev_operations;
483extern const struct file_operations ubi_vol_cdev_operations; 484extern const struct file_operations ubi_vol_cdev_operations;
484extern struct class *ubi_class; 485extern struct class *ubi_class;
485extern struct mutex ubi_devices_mutex; 486extern struct mutex ubi_devices_mutex;
487extern struct blocking_notifier_head ubi_notifiers;
486 488
487/* vtbl.c */ 489/* vtbl.c */
488int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, 490int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -575,6 +577,16 @@ struct ubi_device *ubi_get_device(int ubi_num);
575void ubi_put_device(struct ubi_device *ubi); 577void ubi_put_device(struct ubi_device *ubi);
576struct ubi_device *ubi_get_by_major(int major); 578struct ubi_device *ubi_get_by_major(int major);
577int ubi_major2num(int major); 579int ubi_major2num(int major);
580int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
581 int ntype);
582int ubi_notify_all(struct ubi_device *ubi, int ntype,
583 struct notifier_block *nb);
584int ubi_enumerate_volumes(struct notifier_block *nb);
585
586/* kapi.c */
587void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
588void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
589 struct ubi_volume_info *vi);
578 590
579/* 591/*
580 * ubi_rb_for_each_entry - walk an RB-tree. 592 * ubi_rb_for_each_entry - walk an RB-tree.
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 8e8d6fae7a02..e151862a3a98 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)
358 ubi->vol_count += 1; 358 ubi->vol_count += 1;
359 spin_unlock(&ubi->volumes_lock); 359 spin_unlock(&ubi->volumes_lock);
360 360
361 ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
361 if (paranoid_check_volumes(ubi)) 362 if (paranoid_check_volumes(ubi))
362 dbg_err("check failed while creating volume %d", vol_id); 363 dbg_err("check failed while creating volume %d", vol_id);
363 return err; 364 return err;
@@ -466,6 +467,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
466 ubi->vol_count -= 1; 467 ubi->vol_count -= 1;
467 spin_unlock(&ubi->volumes_lock); 468 spin_unlock(&ubi->volumes_lock);
468 469
470 ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
469 if (!no_vtbl && paranoid_check_volumes(ubi)) 471 if (!no_vtbl && paranoid_check_volumes(ubi))
470 dbg_err("check failed while removing volume %d", vol_id); 472 dbg_err("check failed while removing volume %d", vol_id);
471 473
@@ -589,6 +591,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
589 (long long)vol->used_ebs * vol->usable_leb_size; 591 (long long)vol->used_ebs * vol->usable_leb_size;
590 } 592 }
591 593
594 ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
592 if (paranoid_check_volumes(ubi)) 595 if (paranoid_check_volumes(ubi))
593 dbg_err("check failed while re-sizing volume %d", vol_id); 596 dbg_err("check failed while re-sizing volume %d", vol_id);
594 return err; 597 return err;
@@ -635,6 +638,7 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
635 vol->name_len = re->new_name_len; 638 vol->name_len = re->new_name_len;
636 memcpy(vol->name, re->new_name, re->new_name_len + 1); 639 memcpy(vol->name, re->new_name, re->new_name_len + 1);
637 spin_unlock(&ubi->volumes_lock); 640 spin_unlock(&ubi->volumes_lock);
641 ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED);
638 } 642 }
639 } 643 }
640 644