Commit 78d87c95 authored by Artem Bityutskiy's avatar Artem Bityutskiy

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: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent c4e90ec0
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* This unit is responsible for scanning the flash media, checking UBI * This unit is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image. * headers and providing complete information about the UBI flash image.
* *
* The scanning information is reoresented by a &struct ubi_scan_info' object. * The scanning information is represented by a &struct ubi_scan_info' object.
* Information about found volumes is represented by &struct ubi_scan_volume * Information about found volumes is represented by &struct ubi_scan_volume
* objects which are kept in volume RB-tree with root at the @volumes field. * objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID. * The RB-tree is indexed by the volume ID.
...@@ -55,7 +55,18 @@ static int paranoid_check_si(const struct ubi_device *ubi, ...@@ -55,7 +55,18 @@ static int paranoid_check_si(const struct ubi_device *ubi,
static struct ubi_ec_hdr *ech; static struct ubi_ec_hdr *ech;
static struct ubi_vid_hdr *vidh; static struct ubi_vid_hdr *vidh;
int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec, /*
* add_to_list - add physical eraseblock to a list.
* @si: scanning information
* @pnum: physical eraseblock number to add
* @ec: erase counter of the physical eraseblock
* @list: the list to add to
*
* This function adds physical eraseblock @pnum to free, erase, corrupted or
* alien lists. Returns zero in case of success and a negative error code in
* case of failure.
*/
static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
struct list_head *list) struct list_head *list)
{ {
struct ubi_scan_leb *seb; struct ubi_scan_leb *seb;
...@@ -492,11 +503,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -492,11 +503,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
return err; return err;
if (cmp_res & 4) if (cmp_res & 4)
err = ubi_scan_add_to_list(si, seb->pnum, err = add_to_list(si, seb->pnum, seb->ec,
seb->ec, &si->corr); &si->corr);
else else
err = ubi_scan_add_to_list(si, seb->pnum, err = add_to_list(si, seb->pnum, seb->ec,
seb->ec, &si->erase); &si->erase);
if (err) if (err)
return err; return err;
...@@ -517,11 +528,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -517,11 +528,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
* previously. * previously.
*/ */
if (cmp_res & 4) if (cmp_res & 4)
return ubi_scan_add_to_list(si, pnum, ec, return add_to_list(si, pnum, ec, &si->corr);
&si->corr);
else else
return ubi_scan_add_to_list(si, pnum, ec, return add_to_list(si, pnum, ec, &si->erase);
&si->erase);
} }
} }
...@@ -754,7 +763,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, ...@@ -754,7 +763,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
* @si: scanning information * @si: scanning information
* @pnum: the physical eraseblock number * @pnum: the physical eraseblock number
* *
* This function returns a zero if the physical eraseblock was succesfully * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure. * handled and a negative error code in case of failure.
*/ */
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) 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,8 +792,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BITFLIPS) else if (err == UBI_IO_BITFLIPS)
bitflips = 1; bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY) else if (err == UBI_IO_PEB_EMPTY)
return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
&si->erase);
else if (err == UBI_IO_BAD_EC_HDR) { else if (err == UBI_IO_BAD_EC_HDR) {
/* /*
* We have to also look at the VID header, possibly it is not * 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,13 +840,13 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BAD_VID_HDR || else if (err == UBI_IO_BAD_VID_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) { (err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */ /* VID header is corrupted */
err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); err = add_to_list(si, pnum, ec, &si->corr);
if (err) if (err)
return err; return err;
goto adjust_mean_ec; goto adjust_mean_ec;
} else if (err == UBI_IO_PEB_FREE) { } else if (err == UBI_IO_PEB_FREE) {
/* No VID header - the physical eraseblock is free */ /* No VID header - the physical eraseblock is free */
err = ubi_scan_add_to_list(si, pnum, ec, &si->free); err = add_to_list(si, pnum, ec, &si->free);
if (err) if (err)
return err; return err;
goto adjust_mean_ec; goto adjust_mean_ec;
...@@ -853,7 +861,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum ...@@ -853,7 +861,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
case UBI_COMPAT_DELETE: case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d" ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, remove it", vol_id, lnum); " found, remove it", vol_id, lnum);
err = ubi_scan_add_to_list(si, pnum, ec, &si->corr); err = add_to_list(si, pnum, ec, &si->corr);
if (err) if (err)
return err; return err;
break; break;
...@@ -868,7 +876,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum ...@@ -868,7 +876,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
case UBI_COMPAT_PRESERVE: case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d" ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum); " found", vol_id, lnum);
err = ubi_scan_add_to_list(si, pnum, ec, &si->alien); err = add_to_list(si, pnum, ec, &si->alien);
if (err) if (err)
return err; return err;
si->alien_peb_count += 1; si->alien_peb_count += 1;
...@@ -1109,7 +1117,7 @@ static int paranoid_check_si(const struct ubi_device *ubi, ...@@ -1109,7 +1117,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
uint8_t *buf; uint8_t *buf;
/* /*
* At first, check that scanning information is ok. * At first, check that scanning information is OK.
*/ */
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
int leb_count = 0; int leb_count = 0;
......
...@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, ...@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list); list_add_tail(&seb->u.list, list);
} }
int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
struct list_head *list);
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips); int bitflips);
......
...@@ -317,13 +317,15 @@ retry: ...@@ -317,13 +317,15 @@ retry:
return err; return err;
write_error: write_error:
/* Maybe this physical eraseblock went bad, try to pick another one */ if (err == -EIO && ++tries <= 5) {
if (++tries <= 5) /*
err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec, * Probably this physical eraseblock went bad, try to pick
&si->corr); * another one.
kfree(new_seb); */
if (!err) list_add_tail(&new_seb->u.list, &si->corr);
goto retry; goto retry;
}
kfree(new_seb);
out_free: out_free:
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment