diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/build.c | 100 | ||||
-rw-r--r-- | drivers/mtd/ubi/cdev.c | 1 | ||||
-rw-r--r-- | drivers/mtd/ubi/kapi.c | 108 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 12 | ||||
-rw-r--r-- | drivers/mtd/ubi/vmt.c | 4 |
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 | */ | ||
134 | int 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 | */ | ||
154 | int 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 | */ | ||
193 | int 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 | ||
896 | out_uif: | 985 | out_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 | */ | ||
36 | void 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 | } | ||
44 | EXPORT_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 | } |
56 | EXPORT_SYMBOL_GPL(ubi_get_device_info); | 67 | EXPORT_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 | */ |
63 | void ubi_get_volume_info(struct ubi_volume_desc *desc, | 75 | void 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 | */ | ||
97 | void 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 | } | ||
82 | EXPORT_SYMBOL_GPL(ubi_get_volume_info); | 102 | EXPORT_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) | |||
561 | EXPORT_SYMBOL_GPL(ubi_leb_unmap); | 581 | EXPORT_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 | } |
661 | EXPORT_SYMBOL_GPL(ubi_sync); | 681 | EXPORT_SYMBOL_GPL(ubi_sync); |
682 | |||
683 | BLOCKING_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 | */ | ||
701 | int 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 | } | ||
724 | EXPORT_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 | */ | ||
733 | int ubi_unregister_volume_notifier(struct notifier_block *nb) | ||
734 | { | ||
735 | return blocking_notifier_chain_unregister(&ubi_notifiers, nb); | ||
736 | } | ||
737 | EXPORT_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; | |||
483 | extern const struct file_operations ubi_vol_cdev_operations; | 484 | extern const struct file_operations ubi_vol_cdev_operations; |
484 | extern struct class *ubi_class; | 485 | extern struct class *ubi_class; |
485 | extern struct mutex ubi_devices_mutex; | 486 | extern struct mutex ubi_devices_mutex; |
487 | extern struct blocking_notifier_head ubi_notifiers; | ||
486 | 488 | ||
487 | /* vtbl.c */ | 489 | /* vtbl.c */ |
488 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | 490 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, |
@@ -575,6 +577,16 @@ struct ubi_device *ubi_get_device(int ubi_num); | |||
575 | void ubi_put_device(struct ubi_device *ubi); | 577 | void ubi_put_device(struct ubi_device *ubi); |
576 | struct ubi_device *ubi_get_by_major(int major); | 578 | struct ubi_device *ubi_get_by_major(int major); |
577 | int ubi_major2num(int major); | 579 | int ubi_major2num(int major); |
580 | int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, | ||
581 | int ntype); | ||
582 | int ubi_notify_all(struct ubi_device *ubi, int ntype, | ||
583 | struct notifier_block *nb); | ||
584 | int ubi_enumerate_volumes(struct notifier_block *nb); | ||
585 | |||
586 | /* kapi.c */ | ||
587 | void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di); | ||
588 | void 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 | ||