diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-05-05 04:24:02 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-07-18 09:52:32 -0400 |
commit | 78d87c95b89ccf86c142494beada3082810ed368 (patch) | |
tree | bb2bc3d2b11e2990376d25e13c94aeb50380a0c4 /drivers/mtd | |
parent | c4e90ec0134d7bedebbe3fe58ed5d431293886d4 (diff) |
UBI: fix error path in create_vtbl()
There were several bugs in volume table creation error path. Thanks to
Satyam Sharma <satyam.sharma@gmail.com> and Florin Malita <fmalita@gmail.com>
for finding and analysing them: http://lkml.org/lkml/2007/5/3/274
This patch makes ubi_scan_add_to_list() static and renames it to
add_to_list(), just because it is not needed outside scan.c anymore.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/scan.c | 46 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.h | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/vtbl.c | 14 |
3 files changed, 35 insertions, 27 deletions
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index e4456869e753..30d536ee10fc 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c | |||
@@ -24,7 +24,7 @@ | |||
24 | * This unit is responsible for scanning the flash media, checking UBI | 24 | * This unit is responsible for scanning the flash media, checking UBI |
25 | * headers and providing complete information about the UBI flash image. | 25 | * headers and providing complete information about the UBI flash image. |
26 | * | 26 | * |
27 | * The scanning information is reoresented by a &struct ubi_scan_info' object. | 27 | * The scanning information is represented by a &struct ubi_scan_info' object. |
28 | * Information about found volumes is represented by &struct ubi_scan_volume | 28 | * Information about found volumes is represented by &struct ubi_scan_volume |
29 | * objects which are kept in volume RB-tree with root at the @volumes field. | 29 | * objects which are kept in volume RB-tree with root at the @volumes field. |
30 | * The RB-tree is indexed by the volume ID. | 30 | * The RB-tree is indexed by the volume ID. |
@@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi, | |||
55 | static struct ubi_ec_hdr *ech; | 55 | static struct ubi_ec_hdr *ech; |
56 | static struct ubi_vid_hdr *vidh; | 56 | static struct ubi_vid_hdr *vidh; |
57 | 57 | ||
58 | int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, | 58 | /* |
59 | struct list_head *list) | 59 | * add_to_list - add physical eraseblock to a list. |
60 | * @si: scanning information | ||
61 | * @pnum: physical eraseblock number to add | ||
62 | * @ec: erase counter of the physical eraseblock | ||
63 | * @list: the list to add to | ||
64 | * | ||
65 | * This function adds physical eraseblock @pnum to free, erase, corrupted or | ||
66 | * alien lists. Returns zero in case of success and a negative error code in | ||
67 | * case of failure. | ||
68 | */ | ||
69 | static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, | ||
70 | struct list_head *list) | ||
60 | { | 71 | { |
61 | struct ubi_scan_leb *seb; | 72 | struct ubi_scan_leb *seb; |
62 | 73 | ||
@@ -492,11 +503,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, | |||
492 | return err; | 503 | return err; |
493 | 504 | ||
494 | if (cmp_res & 4) | 505 | if (cmp_res & 4) |
495 | err = ubi_scan_add_to_list(si, seb->pnum, | 506 | err = add_to_list(si, seb->pnum, seb->ec, |
496 | seb->ec, &si->corr); | 507 | &si->corr); |
497 | else | 508 | else |
498 | err = ubi_scan_add_to_list(si, seb->pnum, | 509 | err = add_to_list(si, seb->pnum, seb->ec, |
499 | seb->ec, &si->erase); | 510 | &si->erase); |
500 | if (err) | 511 | if (err) |
501 | return err; | 512 | return err; |
502 | 513 | ||
@@ -517,11 +528,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, | |||
517 | * previously. | 528 | * previously. |
518 | */ | 529 | */ |
519 | if (cmp_res & 4) | 530 | if (cmp_res & 4) |
520 | return ubi_scan_add_to_list(si, pnum, ec, | 531 | return add_to_list(si, pnum, ec, &si->corr); |
521 | &si->corr); | ||
522 | else | 532 | else |
523 | return ubi_scan_add_to_list(si, pnum, ec, | 533 | return add_to_list(si, pnum, ec, &si->erase); |
524 | &si->erase); | ||
525 | } | 534 | } |
526 | } | 535 | } |
527 | 536 | ||
@@ -754,7 +763,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, | |||
754 | * @si: scanning information | 763 | * @si: scanning information |
755 | * @pnum: the physical eraseblock number | 764 | * @pnum: the physical eraseblock number |
756 | * | 765 | * |
757 | * This function returns a zero if the physical eraseblock was succesfully | 766 | * This function returns a zero if the physical eraseblock was successfully |
758 | * handled and a negative error code in case of failure. | 767 | * handled and a negative error code in case of failure. |
759 | */ | 768 | */ |
760 | static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) | 769 | static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) |
@@ -783,8 +792,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
783 | else if (err == UBI_IO_BITFLIPS) | 792 | else if (err == UBI_IO_BITFLIPS) |
784 | bitflips = 1; | 793 | bitflips = 1; |
785 | else if (err == UBI_IO_PEB_EMPTY) | 794 | else if (err == UBI_IO_PEB_EMPTY) |
786 | return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, | 795 | return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); |
787 | &si->erase); | ||
788 | else if (err == UBI_IO_BAD_EC_HDR) { | 796 | else if (err == UBI_IO_BAD_EC_HDR) { |
789 | /* | 797 | /* |
790 | * We have to also look at the VID header, possibly it is not | 798 | * We have to also look at the VID header, possibly it is not |
@@ -832,13 +840,13 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
832 | else if (err == UBI_IO_BAD_VID_HDR || | 840 | else if (err == UBI_IO_BAD_VID_HDR || |
833 | (err == UBI_IO_PEB_FREE && ec_corr)) { | 841 | (err == UBI_IO_PEB_FREE && ec_corr)) { |
834 | /* VID header is corrupted */ | 842 | /* VID header is corrupted */ |
835 | err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); | 843 | err = add_to_list(si, pnum, ec, &si->corr); |
836 | if (err) | 844 | if (err) |
837 | return err; | 845 | return err; |
838 | goto adjust_mean_ec; | 846 | goto adjust_mean_ec; |
839 | } else if (err == UBI_IO_PEB_FREE) { | 847 | } else if (err == UBI_IO_PEB_FREE) { |
840 | /* No VID header - the physical eraseblock is free */ | 848 | /* No VID header - the physical eraseblock is free */ |
841 | err = ubi_scan_add_to_list(si, pnum, ec, &si->free); | 849 | err = add_to_list(si, pnum, ec, &si->free); |
842 | if (err) | 850 | if (err) |
843 | return err; | 851 | return err; |
844 | goto adjust_mean_ec; | 852 | goto adjust_mean_ec; |
@@ -853,7 +861,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
853 | case UBI_COMPAT_DELETE: | 861 | case UBI_COMPAT_DELETE: |
854 | ubi_msg("\"delete\" compatible internal volume %d:%d" | 862 | ubi_msg("\"delete\" compatible internal volume %d:%d" |
855 | " found, remove it", vol_id, lnum); | 863 | " found, remove it", vol_id, lnum); |
856 | err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); | 864 | err = add_to_list(si, pnum, ec, &si->corr); |
857 | if (err) | 865 | if (err) |
858 | return err; | 866 | return err; |
859 | break; | 867 | break; |
@@ -868,7 +876,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
868 | case UBI_COMPAT_PRESERVE: | 876 | case UBI_COMPAT_PRESERVE: |
869 | ubi_msg("\"preserve\" compatible internal volume %d:%d" | 877 | ubi_msg("\"preserve\" compatible internal volume %d:%d" |
870 | " found", vol_id, lnum); | 878 | " found", vol_id, lnum); |
871 | err = ubi_scan_add_to_list(si, pnum, ec, &si->alien); | 879 | err = add_to_list(si, pnum, ec, &si->alien); |
872 | if (err) | 880 | if (err) |
873 | return err; | 881 | return err; |
874 | si->alien_peb_count += 1; | 882 | si->alien_peb_count += 1; |
@@ -1109,7 +1117,7 @@ static int paranoid_check_si(const struct ubi_device *ubi, | |||
1109 | uint8_t *buf; | 1117 | uint8_t *buf; |
1110 | 1118 | ||
1111 | /* | 1119 | /* |
1112 | * At first, check that scanning information is ok. | 1120 | * At first, check that scanning information is OK. |
1113 | */ | 1121 | */ |
1114 | ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { | 1122 | ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { |
1115 | int leb_count = 0; | 1123 | int leb_count = 0; |
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 3949f6192c76..140e82e26534 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h | |||
@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, | |||
147 | list_add_tail(&seb->u.list, list); | 147 | list_add_tail(&seb->u.list, list); |
148 | } | 148 | } |
149 | 149 | ||
150 | int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, | ||
151 | struct list_head *list); | ||
152 | int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, | 150 | int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, |
153 | int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, | 151 | int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, |
154 | int bitflips); | 152 | int bitflips); |
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 83236c31c892..9926f1f9aad8 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
@@ -317,13 +317,15 @@ retry: | |||
317 | return err; | 317 | return err; |
318 | 318 | ||
319 | write_error: | 319 | write_error: |
320 | /* Maybe this physical eraseblock went bad, try to pick another one */ | 320 | if (err == -EIO && ++tries <= 5) { |
321 | if (++tries <= 5) | 321 | /* |
322 | err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec, | 322 | * Probably this physical eraseblock went bad, try to pick |
323 | &si->corr); | 323 | * another one. |
324 | kfree(new_seb); | 324 | */ |
325 | if (!err) | 325 | list_add_tail(&new_seb->u.list, &si->corr); |
326 | goto retry; | 326 | goto retry; |
327 | } | ||
328 | kfree(new_seb); | ||
327 | out_free: | 329 | out_free: |
328 | ubi_free_vid_hdr(ubi, vid_hdr); | 330 | ubi_free_vid_hdr(ubi, vid_hdr); |
329 | return err; | 331 | return err; |