diff options
Diffstat (limited to 'drivers/mtd/ubi/vtbl.c')
-rw-r--r-- | drivers/mtd/ubi/vtbl.c | 71 |
1 files changed, 34 insertions, 37 deletions
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 07cac5f9ffb8..f8fc3081bbb4 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
@@ -30,9 +30,12 @@ | |||
30 | * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each | 30 | * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each |
31 | * other. This redundancy guarantees robustness to unclean reboots. The volume | 31 | * other. This redundancy guarantees robustness to unclean reboots. The volume |
32 | * table is basically an array of volume table records. Each record contains | 32 | * table is basically an array of volume table records. Each record contains |
33 | * full information about the volume and protected by a CRC checksum. | 33 | * full information about the volume and protected by a CRC checksum. Note, |
34 | * nowadays we use the atomic LEB change operation when updating the volume | ||
35 | * table, so we do not really need 2 LEBs anymore, but we preserve the older | ||
36 | * design for the backward compatibility reasons. | ||
34 | * | 37 | * |
35 | * The volume table is changed, it is first changed in RAM. Then LEB 0 is | 38 | * When the volume table is changed, it is first changed in RAM. Then LEB 0 is |
36 | * erased, and the updated volume table is written back to LEB 0. Then same for | 39 | * erased, and the updated volume table is written back to LEB 0. Then same for |
37 | * LEB 1. This scheme guarantees recoverability from unclean reboots. | 40 | * LEB 1. This scheme guarantees recoverability from unclean reboots. |
38 | * | 41 | * |
@@ -96,12 +99,8 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | |||
96 | 99 | ||
97 | memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); | 100 | memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); |
98 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { | 101 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { |
99 | err = ubi_eba_unmap_leb(ubi, layout_vol, i); | 102 | err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl, |
100 | if (err) | 103 | ubi->vtbl_size); |
101 | return err; | ||
102 | |||
103 | err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, | ||
104 | ubi->vtbl_size); | ||
105 | if (err) | 104 | if (err) |
106 | return err; | 105 | return err; |
107 | } | 106 | } |
@@ -148,12 +147,8 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi, | |||
148 | 147 | ||
149 | layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; | 148 | layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; |
150 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { | 149 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { |
151 | err = ubi_eba_unmap_leb(ubi, layout_vol, i); | 150 | err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl, |
152 | if (err) | 151 | ubi->vtbl_size); |
153 | return err; | ||
154 | |||
155 | err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, | ||
156 | ubi->vtbl_size); | ||
157 | if (err) | 152 | if (err) |
158 | return err; | 153 | return err; |
159 | } | 154 | } |
@@ -190,7 +185,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
190 | 185 | ||
191 | crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); | 186 | crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); |
192 | if (be32_to_cpu(vtbl[i].crc) != crc) { | 187 | if (be32_to_cpu(vtbl[i].crc) != crc) { |
193 | ubi_err("bad CRC at record %u: %#08x, not %#08x", | 188 | ubi_err(ubi, "bad CRC at record %u: %#08x, not %#08x", |
194 | i, crc, be32_to_cpu(vtbl[i].crc)); | 189 | i, crc, be32_to_cpu(vtbl[i].crc)); |
195 | ubi_dump_vtbl_record(&vtbl[i], i); | 190 | ubi_dump_vtbl_record(&vtbl[i], i); |
196 | return 1; | 191 | return 1; |
@@ -224,7 +219,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
224 | 219 | ||
225 | n = ubi->leb_size % alignment; | 220 | n = ubi->leb_size % alignment; |
226 | if (data_pad != n) { | 221 | if (data_pad != n) { |
227 | ubi_err("bad data_pad, has to be %d", n); | 222 | ubi_err(ubi, "bad data_pad, has to be %d", n); |
228 | err = 6; | 223 | err = 6; |
229 | goto bad; | 224 | goto bad; |
230 | } | 225 | } |
@@ -240,7 +235,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
240 | } | 235 | } |
241 | 236 | ||
242 | if (reserved_pebs > ubi->good_peb_count) { | 237 | if (reserved_pebs > ubi->good_peb_count) { |
243 | ubi_err("too large reserved_pebs %d, good PEBs %d", | 238 | ubi_err(ubi, "too large reserved_pebs %d, good PEBs %d", |
244 | reserved_pebs, ubi->good_peb_count); | 239 | reserved_pebs, ubi->good_peb_count); |
245 | err = 9; | 240 | err = 9; |
246 | goto bad; | 241 | goto bad; |
@@ -270,7 +265,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
270 | 265 | ||
271 | if (len1 > 0 && len1 == len2 && | 266 | if (len1 > 0 && len1 == len2 && |
272 | !strncmp(vtbl[i].name, vtbl[n].name, len1)) { | 267 | !strncmp(vtbl[i].name, vtbl[n].name, len1)) { |
273 | ubi_err("volumes %d and %d have the same name \"%s\"", | 268 | ubi_err(ubi, "volumes %d and %d have the same name \"%s\"", |
274 | i, n, vtbl[i].name); | 269 | i, n, vtbl[i].name); |
275 | ubi_dump_vtbl_record(&vtbl[i], i); | 270 | ubi_dump_vtbl_record(&vtbl[i], i); |
276 | ubi_dump_vtbl_record(&vtbl[n], n); | 271 | ubi_dump_vtbl_record(&vtbl[n], n); |
@@ -282,7 +277,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
282 | return 0; | 277 | return 0; |
283 | 278 | ||
284 | bad: | 279 | bad: |
285 | ubi_err("volume table check failed: record %d, error %d", i, err); | 280 | ubi_err(ubi, "volume table check failed: record %d, error %d", i, err); |
286 | ubi_dump_vtbl_record(&vtbl[i], i); | 281 | ubi_dump_vtbl_record(&vtbl[i], i); |
287 | return -EINVAL; | 282 | return -EINVAL; |
288 | } | 283 | } |
@@ -446,11 +441,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
446 | leb_corrupted[1] = memcmp(leb[0], leb[1], | 441 | leb_corrupted[1] = memcmp(leb[0], leb[1], |
447 | ubi->vtbl_size); | 442 | ubi->vtbl_size); |
448 | if (leb_corrupted[1]) { | 443 | if (leb_corrupted[1]) { |
449 | ubi_warn("volume table copy #2 is corrupted"); | 444 | ubi_warn(ubi, "volume table copy #2 is corrupted"); |
450 | err = create_vtbl(ubi, ai, 1, leb[0]); | 445 | err = create_vtbl(ubi, ai, 1, leb[0]); |
451 | if (err) | 446 | if (err) |
452 | goto out_free; | 447 | goto out_free; |
453 | ubi_msg("volume table was restored"); | 448 | ubi_msg(ubi, "volume table was restored"); |
454 | } | 449 | } |
455 | 450 | ||
456 | /* Both LEB 1 and LEB 2 are OK and consistent */ | 451 | /* Both LEB 1 and LEB 2 are OK and consistent */ |
@@ -465,15 +460,15 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
465 | } | 460 | } |
466 | if (leb_corrupted[1]) { | 461 | if (leb_corrupted[1]) { |
467 | /* Both LEB 0 and LEB 1 are corrupted */ | 462 | /* Both LEB 0 and LEB 1 are corrupted */ |
468 | ubi_err("both volume tables are corrupted"); | 463 | ubi_err(ubi, "both volume tables are corrupted"); |
469 | goto out_free; | 464 | goto out_free; |
470 | } | 465 | } |
471 | 466 | ||
472 | ubi_warn("volume table copy #1 is corrupted"); | 467 | ubi_warn(ubi, "volume table copy #1 is corrupted"); |
473 | err = create_vtbl(ubi, ai, 0, leb[1]); | 468 | err = create_vtbl(ubi, ai, 0, leb[1]); |
474 | if (err) | 469 | if (err) |
475 | goto out_free; | 470 | goto out_free; |
476 | ubi_msg("volume table was restored"); | 471 | ubi_msg(ubi, "volume table was restored"); |
477 | 472 | ||
478 | vfree(leb[0]); | 473 | vfree(leb[0]); |
479 | return leb[1]; | 474 | return leb[1]; |
@@ -562,7 +557,7 @@ static int init_volumes(struct ubi_device *ubi, | |||
562 | if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { | 557 | if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { |
563 | /* Auto re-size flag may be set only for one volume */ | 558 | /* Auto re-size flag may be set only for one volume */ |
564 | if (ubi->autoresize_vol_id != -1) { | 559 | if (ubi->autoresize_vol_id != -1) { |
565 | ubi_err("more than one auto-resize volume (%d and %d)", | 560 | ubi_err(ubi, "more than one auto-resize volume (%d and %d)", |
566 | ubi->autoresize_vol_id, i); | 561 | ubi->autoresize_vol_id, i); |
567 | kfree(vol); | 562 | kfree(vol); |
568 | return -EINVAL; | 563 | return -EINVAL; |
@@ -608,7 +603,7 @@ static int init_volumes(struct ubi_device *ubi, | |||
608 | * We found a static volume which misses several | 603 | * We found a static volume which misses several |
609 | * eraseblocks. Treat it as corrupted. | 604 | * eraseblocks. Treat it as corrupted. |
610 | */ | 605 | */ |
611 | ubi_warn("static volume %d misses %d LEBs - corrupted", | 606 | ubi_warn(ubi, "static volume %d misses %d LEBs - corrupted", |
612 | av->vol_id, av->used_ebs - av->leb_count); | 607 | av->vol_id, av->used_ebs - av->leb_count); |
613 | vol->corrupted = 1; | 608 | vol->corrupted = 1; |
614 | continue; | 609 | continue; |
@@ -646,10 +641,10 @@ static int init_volumes(struct ubi_device *ubi, | |||
646 | vol->ubi = ubi; | 641 | vol->ubi = ubi; |
647 | 642 | ||
648 | if (reserved_pebs > ubi->avail_pebs) { | 643 | if (reserved_pebs > ubi->avail_pebs) { |
649 | ubi_err("not enough PEBs, required %d, available %d", | 644 | ubi_err(ubi, "not enough PEBs, required %d, available %d", |
650 | reserved_pebs, ubi->avail_pebs); | 645 | reserved_pebs, ubi->avail_pebs); |
651 | if (ubi->corr_peb_count) | 646 | if (ubi->corr_peb_count) |
652 | ubi_err("%d PEBs are corrupted and not used", | 647 | ubi_err(ubi, "%d PEBs are corrupted and not used", |
653 | ubi->corr_peb_count); | 648 | ubi->corr_peb_count); |
654 | } | 649 | } |
655 | ubi->rsvd_pebs += reserved_pebs; | 650 | ubi->rsvd_pebs += reserved_pebs; |
@@ -660,13 +655,14 @@ static int init_volumes(struct ubi_device *ubi, | |||
660 | 655 | ||
661 | /** | 656 | /** |
662 | * check_av - check volume attaching information. | 657 | * check_av - check volume attaching information. |
658 | * @ubi: UBI device description object | ||
663 | * @vol: UBI volume description object | 659 | * @vol: UBI volume description object |
664 | * @av: volume attaching information | 660 | * @av: volume attaching information |
665 | * | 661 | * |
666 | * This function returns zero if the volume attaching information is consistent | 662 | * This function returns zero if the volume attaching information is consistent |
667 | * to the data read from the volume tabla, and %-EINVAL if not. | 663 | * to the data read from the volume tabla, and %-EINVAL if not. |
668 | */ | 664 | */ |
669 | static int check_av(const struct ubi_volume *vol, | 665 | static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, |
670 | const struct ubi_ainf_volume *av) | 666 | const struct ubi_ainf_volume *av) |
671 | { | 667 | { |
672 | int err; | 668 | int err; |
@@ -694,7 +690,7 @@ static int check_av(const struct ubi_volume *vol, | |||
694 | return 0; | 690 | return 0; |
695 | 691 | ||
696 | bad: | 692 | bad: |
697 | ubi_err("bad attaching information, error %d", err); | 693 | ubi_err(ubi, "bad attaching information, error %d", err); |
698 | ubi_dump_av(av); | 694 | ubi_dump_av(av); |
699 | ubi_dump_vol_info(vol); | 695 | ubi_dump_vol_info(vol); |
700 | return -EINVAL; | 696 | return -EINVAL; |
@@ -718,14 +714,15 @@ static int check_attaching_info(const struct ubi_device *ubi, | |||
718 | struct ubi_volume *vol; | 714 | struct ubi_volume *vol; |
719 | 715 | ||
720 | if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { | 716 | if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { |
721 | ubi_err("found %d volumes while attaching, maximum is %d + %d", | 717 | ubi_err(ubi, "found %d volumes while attaching, maximum is %d + %d", |
722 | ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); | 718 | ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); |
723 | return -EINVAL; | 719 | return -EINVAL; |
724 | } | 720 | } |
725 | 721 | ||
726 | if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && | 722 | if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && |
727 | ai->highest_vol_id < UBI_INTERNAL_VOL_START) { | 723 | ai->highest_vol_id < UBI_INTERNAL_VOL_START) { |
728 | ubi_err("too large volume ID %d found", ai->highest_vol_id); | 724 | ubi_err(ubi, "too large volume ID %d found", |
725 | ai->highest_vol_id); | ||
729 | return -EINVAL; | 726 | return -EINVAL; |
730 | } | 727 | } |
731 | 728 | ||
@@ -753,10 +750,10 @@ static int check_attaching_info(const struct ubi_device *ubi, | |||
753 | * reboot while the volume was being removed. Discard | 750 | * reboot while the volume was being removed. Discard |
754 | * these eraseblocks. | 751 | * these eraseblocks. |
755 | */ | 752 | */ |
756 | ubi_msg("finish volume %d removal", av->vol_id); | 753 | ubi_msg(ubi, "finish volume %d removal", av->vol_id); |
757 | ubi_remove_av(ai, av); | 754 | ubi_remove_av(ai, av); |
758 | } else if (av) { | 755 | } else if (av) { |
759 | err = check_av(vol, av); | 756 | err = check_av(ubi, vol, av); |
760 | if (err) | 757 | if (err) |
761 | return err; | 758 | return err; |
762 | } | 759 | } |
@@ -807,13 +804,13 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) | |||
807 | if (IS_ERR(ubi->vtbl)) | 804 | if (IS_ERR(ubi->vtbl)) |
808 | return PTR_ERR(ubi->vtbl); | 805 | return PTR_ERR(ubi->vtbl); |
809 | } else { | 806 | } else { |
810 | ubi_err("the layout volume was not found"); | 807 | ubi_err(ubi, "the layout volume was not found"); |
811 | return -EINVAL; | 808 | return -EINVAL; |
812 | } | 809 | } |
813 | } else { | 810 | } else { |
814 | if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { | 811 | if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { |
815 | /* This must not happen with proper UBI images */ | 812 | /* This must not happen with proper UBI images */ |
816 | ubi_err("too many LEBs (%d) in layout volume", | 813 | ubi_err(ubi, "too many LEBs (%d) in layout volume", |
817 | av->leb_count); | 814 | av->leb_count); |
818 | return -EINVAL; | 815 | return -EINVAL; |
819 | } | 816 | } |
@@ -862,7 +859,7 @@ static void self_vtbl_check(const struct ubi_device *ubi) | |||
862 | return; | 859 | return; |
863 | 860 | ||
864 | if (vtbl_check(ubi, ubi->vtbl)) { | 861 | if (vtbl_check(ubi, ubi->vtbl)) { |
865 | ubi_err("self-check failed"); | 862 | ubi_err(ubi, "self-check failed"); |
866 | BUG(); | 863 | BUG(); |
867 | } | 864 | } |
868 | } | 865 | } |