aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Reardon <joel@clambassador.com>2012-05-20 15:27:11 -0400
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2012-05-21 04:34:41 -0400
commit62f384552b6756cf1ea71f8762d1e97dc77dbd90 (patch)
tree6ebd89f4f18eca1724e8a50b8fc6cdefc29de18a
parent05a3cb7dcec5a15ed9b18a5317ba2075355c7547 (diff)
UBI: modify ubi_wl_flush function to clear work queue for a lnum
This patch modifies ubi_wl_flush to force the erasure of particular volume id / logical eraseblock number pairs. Previous functionality is preserved when passing UBI_ALL for both values. The locations where ubi_wl_flush were called are appropriately changed: ubi_leb_erase only flushes for the erased LEB, and ubi_create_volume forces only flushing for its volume id. External code can call this new feature via the new function ubi_flush() added to kapi.c, which simply passes through to ubi_wl_flush(). This was tested by disabling the call to do_work in ubi thread, which results in the work queue remaining unless explicitly called to remove. UBIFS was changed to call ubifs_leb_change 50 times for four different LEBs. Then the new function was called to clear the queue: passing wrong volume ids / lnum, correct ones, and finally UBI_ALL for both to ensure it was finally all cleard. The work queue was dumped each time and the selective removal of the particular LEB numbers was observed. Extra checks were enabled and ubifs's integck was also run. Finally, the drive was repeatedly filled and emptied to ensure that the queue was cleared normally. Artem: amended the patch. Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
-rw-r--r--drivers/mtd/ubi/cdev.c2
-rw-r--r--drivers/mtd/ubi/kapi.c29
-rw-r--r--drivers/mtd/ubi/ubi.h2
-rw-r--r--drivers/mtd/ubi/upd.c4
-rw-r--r--drivers/mtd/ubi/vmt.c2
-rw-r--r--drivers/mtd/ubi/wl.c61
-rw-r--r--include/linux/mtd/ubi.h1
7 files changed, 70 insertions, 31 deletions
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 2364c00f66d0..acec85deb6af 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -514,7 +514,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
514 if (err) 514 if (err)
515 break; 515 break;
516 516
517 err = ubi_wl_flush(ubi); 517 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
518 break; 518 break;
519 } 519 }
520 520
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d76fe47477e5..3aac1acceeb4 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -551,7 +551,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
551 if (err) 551 if (err)
552 return err; 552 return err;
553 553
554 return ubi_wl_flush(ubi); 554 return ubi_wl_flush(ubi, vol->vol_id, lnum);
555} 555}
556EXPORT_SYMBOL_GPL(ubi_leb_erase); 556EXPORT_SYMBOL_GPL(ubi_leb_erase);
557 557
@@ -704,6 +704,33 @@ int ubi_sync(int ubi_num)
704} 704}
705EXPORT_SYMBOL_GPL(ubi_sync); 705EXPORT_SYMBOL_GPL(ubi_sync);
706 706
707/**
708 * ubi_flush - flush UBI work queue.
709 * @ubi_num: UBI device to flush work queue
710 * @vol_id: volume id to flush for
711 * @lnum: logical eraseblock number to flush for
712 *
713 * This function executes all pending works for a particular volume id / logical
714 * eraseblock number pair. If either value is set to %UBI_ALL, then it acts as
715 * a wildcard for all of the corresponding volume numbers or logical
716 * eraseblock numbers. It returns zero in case of success and a negative error
717 * code in case of failure.
718 */
719int ubi_flush(int ubi_num, int vol_id, int lnum)
720{
721 struct ubi_device *ubi;
722 int err = 0;
723
724 ubi = ubi_get_device(ubi_num);
725 if (!ubi)
726 return -ENODEV;
727
728 err = ubi_wl_flush(ubi, vol_id, lnum);
729 ubi_put_device(ubi);
730 return err;
731}
732EXPORT_SYMBOL_GPL(ubi_flush);
733
707BLOCKING_NOTIFIER_HEAD(ubi_notifiers); 734BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
708 735
709/** 736/**
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 38cfb0f2adf2..a1a81c9ea8ce 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -669,7 +669,7 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
669int ubi_wl_get_peb(struct ubi_device *ubi); 669int ubi_wl_get_peb(struct ubi_device *ubi);
670int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, 670int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
671 int pnum, int torture); 671 int pnum, int torture);
672int ubi_wl_flush(struct ubi_device *ubi); 672int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum);
673int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); 673int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
674int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai); 674int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
675void ubi_wl_close(struct ubi_device *ubi); 675void ubi_wl_close(struct ubi_device *ubi);
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 11a28f9ce0db..9f2ebd8750e7 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -147,7 +147,7 @@ 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); 150 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
151 if (err) 151 if (err)
152 return err; 152 return err;
153 153
@@ -361,7 +361,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
361 361
362 ubi_assert(vol->upd_received <= vol->upd_bytes); 362 ubi_assert(vol->upd_received <= vol->upd_bytes);
363 if (vol->upd_received == vol->upd_bytes) { 363 if (vol->upd_received == vol->upd_bytes) {
364 err = ubi_wl_flush(ubi); 364 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
365 if (err) 365 if (err)
366 return err; 366 return err;
367 /* The update is finished, clear the update marker */ 367 /* The update is finished, clear the update marker */
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index e4b897ab4543..0669cff8ac3c 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -280,7 +280,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
280 * Finish all pending erases because there may be some LEBs belonging 280 * Finish all pending erases because there may be some LEBs belonging
281 * to the same volume ID. 281 * to the same volume ID.
282 */ 282 */
283 err = ubi_wl_flush(ubi); 283 err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
284 if (err) 284 if (err)
285 goto out_acc; 285 goto out_acc;
286 286
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 70ebfa7bc384..9df100a4ec38 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1241,44 +1241,55 @@ retry:
1241/** 1241/**
1242 * ubi_wl_flush - flush all pending works. 1242 * ubi_wl_flush - flush all pending works.
1243 * @ubi: UBI device description object 1243 * @ubi: UBI device description object
1244 * @vol_id: the volume id to flush for
1245 * @lnum: the logical eraseblock number to flush for
1244 * 1246 *
1245 * This function returns zero in case of success and a negative error code in 1247 * This function executes all pending works for a particular volume id /
1246 * case of failure. 1248 * logical eraseblock number pair. If either value is set to %UBI_ALL, then it
1249 * acts as a wildcard for all of the corresponding volume numbers or logical
1250 * eraseblock numbers. It returns zero in case of success and a negative error
1251 * code in case of failure.
1247 */ 1252 */
1248int ubi_wl_flush(struct ubi_device *ubi) 1253int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum)
1249{ 1254{
1250 int err; 1255 int err = 0;
1256 int found = 1;
1251 1257
1252 /* 1258 /*
1253 * Erase while the pending works queue is not empty, but not more than 1259 * Erase while the pending works queue is not empty, but not more than
1254 * the number of currently pending works. 1260 * the number of currently pending works.
1255 */ 1261 */
1256 dbg_wl("flush (%d pending works)", ubi->works_count); 1262 dbg_wl("flush pending work for LEB %d:%d (%d pending works)",
1257 while (ubi->works_count) { 1263 vol_id, lnum, ubi->works_count);
1258 err = do_work(ubi);
1259 if (err)
1260 return err;
1261 }
1262 1264
1263 /*
1264 * Make sure all the works which have been done in parallel are
1265 * finished.
1266 */
1267 down_write(&ubi->work_sem); 1265 down_write(&ubi->work_sem);
1268 up_write(&ubi->work_sem); 1266 while (found) {
1267 struct ubi_work *wrk;
1268 found = 0;
1269 1269
1270 /* 1270 spin_lock(&ubi->wl_lock);
1271 * And in case last was the WL worker and it canceled the LEB 1271 list_for_each_entry(wrk, &ubi->works, list) {
1272 * movement, flush again. 1272 if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) &&
1273 */ 1273 (lnum == UBI_ALL || wrk->lnum == lnum)) {
1274 while (ubi->works_count) { 1274 list_del(&wrk->list);
1275 dbg_wl("flush more (%d pending works)", ubi->works_count); 1275 ubi->works_count -= 1;
1276 err = do_work(ubi); 1276 ubi_assert(ubi->works_count >= 0);
1277 if (err) 1277 spin_unlock(&ubi->wl_lock);
1278 return err; 1278
1279 err = wrk->func(ubi, wrk, 0);
1280 if (err)
1281 goto out;
1282 spin_lock(&ubi->wl_lock);
1283 found = 1;
1284 break;
1285 }
1286 }
1287 spin_unlock(&ubi->wl_lock);
1279 } 1288 }
1280 1289
1281 return 0; 1290out:
1291 up_write(&ubi->work_sem);
1292 return err;
1282} 1293}
1283 1294
1284/** 1295/**
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index f636f5df883f..c3918a0684fe 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -219,6 +219,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
219int ubi_leb_map(struct ubi_volume_desc *desc, int lnum); 219int ubi_leb_map(struct ubi_volume_desc *desc, int lnum);
220int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); 220int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
221int ubi_sync(int ubi_num); 221int ubi_sync(int ubi_num);
222int ubi_flush(int ubi_num, int vol_id, int lnum);
222 223
223/* 224/*
224 * This function is the same as the 'ubi_leb_read()' function, but it does not 225 * This function is the same as the 'ubi_leb_read()' function, but it does not