aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/build.c
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/build.c
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/build.c')
-rw-r--r--drivers/mtd/ubi/build.c100
1 files changed, 95 insertions, 5 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 /*