diff options
author | Joel Reardon <joel@clambassador.com> | 2012-05-18 09:40:24 -0400 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-05-21 04:34:41 -0400 |
commit | d36e59e69b8be536c55d6118630f0221cee5ccee (patch) | |
tree | 8ffa8feec4ddbfeca391278c449c5ba1b3e78d2e /drivers/mtd | |
parent | 6dd3bc7e6032ffb392477fadca77172c1c9e346b (diff) |
UBI: add lnum and vol_id to struct ubi_work
This is part of a multipart patch to allow UBI to force the erasure of
particular logical eraseblock numbers. In this patch, the volume id and LEB
number are added to ubi_work data structure, and both are also passed as a
parameter to schedule erase to set it appropriately. Whenever ubi_wl_put_peb
is called, the lnum is also passed to be forwarded to schedule erase. Later,
a new ubi_sync_lnum will be added to execute immediately all work related to
that lnum.
This was tested by outputting the vol_id and lnum during the schedule of
erasure. The ubi thread was disabled and two ubifs drives on separate
partitions repeated changed a small number of LEBs. The ubi module was readded,
and all the erased LEBs, corresponding to the volumes, were added to the
schedule erase queue.
Artem: minor tweaks
Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 16 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 3 | ||||
-rw-r--r-- | drivers/mtd/ubi/wl.c | 32 |
3 files changed, 33 insertions, 18 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 5fa726f9c1f..b703ac7729c 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -341,7 +341,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, | |||
341 | dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); | 341 | dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); |
342 | 342 | ||
343 | vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; | 343 | vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; |
344 | err = ubi_wl_put_peb(ubi, pnum, 0); | 344 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0); |
345 | 345 | ||
346 | out_unlock: | 346 | out_unlock: |
347 | leb_write_unlock(ubi, vol_id, lnum); | 347 | leb_write_unlock(ubi, vol_id, lnum); |
@@ -550,7 +550,7 @@ retry: | |||
550 | ubi_free_vid_hdr(ubi, vid_hdr); | 550 | ubi_free_vid_hdr(ubi, vid_hdr); |
551 | 551 | ||
552 | vol->eba_tbl[lnum] = new_pnum; | 552 | vol->eba_tbl[lnum] = new_pnum; |
553 | ubi_wl_put_peb(ubi, pnum, 1); | 553 | ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); |
554 | 554 | ||
555 | ubi_msg("data was successfully recovered"); | 555 | ubi_msg("data was successfully recovered"); |
556 | return 0; | 556 | return 0; |
@@ -558,7 +558,7 @@ retry: | |||
558 | out_unlock: | 558 | out_unlock: |
559 | mutex_unlock(&ubi->buf_mutex); | 559 | mutex_unlock(&ubi->buf_mutex); |
560 | out_put: | 560 | out_put: |
561 | ubi_wl_put_peb(ubi, new_pnum, 1); | 561 | ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); |
562 | ubi_free_vid_hdr(ubi, vid_hdr); | 562 | ubi_free_vid_hdr(ubi, vid_hdr); |
563 | return err; | 563 | return err; |
564 | 564 | ||
@@ -568,7 +568,7 @@ write_error: | |||
568 | * get another one. | 568 | * get another one. |
569 | */ | 569 | */ |
570 | ubi_warn("failed to write to PEB %d", new_pnum); | 570 | ubi_warn("failed to write to PEB %d", new_pnum); |
571 | ubi_wl_put_peb(ubi, new_pnum, 1); | 571 | ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); |
572 | if (++tries > UBI_IO_RETRIES) { | 572 | if (++tries > UBI_IO_RETRIES) { |
573 | ubi_free_vid_hdr(ubi, vid_hdr); | 573 | ubi_free_vid_hdr(ubi, vid_hdr); |
574 | return err; | 574 | return err; |
@@ -686,7 +686,7 @@ write_error: | |||
686 | * eraseblock, so just put it and request a new one. We assume that if | 686 | * eraseblock, so just put it and request a new one. We assume that if |
687 | * this physical eraseblock went bad, the erase code will handle that. | 687 | * this physical eraseblock went bad, the erase code will handle that. |
688 | */ | 688 | */ |
689 | err = ubi_wl_put_peb(ubi, pnum, 1); | 689 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); |
690 | if (err || ++tries > UBI_IO_RETRIES) { | 690 | if (err || ++tries > UBI_IO_RETRIES) { |
691 | ubi_ro_mode(ubi); | 691 | ubi_ro_mode(ubi); |
692 | leb_write_unlock(ubi, vol_id, lnum); | 692 | leb_write_unlock(ubi, vol_id, lnum); |
@@ -804,7 +804,7 @@ write_error: | |||
804 | return err; | 804 | return err; |
805 | } | 805 | } |
806 | 806 | ||
807 | err = ubi_wl_put_peb(ubi, pnum, 1); | 807 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); |
808 | if (err || ++tries > UBI_IO_RETRIES) { | 808 | if (err || ++tries > UBI_IO_RETRIES) { |
809 | ubi_ro_mode(ubi); | 809 | ubi_ro_mode(ubi); |
810 | leb_write_unlock(ubi, vol_id, lnum); | 810 | leb_write_unlock(ubi, vol_id, lnum); |
@@ -901,7 +901,7 @@ retry: | |||
901 | } | 901 | } |
902 | 902 | ||
903 | if (vol->eba_tbl[lnum] >= 0) { | 903 | if (vol->eba_tbl[lnum] >= 0) { |
904 | err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0); | 904 | err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0); |
905 | if (err) | 905 | if (err) |
906 | goto out_leb_unlock; | 906 | goto out_leb_unlock; |
907 | } | 907 | } |
@@ -926,7 +926,7 @@ write_error: | |||
926 | goto out_leb_unlock; | 926 | goto out_leb_unlock; |
927 | } | 927 | } |
928 | 928 | ||
929 | err = ubi_wl_put_peb(ubi, pnum, 1); | 929 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); |
930 | if (err || ++tries > UBI_IO_RETRIES) { | 930 | if (err || ++tries > UBI_IO_RETRIES) { |
931 | ubi_ro_mode(ubi); | 931 | ubi_ro_mode(ubi); |
932 | goto out_leb_unlock; | 932 | goto out_leb_unlock; |
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index b4b3913f1df..5e1182ca289 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
@@ -667,7 +667,8 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai); | |||
667 | 667 | ||
668 | /* wl.c */ | 668 | /* wl.c */ |
669 | int ubi_wl_get_peb(struct ubi_device *ubi); | 669 | int ubi_wl_get_peb(struct ubi_device *ubi); |
670 | int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture); | 670 | int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, |
671 | int pnum, int torture); | ||
671 | int ubi_wl_flush(struct ubi_device *ubi); | 672 | int ubi_wl_flush(struct ubi_device *ubi); |
672 | int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); | 673 | int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); |
673 | int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai); | 674 | int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai); |
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index c143e611235..70ebfa7bc38 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c | |||
@@ -140,6 +140,8 @@ | |||
140 | * @list: a link in the list of pending works | 140 | * @list: a link in the list of pending works |
141 | * @func: worker function | 141 | * @func: worker function |
142 | * @e: physical eraseblock to erase | 142 | * @e: physical eraseblock to erase |
143 | * @vol_id: the volume ID on which this erasure is being performed | ||
144 | * @lnum: the logical eraseblock number | ||
143 | * @torture: if the physical eraseblock has to be tortured | 145 | * @torture: if the physical eraseblock has to be tortured |
144 | * | 146 | * |
145 | * The @func pointer points to the worker function. If the @cancel argument is | 147 | * The @func pointer points to the worker function. If the @cancel argument is |
@@ -152,6 +154,8 @@ struct ubi_work { | |||
152 | int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); | 154 | int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); |
153 | /* The below fields are only relevant to erasure works */ | 155 | /* The below fields are only relevant to erasure works */ |
154 | struct ubi_wl_entry *e; | 156 | struct ubi_wl_entry *e; |
157 | int vol_id; | ||
158 | int lnum; | ||
155 | int torture; | 159 | int torture; |
156 | }; | 160 | }; |
157 | 161 | ||
@@ -579,13 +583,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
579 | * schedule_erase - schedule an erase work. | 583 | * schedule_erase - schedule an erase work. |
580 | * @ubi: UBI device description object | 584 | * @ubi: UBI device description object |
581 | * @e: the WL entry of the physical eraseblock to erase | 585 | * @e: the WL entry of the physical eraseblock to erase |
586 | * @vol_id: the volume ID that last used this PEB | ||
587 | * @lnum: the last used logical eraseblock number for the PEB | ||
582 | * @torture: if the physical eraseblock has to be tortured | 588 | * @torture: if the physical eraseblock has to be tortured |
583 | * | 589 | * |
584 | * This function returns zero in case of success and a %-ENOMEM in case of | 590 | * This function returns zero in case of success and a %-ENOMEM in case of |
585 | * failure. | 591 | * failure. |
586 | */ | 592 | */ |
587 | static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, | 593 | static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, |
588 | int torture) | 594 | int vol_id, int lnum, int torture) |
589 | { | 595 | { |
590 | struct ubi_work *wl_wrk; | 596 | struct ubi_work *wl_wrk; |
591 | 597 | ||
@@ -598,6 +604,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, | |||
598 | 604 | ||
599 | wl_wrk->func = &erase_worker; | 605 | wl_wrk->func = &erase_worker; |
600 | wl_wrk->e = e; | 606 | wl_wrk->e = e; |
607 | wl_wrk->vol_id = vol_id; | ||
608 | wl_wrk->lnum = lnum; | ||
601 | wl_wrk->torture = torture; | 609 | wl_wrk->torture = torture; |
602 | 610 | ||
603 | schedule_ubi_work(ubi, wl_wrk); | 611 | schedule_ubi_work(ubi, wl_wrk); |
@@ -798,7 +806,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
798 | ubi->move_to_put = ubi->wl_scheduled = 0; | 806 | ubi->move_to_put = ubi->wl_scheduled = 0; |
799 | spin_unlock(&ubi->wl_lock); | 807 | spin_unlock(&ubi->wl_lock); |
800 | 808 | ||
801 | err = schedule_erase(ubi, e1, 0); | 809 | err = schedule_erase(ubi, e1, vol_id, lnum, 0); |
802 | if (err) { | 810 | if (err) { |
803 | kmem_cache_free(ubi_wl_entry_slab, e1); | 811 | kmem_cache_free(ubi_wl_entry_slab, e1); |
804 | if (e2) | 812 | if (e2) |
@@ -813,7 +821,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
813 | */ | 821 | */ |
814 | dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", | 822 | dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", |
815 | e2->pnum, vol_id, lnum); | 823 | e2->pnum, vol_id, lnum); |
816 | err = schedule_erase(ubi, e2, 0); | 824 | err = schedule_erase(ubi, e2, vol_id, lnum, 0); |
817 | if (err) { | 825 | if (err) { |
818 | kmem_cache_free(ubi_wl_entry_slab, e2); | 826 | kmem_cache_free(ubi_wl_entry_slab, e2); |
819 | goto out_ro; | 827 | goto out_ro; |
@@ -852,7 +860,7 @@ out_not_moved: | |||
852 | spin_unlock(&ubi->wl_lock); | 860 | spin_unlock(&ubi->wl_lock); |
853 | 861 | ||
854 | ubi_free_vid_hdr(ubi, vid_hdr); | 862 | ubi_free_vid_hdr(ubi, vid_hdr); |
855 | err = schedule_erase(ubi, e2, torture); | 863 | err = schedule_erase(ubi, e2, vol_id, lnum, torture); |
856 | if (err) { | 864 | if (err) { |
857 | kmem_cache_free(ubi_wl_entry_slab, e2); | 865 | kmem_cache_free(ubi_wl_entry_slab, e2); |
858 | goto out_ro; | 866 | goto out_ro; |
@@ -971,6 +979,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
971 | { | 979 | { |
972 | struct ubi_wl_entry *e = wl_wrk->e; | 980 | struct ubi_wl_entry *e = wl_wrk->e; |
973 | int pnum = e->pnum, err, need; | 981 | int pnum = e->pnum, err, need; |
982 | int vol_id = wl_wrk->vol_id; | ||
983 | int lnum = wl_wrk->lnum; | ||
974 | 984 | ||
975 | if (cancel) { | 985 | if (cancel) { |
976 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); | 986 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); |
@@ -979,7 +989,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
979 | return 0; | 989 | return 0; |
980 | } | 990 | } |
981 | 991 | ||
982 | dbg_wl("erase PEB %d EC %d", pnum, e->ec); | 992 | dbg_wl("erase PEB %d EC %d LEB %d:%d", |
993 | pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum); | ||
983 | 994 | ||
984 | err = sync_erase(ubi, e, wl_wrk->torture); | 995 | err = sync_erase(ubi, e, wl_wrk->torture); |
985 | if (!err) { | 996 | if (!err) { |
@@ -1009,7 +1020,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
1009 | int err1; | 1020 | int err1; |
1010 | 1021 | ||
1011 | /* Re-schedule the LEB for erasure */ | 1022 | /* Re-schedule the LEB for erasure */ |
1012 | err1 = schedule_erase(ubi, e, 0); | 1023 | err1 = schedule_erase(ubi, e, vol_id, lnum, 0); |
1013 | if (err1) { | 1024 | if (err1) { |
1014 | err = err1; | 1025 | err = err1; |
1015 | goto out_ro; | 1026 | goto out_ro; |
@@ -1077,6 +1088,8 @@ out_ro: | |||
1077 | /** | 1088 | /** |
1078 | * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system. | 1089 | * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system. |
1079 | * @ubi: UBI device description object | 1090 | * @ubi: UBI device description object |
1091 | * @vol_id: the volume ID that last used this PEB | ||
1092 | * @lnum: the last used logical eraseblock number for the PEB | ||
1080 | * @pnum: physical eraseblock to return | 1093 | * @pnum: physical eraseblock to return |
1081 | * @torture: if this physical eraseblock has to be tortured | 1094 | * @torture: if this physical eraseblock has to be tortured |
1082 | * | 1095 | * |
@@ -1085,7 +1098,8 @@ out_ro: | |||
1085 | * occurred to this @pnum and it has to be tested. This function returns zero | 1098 | * occurred to this @pnum and it has to be tested. This function returns zero |
1086 | * in case of success, and a negative error code in case of failure. | 1099 | * in case of success, and a negative error code in case of failure. |
1087 | */ | 1100 | */ |
1088 | int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) | 1101 | int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, |
1102 | int pnum, int torture) | ||
1089 | { | 1103 | { |
1090 | int err; | 1104 | int err; |
1091 | struct ubi_wl_entry *e; | 1105 | struct ubi_wl_entry *e; |
@@ -1151,7 +1165,7 @@ retry: | |||
1151 | } | 1165 | } |
1152 | spin_unlock(&ubi->wl_lock); | 1166 | spin_unlock(&ubi->wl_lock); |
1153 | 1167 | ||
1154 | err = schedule_erase(ubi, e, torture); | 1168 | err = schedule_erase(ubi, e, vol_id, lnum, torture); |
1155 | if (err) { | 1169 | if (err) { |
1156 | spin_lock(&ubi->wl_lock); | 1170 | spin_lock(&ubi->wl_lock); |
1157 | wl_tree_add(e, &ubi->used); | 1171 | wl_tree_add(e, &ubi->used); |
@@ -1416,7 +1430,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) | |||
1416 | e->pnum = aeb->pnum; | 1430 | e->pnum = aeb->pnum; |
1417 | e->ec = aeb->ec; | 1431 | e->ec = aeb->ec; |
1418 | ubi->lookuptbl[e->pnum] = e; | 1432 | ubi->lookuptbl[e->pnum] = e; |
1419 | if (schedule_erase(ubi, e, 0)) { | 1433 | if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { |
1420 | kmem_cache_free(ubi_wl_entry_slab, e); | 1434 | kmem_cache_free(ubi_wl_entry_slab, e); |
1421 | goto out_free; | 1435 | goto out_free; |
1422 | } | 1436 | } |