diff options
| -rw-r--r-- | drivers/mtd/ubi/wl.c | 89 |
1 files changed, 48 insertions, 41 deletions
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index d512cf16350d..9de953762097 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c | |||
| @@ -1060,9 +1060,8 @@ out_unlock: | |||
| 1060 | static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | 1060 | static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, |
| 1061 | int cancel) | 1061 | int cancel) |
| 1062 | { | 1062 | { |
| 1063 | int err; | ||
| 1064 | struct ubi_wl_entry *e = wl_wrk->e; | 1063 | struct ubi_wl_entry *e = wl_wrk->e; |
| 1065 | int pnum = e->pnum; | 1064 | int pnum = e->pnum, err, need; |
| 1066 | 1065 | ||
| 1067 | if (cancel) { | 1066 | if (cancel) { |
| 1068 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); | 1067 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); |
| @@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
| 1097 | kfree(wl_wrk); | 1096 | kfree(wl_wrk); |
| 1098 | kmem_cache_free(wl_entries_slab, e); | 1097 | kmem_cache_free(wl_entries_slab, e); |
| 1099 | 1098 | ||
| 1100 | if (err != -EIO) { | 1099 | if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || |
| 1100 | err == -EBUSY) { | ||
| 1101 | int err1; | ||
| 1102 | |||
| 1103 | /* Re-schedule the LEB for erasure */ | ||
| 1104 | err1 = schedule_erase(ubi, e, 0); | ||
| 1105 | if (err1) { | ||
| 1106 | err = err1; | ||
| 1107 | goto out_ro; | ||
| 1108 | } | ||
| 1109 | return err; | ||
| 1110 | } else if (err != -EIO) { | ||
| 1101 | /* | 1111 | /* |
| 1102 | * If this is not %-EIO, we have no idea what to do. Scheduling | 1112 | * If this is not %-EIO, we have no idea what to do. Scheduling |
| 1103 | * this physical eraseblock for erasure again would cause | 1113 | * this physical eraseblock for erasure again would cause |
| 1104 | * errors again and again. Well, lets switch to RO mode. | 1114 | * errors again and again. Well, lets switch to RO mode. |
| 1105 | */ | 1115 | */ |
| 1106 | ubi_ro_mode(ubi); | 1116 | goto out_ro; |
| 1107 | return err; | ||
| 1108 | } | 1117 | } |
| 1109 | 1118 | ||
| 1110 | /* It is %-EIO, the PEB went bad */ | 1119 | /* It is %-EIO, the PEB went bad */ |
| 1111 | 1120 | ||
| 1112 | if (!ubi->bad_allowed) { | 1121 | if (!ubi->bad_allowed) { |
| 1113 | ubi_err("bad physical eraseblock %d detected", pnum); | 1122 | ubi_err("bad physical eraseblock %d detected", pnum); |
| 1114 | ubi_ro_mode(ubi); | 1123 | goto out_ro; |
| 1115 | err = -EIO; | 1124 | } |
| 1116 | } else { | ||
| 1117 | int need; | ||
| 1118 | |||
| 1119 | spin_lock(&ubi->volumes_lock); | ||
| 1120 | need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; | ||
| 1121 | if (need > 0) { | ||
| 1122 | need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; | ||
| 1123 | ubi->avail_pebs -= need; | ||
| 1124 | ubi->rsvd_pebs += need; | ||
| 1125 | ubi->beb_rsvd_pebs += need; | ||
| 1126 | if (need > 0) | ||
| 1127 | ubi_msg("reserve more %d PEBs", need); | ||
| 1128 | } | ||
| 1129 | 1125 | ||
| 1130 | if (ubi->beb_rsvd_pebs == 0) { | 1126 | spin_lock(&ubi->volumes_lock); |
| 1131 | spin_unlock(&ubi->volumes_lock); | 1127 | need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; |
| 1132 | ubi_err("no reserved physical eraseblocks"); | 1128 | if (need > 0) { |
| 1133 | ubi_ro_mode(ubi); | 1129 | need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; |
| 1134 | return -EIO; | 1130 | ubi->avail_pebs -= need; |
| 1135 | } | 1131 | ubi->rsvd_pebs += need; |
| 1132 | ubi->beb_rsvd_pebs += need; | ||
| 1133 | if (need > 0) | ||
| 1134 | ubi_msg("reserve more %d PEBs", need); | ||
| 1135 | } | ||
| 1136 | 1136 | ||
| 1137 | if (ubi->beb_rsvd_pebs == 0) { | ||
| 1137 | spin_unlock(&ubi->volumes_lock); | 1138 | spin_unlock(&ubi->volumes_lock); |
| 1138 | ubi_msg("mark PEB %d as bad", pnum); | 1139 | ubi_err("no reserved physical eraseblocks"); |
| 1140 | goto out_ro; | ||
| 1141 | } | ||
| 1139 | 1142 | ||
| 1140 | err = ubi_io_mark_bad(ubi, pnum); | 1143 | spin_unlock(&ubi->volumes_lock); |
| 1141 | if (err) { | 1144 | ubi_msg("mark PEB %d as bad", pnum); |
| 1142 | ubi_ro_mode(ubi); | ||
| 1143 | return err; | ||
| 1144 | } | ||
| 1145 | 1145 | ||
| 1146 | spin_lock(&ubi->volumes_lock); | 1146 | err = ubi_io_mark_bad(ubi, pnum); |
| 1147 | ubi->beb_rsvd_pebs -= 1; | 1147 | if (err) |
| 1148 | ubi->bad_peb_count += 1; | 1148 | goto out_ro; |
| 1149 | ubi->good_peb_count -= 1; | 1149 | |
| 1150 | ubi_calculate_reserved(ubi); | 1150 | spin_lock(&ubi->volumes_lock); |
| 1151 | if (ubi->beb_rsvd_pebs == 0) | 1151 | ubi->beb_rsvd_pebs -= 1; |
| 1152 | ubi_warn("last PEB from the reserved pool was used"); | 1152 | ubi->bad_peb_count += 1; |
| 1153 | spin_unlock(&ubi->volumes_lock); | 1153 | ubi->good_peb_count -= 1; |
| 1154 | } | 1154 | ubi_calculate_reserved(ubi); |
| 1155 | if (ubi->beb_rsvd_pebs == 0) | ||
| 1156 | ubi_warn("last PEB from the reserved pool was used"); | ||
| 1157 | spin_unlock(&ubi->volumes_lock); | ||
| 1158 | |||
| 1159 | return err; | ||
| 1155 | 1160 | ||
| 1161 | out_ro: | ||
| 1162 | ubi_ro_mode(ubi); | ||
| 1156 | return err; | 1163 | return err; |
| 1157 | } | 1164 | } |
| 1158 | 1165 | ||
