diff options
Diffstat (limited to 'drivers/mtd/ubi/eba.c')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index da4c79259f67..51bca035cd83 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -340,9 +340,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); - down_read(&ubi->fm_sem); + down_read(&ubi->fm_eba_sem); vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; - up_read(&ubi->fm_sem); + up_read(&ubi->fm_eba_sem); err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0); out_unlock: @@ -425,9 +425,10 @@ retry: ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d", pnum, vol_id, lnum); err = -EBADMSG; - } else + } else { err = -EINVAL; ubi_ro_mode(ubi); + } } goto out_free; } else if (err == UBI_IO_BITFLIPS) @@ -566,6 +567,7 @@ retry: new_pnum = ubi_wl_get_peb(ubi); if (new_pnum < 0) { ubi_free_vid_hdr(ubi, vid_hdr); + up_read(&ubi->fm_eba_sem); return new_pnum; } @@ -576,13 +578,16 @@ retry: if (err && err != UBI_IO_BITFLIPS) { if (err > 0) err = -EIO; + up_read(&ubi->fm_eba_sem); goto out_put; } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); - if (err) + if (err) { + up_read(&ubi->fm_eba_sem); goto write_error; + } data_size = offset + len; mutex_lock(&ubi->buf_mutex); @@ -591,8 +596,10 @@ retry: /* Read everything before the area where the write failure happened */ if (offset > 0) { err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset); - if (err && err != UBI_IO_BITFLIPS) + if (err && err != UBI_IO_BITFLIPS) { + up_read(&ubi->fm_eba_sem); goto out_unlock; + } } memcpy(ubi->peb_buf + offset, buf, len); @@ -600,15 +607,15 @@ retry: err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size); if (err) { mutex_unlock(&ubi->buf_mutex); + up_read(&ubi->fm_eba_sem); goto write_error; } mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); - down_read(&ubi->fm_sem); vol->eba_tbl[lnum] = new_pnum; - up_read(&ubi->fm_sem); + up_read(&ubi->fm_eba_sem); ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); ubi_msg(ubi, "data was successfully recovered"); @@ -703,6 +710,7 @@ retry: if (pnum < 0) { ubi_free_vid_hdr(ubi, vid_hdr); leb_write_unlock(ubi, vol_id, lnum); + up_read(&ubi->fm_eba_sem); return pnum; } @@ -713,6 +721,7 @@ retry: if (err) { ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } @@ -721,13 +730,13 @@ retry: if (err) { ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } } - down_read(&ubi->fm_sem); vol->eba_tbl[lnum] = pnum; - up_read(&ubi->fm_sem); + up_read(&ubi->fm_eba_sem); leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); @@ -824,6 +833,7 @@ retry: if (pnum < 0) { ubi_free_vid_hdr(ubi, vid_hdr); leb_write_unlock(ubi, vol_id, lnum); + up_read(&ubi->fm_eba_sem); return pnum; } @@ -834,6 +844,7 @@ retry: if (err) { ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } @@ -841,13 +852,13 @@ retry: if (err) { ubi_warn(ubi, "failed to write %d bytes of data to PEB %d", len, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } ubi_assert(vol->eba_tbl[lnum] < 0); - down_read(&ubi->fm_sem); vol->eba_tbl[lnum] = pnum; - up_read(&ubi->fm_sem); + up_read(&ubi->fm_eba_sem); leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); @@ -899,7 +910,7 @@ write_error: int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, const void *buf, int len) { - int err, pnum, tries = 0, vol_id = vol->vol_id; + int err, pnum, old_pnum, tries = 0, vol_id = vol->vol_id; struct ubi_vid_hdr *vid_hdr; uint32_t crc; @@ -942,6 +953,7 @@ retry: pnum = ubi_wl_get_peb(ubi); if (pnum < 0) { err = pnum; + up_read(&ubi->fm_eba_sem); goto out_leb_unlock; } @@ -952,6 +964,7 @@ retry: if (err) { ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } @@ -959,19 +972,20 @@ retry: if (err) { ubi_warn(ubi, "failed to write %d bytes of data to PEB %d", len, pnum); + up_read(&ubi->fm_eba_sem); goto write_error; } - if (vol->eba_tbl[lnum] >= 0) { - err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0); + old_pnum = vol->eba_tbl[lnum]; + vol->eba_tbl[lnum] = pnum; + up_read(&ubi->fm_eba_sem); + + if (old_pnum >= 0) { + err = ubi_wl_put_peb(ubi, vol_id, lnum, old_pnum, 0); if (err) goto out_leb_unlock; } - down_read(&ubi->fm_sem); - vol->eba_tbl[lnum] = pnum; - up_read(&ubi->fm_sem); - out_leb_unlock: leb_write_unlock(ubi, vol_id, lnum); out_mutex: @@ -1217,9 +1231,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, } ubi_assert(vol->eba_tbl[lnum] == from); - down_read(&ubi->fm_sem); + down_read(&ubi->fm_eba_sem); vol->eba_tbl[lnum] = to; - up_read(&ubi->fm_sem); + up_read(&ubi->fm_eba_sem); out_unlock_buf: mutex_unlock(&ubi->buf_mutex); @@ -1418,7 +1432,8 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai) * during re-size. */ ubi_move_aeb_to_list(av, aeb, &ai->erase); - vol->eba_tbl[aeb->lnum] = aeb->pnum; + else + vol->eba_tbl[aeb->lnum] = aeb->pnum; } } |