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>
This commit is contained in:
parent
c4e90ec013
commit
78d87c95b8
3 changed files with 35 additions and 27 deletions
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
* 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,
|
||||||
* @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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue