diff options
Diffstat (limited to 'drivers/mtd/ubi/eba.c')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 126 |
1 files changed, 117 insertions, 9 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index a26d7d253174..0e11671dadc4 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -57,7 +57,7 @@ | |||
57 | * global sequence counter value. It also increases the global sequence | 57 | * global sequence counter value. It also increases the global sequence |
58 | * counter. | 58 | * counter. |
59 | */ | 59 | */ |
60 | static unsigned long long next_sqnum(struct ubi_device *ubi) | 60 | unsigned long long ubi_next_sqnum(struct ubi_device *ubi) |
61 | { | 61 | { |
62 | unsigned long long sqnum; | 62 | unsigned long long sqnum; |
63 | 63 | ||
@@ -340,7 +340,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, | |||
340 | 340 | ||
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 | down_read(&ubi->fm_sem); | ||
343 | vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; | 344 | vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; |
345 | up_read(&ubi->fm_sem); | ||
344 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0); | 346 | err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0); |
345 | 347 | ||
346 | out_unlock: | 348 | out_unlock: |
@@ -521,7 +523,7 @@ retry: | |||
521 | goto out_put; | 523 | goto out_put; |
522 | } | 524 | } |
523 | 525 | ||
524 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 526 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
525 | err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); | 527 | err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); |
526 | if (err) | 528 | if (err) |
527 | goto write_error; | 529 | goto write_error; |
@@ -548,7 +550,9 @@ retry: | |||
548 | mutex_unlock(&ubi->buf_mutex); | 550 | mutex_unlock(&ubi->buf_mutex); |
549 | ubi_free_vid_hdr(ubi, vid_hdr); | 551 | ubi_free_vid_hdr(ubi, vid_hdr); |
550 | 552 | ||
553 | down_read(&ubi->fm_sem); | ||
551 | vol->eba_tbl[lnum] = new_pnum; | 554 | vol->eba_tbl[lnum] = new_pnum; |
555 | up_read(&ubi->fm_sem); | ||
552 | ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); | 556 | ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); |
553 | 557 | ||
554 | ubi_msg("data was successfully recovered"); | 558 | ubi_msg("data was successfully recovered"); |
@@ -632,7 +636,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, | |||
632 | } | 636 | } |
633 | 637 | ||
634 | vid_hdr->vol_type = UBI_VID_DYNAMIC; | 638 | vid_hdr->vol_type = UBI_VID_DYNAMIC; |
635 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 639 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
636 | vid_hdr->vol_id = cpu_to_be32(vol_id); | 640 | vid_hdr->vol_id = cpu_to_be32(vol_id); |
637 | vid_hdr->lnum = cpu_to_be32(lnum); | 641 | vid_hdr->lnum = cpu_to_be32(lnum); |
638 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); | 642 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); |
@@ -665,7 +669,9 @@ retry: | |||
665 | } | 669 | } |
666 | } | 670 | } |
667 | 671 | ||
672 | down_read(&ubi->fm_sem); | ||
668 | vol->eba_tbl[lnum] = pnum; | 673 | vol->eba_tbl[lnum] = pnum; |
674 | up_read(&ubi->fm_sem); | ||
669 | 675 | ||
670 | leb_write_unlock(ubi, vol_id, lnum); | 676 | leb_write_unlock(ubi, vol_id, lnum); |
671 | ubi_free_vid_hdr(ubi, vid_hdr); | 677 | ubi_free_vid_hdr(ubi, vid_hdr); |
@@ -692,7 +698,7 @@ write_error: | |||
692 | return err; | 698 | return err; |
693 | } | 699 | } |
694 | 700 | ||
695 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 701 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
696 | ubi_msg("try another PEB"); | 702 | ubi_msg("try another PEB"); |
697 | goto retry; | 703 | goto retry; |
698 | } | 704 | } |
@@ -745,7 +751,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, | |||
745 | return err; | 751 | return err; |
746 | } | 752 | } |
747 | 753 | ||
748 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 754 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
749 | vid_hdr->vol_id = cpu_to_be32(vol_id); | 755 | vid_hdr->vol_id = cpu_to_be32(vol_id); |
750 | vid_hdr->lnum = cpu_to_be32(lnum); | 756 | vid_hdr->lnum = cpu_to_be32(lnum); |
751 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); | 757 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); |
@@ -783,7 +789,9 @@ retry: | |||
783 | } | 789 | } |
784 | 790 | ||
785 | ubi_assert(vol->eba_tbl[lnum] < 0); | 791 | ubi_assert(vol->eba_tbl[lnum] < 0); |
792 | down_read(&ubi->fm_sem); | ||
786 | vol->eba_tbl[lnum] = pnum; | 793 | vol->eba_tbl[lnum] = pnum; |
794 | up_read(&ubi->fm_sem); | ||
787 | 795 | ||
788 | leb_write_unlock(ubi, vol_id, lnum); | 796 | leb_write_unlock(ubi, vol_id, lnum); |
789 | ubi_free_vid_hdr(ubi, vid_hdr); | 797 | ubi_free_vid_hdr(ubi, vid_hdr); |
@@ -810,7 +818,7 @@ write_error: | |||
810 | return err; | 818 | return err; |
811 | } | 819 | } |
812 | 820 | ||
813 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 821 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
814 | ubi_msg("try another PEB"); | 822 | ubi_msg("try another PEB"); |
815 | goto retry; | 823 | goto retry; |
816 | } | 824 | } |
@@ -862,7 +870,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, | |||
862 | if (err) | 870 | if (err) |
863 | goto out_mutex; | 871 | goto out_mutex; |
864 | 872 | ||
865 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 873 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
866 | vid_hdr->vol_id = cpu_to_be32(vol_id); | 874 | vid_hdr->vol_id = cpu_to_be32(vol_id); |
867 | vid_hdr->lnum = cpu_to_be32(lnum); | 875 | vid_hdr->lnum = cpu_to_be32(lnum); |
868 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); | 876 | vid_hdr->compat = ubi_get_compat(ubi, vol_id); |
@@ -904,7 +912,9 @@ retry: | |||
904 | goto out_leb_unlock; | 912 | goto out_leb_unlock; |
905 | } | 913 | } |
906 | 914 | ||
915 | down_read(&ubi->fm_sem); | ||
907 | vol->eba_tbl[lnum] = pnum; | 916 | vol->eba_tbl[lnum] = pnum; |
917 | up_read(&ubi->fm_sem); | ||
908 | 918 | ||
909 | out_leb_unlock: | 919 | out_leb_unlock: |
910 | leb_write_unlock(ubi, vol_id, lnum); | 920 | leb_write_unlock(ubi, vol_id, lnum); |
@@ -930,7 +940,7 @@ write_error: | |||
930 | goto out_leb_unlock; | 940 | goto out_leb_unlock; |
931 | } | 941 | } |
932 | 942 | ||
933 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 943 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
934 | ubi_msg("try another PEB"); | 944 | ubi_msg("try another PEB"); |
935 | goto retry; | 945 | goto retry; |
936 | } | 946 | } |
@@ -1089,7 +1099,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1089 | vid_hdr->data_size = cpu_to_be32(data_size); | 1099 | vid_hdr->data_size = cpu_to_be32(data_size); |
1090 | vid_hdr->data_crc = cpu_to_be32(crc); | 1100 | vid_hdr->data_crc = cpu_to_be32(crc); |
1091 | } | 1101 | } |
1092 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 1102 | vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); |
1093 | 1103 | ||
1094 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); | 1104 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); |
1095 | if (err) { | 1105 | if (err) { |
@@ -1151,7 +1161,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1151 | } | 1161 | } |
1152 | 1162 | ||
1153 | ubi_assert(vol->eba_tbl[lnum] == from); | 1163 | ubi_assert(vol->eba_tbl[lnum] == from); |
1164 | down_read(&ubi->fm_sem); | ||
1154 | vol->eba_tbl[lnum] = to; | 1165 | vol->eba_tbl[lnum] = to; |
1166 | up_read(&ubi->fm_sem); | ||
1155 | 1167 | ||
1156 | out_unlock_buf: | 1168 | out_unlock_buf: |
1157 | mutex_unlock(&ubi->buf_mutex); | 1169 | mutex_unlock(&ubi->buf_mutex); |
@@ -1202,6 +1214,102 @@ static void print_rsvd_warning(struct ubi_device *ubi, | |||
1202 | } | 1214 | } |
1203 | 1215 | ||
1204 | /** | 1216 | /** |
1217 | * self_check_eba - run a self check on the EBA table constructed by fastmap. | ||
1218 | * @ubi: UBI device description object | ||
1219 | * @ai_fastmap: UBI attach info object created by fastmap | ||
1220 | * @ai_scan: UBI attach info object created by scanning | ||
1221 | * | ||
1222 | * Returns < 0 in case of an internal error, 0 otherwise. | ||
1223 | * If a bad EBA table entry was found it will be printed out and | ||
1224 | * ubi_assert() triggers. | ||
1225 | */ | ||
1226 | int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, | ||
1227 | struct ubi_attach_info *ai_scan) | ||
1228 | { | ||
1229 | int i, j, num_volumes, ret = 0; | ||
1230 | int **scan_eba, **fm_eba; | ||
1231 | struct ubi_ainf_volume *av; | ||
1232 | struct ubi_volume *vol; | ||
1233 | struct ubi_ainf_peb *aeb; | ||
1234 | struct rb_node *rb; | ||
1235 | |||
1236 | num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; | ||
1237 | |||
1238 | scan_eba = kmalloc(sizeof(*scan_eba) * num_volumes, GFP_KERNEL); | ||
1239 | if (!scan_eba) | ||
1240 | return -ENOMEM; | ||
1241 | |||
1242 | fm_eba = kmalloc(sizeof(*fm_eba) * num_volumes, GFP_KERNEL); | ||
1243 | if (!fm_eba) { | ||
1244 | kfree(scan_eba); | ||
1245 | return -ENOMEM; | ||
1246 | } | ||
1247 | |||
1248 | for (i = 0; i < num_volumes; i++) { | ||
1249 | vol = ubi->volumes[i]; | ||
1250 | if (!vol) | ||
1251 | continue; | ||
1252 | |||
1253 | scan_eba[i] = kmalloc(vol->reserved_pebs * sizeof(**scan_eba), | ||
1254 | GFP_KERNEL); | ||
1255 | if (!scan_eba[i]) { | ||
1256 | ret = -ENOMEM; | ||
1257 | goto out_free; | ||
1258 | } | ||
1259 | |||
1260 | fm_eba[i] = kmalloc(vol->reserved_pebs * sizeof(**fm_eba), | ||
1261 | GFP_KERNEL); | ||
1262 | if (!fm_eba[i]) { | ||
1263 | ret = -ENOMEM; | ||
1264 | goto out_free; | ||
1265 | } | ||
1266 | |||
1267 | for (j = 0; j < vol->reserved_pebs; j++) | ||
1268 | scan_eba[i][j] = fm_eba[i][j] = UBI_LEB_UNMAPPED; | ||
1269 | |||
1270 | av = ubi_find_av(ai_scan, idx2vol_id(ubi, i)); | ||
1271 | if (!av) | ||
1272 | continue; | ||
1273 | |||
1274 | ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) | ||
1275 | scan_eba[i][aeb->lnum] = aeb->pnum; | ||
1276 | |||
1277 | av = ubi_find_av(ai_fastmap, idx2vol_id(ubi, i)); | ||
1278 | if (!av) | ||
1279 | continue; | ||
1280 | |||
1281 | ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) | ||
1282 | fm_eba[i][aeb->lnum] = aeb->pnum; | ||
1283 | |||
1284 | for (j = 0; j < vol->reserved_pebs; j++) { | ||
1285 | if (scan_eba[i][j] != fm_eba[i][j]) { | ||
1286 | if (scan_eba[i][j] == UBI_LEB_UNMAPPED || | ||
1287 | fm_eba[i][j] == UBI_LEB_UNMAPPED) | ||
1288 | continue; | ||
1289 | |||
1290 | ubi_err("LEB:%i:%i is PEB:%i instead of %i!", | ||
1291 | vol->vol_id, i, fm_eba[i][j], | ||
1292 | scan_eba[i][j]); | ||
1293 | ubi_assert(0); | ||
1294 | } | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | out_free: | ||
1299 | for (i = 0; i < num_volumes; i++) { | ||
1300 | if (!ubi->volumes[i]) | ||
1301 | continue; | ||
1302 | |||
1303 | kfree(scan_eba[i]); | ||
1304 | kfree(fm_eba[i]); | ||
1305 | } | ||
1306 | |||
1307 | kfree(scan_eba); | ||
1308 | kfree(fm_eba); | ||
1309 | return ret; | ||
1310 | } | ||
1311 | |||
1312 | /** | ||
1205 | * ubi_eba_init - initialize the EBA sub-system using attaching information. | 1313 | * ubi_eba_init - initialize the EBA sub-system using attaching information. |
1206 | * @ubi: UBI device description object | 1314 | * @ubi: UBI device description object |
1207 | * @ai: attaching information | 1315 | * @ai: attaching information |