ubi: Make recover_peb power cut aware
[pandora-kernel.git] / drivers / mtd / ubi / eba.c
index 4be6718..910bf27 100644 (file)
@@ -443,7 +443,7 @@ retry:
                if (err == UBI_IO_BITFLIPS) {
                        scrub = 1;
                        err = 0;
-               } else if (err == -EBADMSG) {
+               } else if (mtd_is_eccerr(err)) {
                        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                                goto out_unlock;
                        scrub = 1;
@@ -501,6 +501,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
        int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
        struct ubi_volume *vol = ubi->volumes[idx];
        struct ubi_vid_hdr *vid_hdr;
+       uint32_t crc;
 
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
@@ -522,12 +523,8 @@ retry:
                goto out_put;
        }
 
-       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
-       err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
-       if (err)
-               goto write_error;
+       ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
 
-       data_size = offset + len;
        mutex_lock(&ubi->buf_mutex);
        memset(ubi->peb_buf1 + offset, 0xFF, len);
 
@@ -540,6 +537,18 @@ retry:
 
        memcpy(ubi->peb_buf1 + offset, buf, len);
 
+       data_size = offset + len;
+       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
+       vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+       vid_hdr->copy_flag = 1;
+       vid_hdr->data_size = cpu_to_be32(data_size);
+       vid_hdr->data_crc = cpu_to_be32(crc);
+       err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+       if (err) {
+               mutex_unlock(&ubi->buf_mutex);
+               goto write_error;
+       }
+
        err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
        if (err) {
                mutex_unlock(&ubi->buf_mutex);
@@ -1028,12 +1037,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
         * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
         * LEB is already locked, we just do not move it and return
-        * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later.
+        * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because
+        * we do not know the reasons of the contention - it may be just a
+        * normal I/O on this LEB, so we want to re-try.
         */
        err = leb_write_trylock(ubi, vol_id, lnum);
        if (err) {
                dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum);
-               return MOVE_CANCEL_RACE;
+               return MOVE_RETRY;
        }
 
        /*
@@ -1259,7 +1270,8 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                                 * during re-size.
                                 */
                                ubi_scan_move_to_list(sv, seb, &si->erase);
-                       vol->eba_tbl[seb->lnum] = seb->pnum;
+                       else
+                               vol->eba_tbl[seb->lnum] = seb->pnum;
                }
        }