@@ -48,11 +48,18 @@ config MTD_UBI_BEB_LIMIT
default 2
range 0 25
help
- This option specifies the maximum bad physical eraseblocks UBI
- expects on the UBI device (percents of total number of physical
- eraseblocks on this MTD partition). If the underlying flash does not
- admit of bad eraseblocks (e.g. NOR flash), this value is ignored.
- Leave the default value if unsure.
+ If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI
+ reserves some amount of physical eraseblocks to handle new bad
+ eraseblocks. This option specifies the maximum bad physical
+ eraseblocks UBI expects on the UBI device (percents of total number
+ of physical eraseblocks on this MTD partition). If the device has
+ more bad eraseblocks than this limit, UBI does not reserve any more
+ physical eraseblocks for new bad eraseblocks, but attempts to use
+ available physical eraseblocks (if any), i.e., those ones which are
+ not reserved for any UBI volume.
+
+ If the underlying flash does not admit of bad eraseblocks (e.g. NOR
+ flash), this value is ignored. Leave the default value if unsure.
config MTD_UBI_GLUEBI
tristate "MTD devices emulation driver (gluebi)"
@@ -121,10 +121,18 @@ void ubi_update_reserved(struct ubi_device *ubi)
*/
void ubi_calculate_reserved(struct ubi_device *ubi)
{
- ubi->beb_rsvd_level = ubi->good_peb_count/100;
- ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE;
- if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS)
- ubi->beb_rsvd_level = MIN_RESEVED_PEBS;
+ /*
+ * Calculate the actual number of PEBs currently needed to be reserved
+ * for future bad eraseblock handling.
+ */
+ ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count;
+ if (ubi->beb_rsvd_level < 0) {
+ ubi->beb_rsvd_level = 0;
+ ubi_warn("number of bad PEBs (%d) is above the expected limit "
+ "(%d), not reserving any PEBs for bad PEB handling, "
+ "will use available PEBs (if any)",
+ ubi->bad_peb_count, ubi->bad_peb_limit);
+ }
}
/**
@@ -978,7 +978,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel)
{
struct ubi_wl_entry *e = wl_wrk->e;
- int pnum = e->pnum, err, need;
+ int pnum = e->pnum, err;
int vol_id = wl_wrk->vol_id;
int lnum = wl_wrk->lnum;
@@ -1044,40 +1044,32 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
goto out_ro;
}
- spin_lock(&ubi->volumes_lock);
- need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
- if (need > 0) {
- need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
- ubi->avail_pebs -= need;
- ubi->rsvd_pebs += need;
- ubi->beb_rsvd_pebs += need;
- if (need > 0)
- ubi_msg("reserve more %d PEBs", need);
- }
-
- if (ubi->beb_rsvd_pebs == 0) {
- spin_unlock(&ubi->volumes_lock);
- ubi_err("no reserved physical eraseblocks");
- goto out_ro;
- }
- spin_unlock(&ubi->volumes_lock);
-
ubi_msg("mark PEB %d as bad", pnum);
err = ubi_io_mark_bad(ubi, pnum);
if (err)
goto out_ro;
spin_lock(&ubi->volumes_lock);
- ubi->beb_rsvd_pebs -= 1;
+ if (ubi->beb_rsvd_pebs > 0) {
+ ubi->beb_rsvd_pebs -= 1;
+ } else if (ubi->beb_rsvd_pebs == 0) {
+ if (ubi->avail_pebs == 0) {
+ spin_unlock(&ubi->volumes_lock);
+ ubi_err("no reserved/available physical eraseblocks");
+ goto out_ro;
+ }
+ ubi->avail_pebs -= 1;
+ }
+
ubi->bad_peb_count += 1;
ubi->good_peb_count -= 1;
ubi_calculate_reserved(ubi);
+ spin_unlock(&ubi->volumes_lock);
+
if (ubi->beb_rsvd_pebs)
ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs);
else
- ubi_warn("last PEB from the reserved pool was used");
- spin_unlock(&ubi->volumes_lock);
-
+ ubi_warn("last PEB from the reserve was used");
return err;
out_ro: