aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/eba.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/ubi/eba.c')
-rw-r--r--drivers/mtd/ubi/eba.c126
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 */
60static unsigned long long next_sqnum(struct ubi_device *ubi) 60unsigned 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
346out_unlock: 348out_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
909out_leb_unlock: 919out_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
1156out_unlock_buf: 1168out_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 */
1226int 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
1298out_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