| From 972228d87445dc46c0a01f5f3de673ac017626f7 Mon Sep 17 00:00:00 2001 |
| From: Richard Weinberger <richard@nod.at> |
| Date: Tue, 21 Jun 2016 00:31:50 +0200 |
| Subject: ubi: Make recover_peb power cut aware |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Richard Weinberger <richard@nod.at> |
| |
| commit 972228d87445dc46c0a01f5f3de673ac017626f7 upstream. |
| |
| recover_peb() was never power cut aware, |
| if a power cut happened right after writing the VID header |
| upon next attach UBI would blindly use the new partial written |
| PEB and all data from the old PEB is lost. |
| |
| In order to make recover_peb() power cut aware, write the new |
| VID with a proper crc and copy_flag set such that the UBI attach |
| process will detect whether the new PEB is completely written |
| or not. |
| We cannot directly use ubi_eba_atomic_leb_change() since we'd |
| have to unlock the LEB which is facing a write error. |
| |
| Reported-by: Jörg Pfähler <pfaehler@isse.de> |
| Reviewed-by: Jörg Pfähler <pfaehler@isse.de> |
| Signed-off-by: Richard Weinberger <richard@nod.at> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/mtd/ubi/eba.c | 22 +++++++++++++++------- |
| 1 file changed, 15 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/mtd/ubi/eba.c |
| +++ b/drivers/mtd/ubi/eba.c |
| @@ -575,6 +575,7 @@ static int recover_peb(struct ubi_device |
| 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) |
| @@ -599,14 +600,8 @@ retry: |
| 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) { |
| - up_read(&ubi->fm_eba_sem); |
| - goto write_error; |
| - } |
| + ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC); |
| |
| - data_size = offset + len; |
| mutex_lock(&ubi->buf_mutex); |
| memset(ubi->peb_buf + offset, 0xFF, len); |
| |
| @@ -621,6 +616,19 @@ retry: |
| |
| memcpy(ubi->peb_buf + offset, buf, len); |
| |
| + data_size = offset + len; |
| + crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size); |
| + vid_hdr->sqnum = cpu_to_be64(ubi_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); |
| + up_read(&ubi->fm_eba_sem); |
| + goto write_error; |
| + } |
| + |
| err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size); |
| if (err) { |
| mutex_unlock(&ubi->buf_mutex); |