aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <sebastian@breakpoint.cc>2009-11-29 13:46:02 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-12-04 00:47:11 -0500
commit6afaf8a484cbbfd2ccf58a4e5396d1f280469789 (patch)
treef32db3212e23a38c794df0c01fcf8505180ca51d /drivers/mtd/ubi
parent949cb6232d5fc9fa77cfa441418e12d6f9de163e (diff)
UBI: flush wl before clearing update marker
ubiupdatevol -t does the following: - ubi_start_update() - set_update_marker() - for all LEBs ubi_eba_unmap_leb() - clear_update_marker() - ubi_wl_flush() ubi_wl_flush() physically erases all PEB, once it returns all PEBs are empty. clear_update_marker() has the update marker written after return. If there is a power cut between the last two functions then the UBI volume has no longer the "update" marker set and may have some valid LEBs while some of them may be gone. If that volume in question happens to be a UBIFS volume, then mount will fail with |UBIFS error (pid 1361): ubifs_read_node: bad node type (255 but expected 6) |UBIFS error (pid 1361): ubifs_read_node: bad node at LEB 0:0 |Not a node, first 24 bytes: |00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff if there is at least one valid LEB and the wear-leveling worker managed to clear LEB 0. The patch waits for the wl worker to finish prior clearing the "update" marker on flash. The two new LEB which are scheduled for erasing after clear_update_marker() should not matter because they are only visible to UBI. Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Cc: stable@kernel.org
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r--drivers/mtd/ubi/upd.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 74fdc40c8627..c1d7b880c795 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -147,12 +147,14 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
147 } 147 }
148 148
149 if (bytes == 0) { 149 if (bytes == 0) {
150 err = ubi_wl_flush(ubi);
151 if (err)
152 return err;
153
150 err = clear_update_marker(ubi, vol, 0); 154 err = clear_update_marker(ubi, vol, 0);
151 if (err) 155 if (err)
152 return err; 156 return err;
153 err = ubi_wl_flush(ubi); 157 vol->updating = 0;
154 if (!err)
155 vol->updating = 0;
156 } 158 }
157 159
158 vol->upd_buf = vmalloc(ubi->leb_size); 160 vol->upd_buf = vmalloc(ubi->leb_size);
@@ -362,16 +364,16 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
362 364
363 ubi_assert(vol->upd_received <= vol->upd_bytes); 365 ubi_assert(vol->upd_received <= vol->upd_bytes);
364 if (vol->upd_received == vol->upd_bytes) { 366 if (vol->upd_received == vol->upd_bytes) {
367 err = ubi_wl_flush(ubi);
368 if (err)
369 return err;
365 /* The update is finished, clear the update marker */ 370 /* The update is finished, clear the update marker */
366 err = clear_update_marker(ubi, vol, vol->upd_bytes); 371 err = clear_update_marker(ubi, vol, vol->upd_bytes);
367 if (err) 372 if (err)
368 return err; 373 return err;
369 err = ubi_wl_flush(ubi); 374 vol->updating = 0;
370 if (err == 0) { 375 err = to_write;
371 vol->updating = 0; 376 vfree(vol->upd_buf);
372 err = to_write;
373 vfree(vol->upd_buf);
374 }
375 } 377 }
376 378
377 return err; 379 return err;