diff options
Diffstat (limited to 'drivers/mtd/ubi/vtbl.c')
-rw-r--r-- | drivers/mtd/ubi/vtbl.c | 127 |
1 files changed, 93 insertions, 34 deletions
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index af36b12be278..217d0e111b2a 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
@@ -115,8 +115,58 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /** | 117 | /** |
118 | * vtbl_check - check if volume table is not corrupted and contains sensible | 118 | * ubi_vtbl_rename_volumes - rename UBI volumes in the volume table. |
119 | * data. | 119 | * @ubi: UBI device description object |
120 | * @rename_list: list of &struct ubi_rename_entry objects | ||
121 | * | ||
122 | * This function re-names multiple volumes specified in @req in the volume | ||
123 | * table. Returns zero in case of success and a negative error code in case of | ||
124 | * failure. | ||
125 | */ | ||
126 | int ubi_vtbl_rename_volumes(struct ubi_device *ubi, | ||
127 | struct list_head *rename_list) | ||
128 | { | ||
129 | int i, err; | ||
130 | struct ubi_rename_entry *re; | ||
131 | struct ubi_volume *layout_vol; | ||
132 | |||
133 | list_for_each_entry(re, rename_list, list) { | ||
134 | uint32_t crc; | ||
135 | struct ubi_volume *vol = re->desc->vol; | ||
136 | struct ubi_vtbl_record *vtbl_rec = &ubi->vtbl[vol->vol_id]; | ||
137 | |||
138 | if (re->remove) { | ||
139 | memcpy(vtbl_rec, &empty_vtbl_record, | ||
140 | sizeof(struct ubi_vtbl_record)); | ||
141 | continue; | ||
142 | } | ||
143 | |||
144 | vtbl_rec->name_len = cpu_to_be16(re->new_name_len); | ||
145 | memcpy(vtbl_rec->name, re->new_name, re->new_name_len); | ||
146 | memset(vtbl_rec->name + re->new_name_len, 0, | ||
147 | UBI_VOL_NAME_MAX + 1 - re->new_name_len); | ||
148 | crc = crc32(UBI_CRC32_INIT, vtbl_rec, | ||
149 | UBI_VTBL_RECORD_SIZE_CRC); | ||
150 | vtbl_rec->crc = cpu_to_be32(crc); | ||
151 | } | ||
152 | |||
153 | layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; | ||
154 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { | ||
155 | err = ubi_eba_unmap_leb(ubi, layout_vol, i); | ||
156 | if (err) | ||
157 | return err; | ||
158 | |||
159 | err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, | ||
160 | ubi->vtbl_size, UBI_LONGTERM); | ||
161 | if (err) | ||
162 | return err; | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * vtbl_check - check if volume table is not corrupted and sensible. | ||
120 | * @ubi: UBI device description object | 170 | * @ubi: UBI device description object |
121 | * @vtbl: volume table | 171 | * @vtbl: volume table |
122 | * | 172 | * |
@@ -127,7 +177,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
127 | const struct ubi_vtbl_record *vtbl) | 177 | const struct ubi_vtbl_record *vtbl) |
128 | { | 178 | { |
129 | int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; | 179 | int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; |
130 | int upd_marker; | 180 | int upd_marker, err; |
131 | uint32_t crc; | 181 | uint32_t crc; |
132 | const char *name; | 182 | const char *name; |
133 | 183 | ||
@@ -153,7 +203,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
153 | if (reserved_pebs == 0) { | 203 | if (reserved_pebs == 0) { |
154 | if (memcmp(&vtbl[i], &empty_vtbl_record, | 204 | if (memcmp(&vtbl[i], &empty_vtbl_record, |
155 | UBI_VTBL_RECORD_SIZE)) { | 205 | UBI_VTBL_RECORD_SIZE)) { |
156 | dbg_err("bad empty record"); | 206 | err = 2; |
157 | goto bad; | 207 | goto bad; |
158 | } | 208 | } |
159 | continue; | 209 | continue; |
@@ -161,56 +211,57 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
161 | 211 | ||
162 | if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || | 212 | if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || |
163 | name_len < 0) { | 213 | name_len < 0) { |
164 | dbg_err("negative values"); | 214 | err = 3; |
165 | goto bad; | 215 | goto bad; |
166 | } | 216 | } |
167 | 217 | ||
168 | if (alignment > ubi->leb_size || alignment == 0) { | 218 | if (alignment > ubi->leb_size || alignment == 0) { |
169 | dbg_err("bad alignment"); | 219 | err = 4; |
170 | goto bad; | 220 | goto bad; |
171 | } | 221 | } |
172 | 222 | ||
173 | n = alignment % ubi->min_io_size; | 223 | n = alignment & (ubi->min_io_size - 1); |
174 | if (alignment != 1 && n) { | 224 | if (alignment != 1 && n) { |
175 | dbg_err("alignment is not multiple of min I/O unit"); | 225 | err = 5; |
176 | goto bad; | 226 | goto bad; |
177 | } | 227 | } |
178 | 228 | ||
179 | n = ubi->leb_size % alignment; | 229 | n = ubi->leb_size % alignment; |
180 | if (data_pad != n) { | 230 | if (data_pad != n) { |
181 | dbg_err("bad data_pad, has to be %d", n); | 231 | dbg_err("bad data_pad, has to be %d", n); |
232 | err = 6; | ||
182 | goto bad; | 233 | goto bad; |
183 | } | 234 | } |
184 | 235 | ||
185 | if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { | 236 | if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { |
186 | dbg_err("bad vol_type"); | 237 | err = 7; |
187 | goto bad; | 238 | goto bad; |
188 | } | 239 | } |
189 | 240 | ||
190 | if (upd_marker != 0 && upd_marker != 1) { | 241 | if (upd_marker != 0 && upd_marker != 1) { |
191 | dbg_err("bad upd_marker"); | 242 | err = 8; |
192 | goto bad; | 243 | goto bad; |
193 | } | 244 | } |
194 | 245 | ||
195 | if (reserved_pebs > ubi->good_peb_count) { | 246 | if (reserved_pebs > ubi->good_peb_count) { |
196 | dbg_err("too large reserved_pebs, good PEBs %d", | 247 | dbg_err("too large reserved_pebs, good PEBs %d", |
197 | ubi->good_peb_count); | 248 | ubi->good_peb_count); |
249 | err = 9; | ||
198 | goto bad; | 250 | goto bad; |
199 | } | 251 | } |
200 | 252 | ||
201 | if (name_len > UBI_VOL_NAME_MAX) { | 253 | if (name_len > UBI_VOL_NAME_MAX) { |
202 | dbg_err("too long volume name, max %d", | 254 | err = 10; |
203 | UBI_VOL_NAME_MAX); | ||
204 | goto bad; | 255 | goto bad; |
205 | } | 256 | } |
206 | 257 | ||
207 | if (name[0] == '\0') { | 258 | if (name[0] == '\0') { |
208 | dbg_err("NULL volume name"); | 259 | err = 11; |
209 | goto bad; | 260 | goto bad; |
210 | } | 261 | } |
211 | 262 | ||
212 | if (name_len != strnlen(name, name_len + 1)) { | 263 | if (name_len != strnlen(name, name_len + 1)) { |
213 | dbg_err("bad name_len"); | 264 | err = 12; |
214 | goto bad; | 265 | goto bad; |
215 | } | 266 | } |
216 | } | 267 | } |
@@ -235,7 +286,7 @@ static int vtbl_check(const struct ubi_device *ubi, | |||
235 | return 0; | 286 | return 0; |
236 | 287 | ||
237 | bad: | 288 | bad: |
238 | ubi_err("volume table check failed, record %d", i); | 289 | ubi_err("volume table check failed: record %d, error %d", i, err); |
239 | ubi_dbg_dump_vtbl_record(&vtbl[i], i); | 290 | ubi_dbg_dump_vtbl_record(&vtbl[i], i); |
240 | return -EINVAL; | 291 | return -EINVAL; |
241 | } | 292 | } |
@@ -287,7 +338,6 @@ retry: | |||
287 | vid_hdr->data_pad = cpu_to_be32(0); | 338 | vid_hdr->data_pad = cpu_to_be32(0); |
288 | vid_hdr->lnum = cpu_to_be32(copy); | 339 | vid_hdr->lnum = cpu_to_be32(copy); |
289 | vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum); | 340 | vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum); |
290 | vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0); | ||
291 | 341 | ||
292 | /* The EC header is already there, write the VID header */ | 342 | /* The EC header is already there, write the VID header */ |
293 | err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); | 343 | err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); |
@@ -370,7 +420,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
370 | * to LEB 0. | 420 | * to LEB 0. |
371 | */ | 421 | */ |
372 | 422 | ||
373 | dbg_msg("check layout volume"); | 423 | dbg_gen("check layout volume"); |
374 | 424 | ||
375 | /* Read both LEB 0 and LEB 1 into memory */ | 425 | /* Read both LEB 0 and LEB 1 into memory */ |
376 | ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { | 426 | ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { |
@@ -384,7 +434,16 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
384 | err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, | 434 | err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, |
385 | ubi->vtbl_size); | 435 | ubi->vtbl_size); |
386 | if (err == UBI_IO_BITFLIPS || err == -EBADMSG) | 436 | if (err == UBI_IO_BITFLIPS || err == -EBADMSG) |
387 | /* Scrub the PEB later */ | 437 | /* |
438 | * Scrub the PEB later. Note, -EBADMSG indicates an | ||
439 | * uncorrectable ECC error, but we have our own CRC and | ||
440 | * the data will be checked later. If the data is OK, | ||
441 | * the PEB will be scrubbed (because we set | ||
442 | * seb->scrub). If the data is not OK, the contents of | ||
443 | * the PEB will be recovered from the second copy, and | ||
444 | * seb->scrub will be cleared in | ||
445 | * 'ubi_scan_add_used()'. | ||
446 | */ | ||
388 | seb->scrub = 1; | 447 | seb->scrub = 1; |
389 | else if (err) | 448 | else if (err) |
390 | goto out_free; | 449 | goto out_free; |
@@ -400,7 +459,8 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
400 | if (!leb_corrupted[0]) { | 459 | if (!leb_corrupted[0]) { |
401 | /* LEB 0 is OK */ | 460 | /* LEB 0 is OK */ |
402 | if (leb[1]) | 461 | if (leb[1]) |
403 | leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); | 462 | leb_corrupted[1] = memcmp(leb[0], leb[1], |
463 | ubi->vtbl_size); | ||
404 | if (leb_corrupted[1]) { | 464 | if (leb_corrupted[1]) { |
405 | ubi_warn("volume table copy #2 is corrupted"); | 465 | ubi_warn("volume table copy #2 is corrupted"); |
406 | err = create_vtbl(ubi, si, 1, leb[0]); | 466 | err = create_vtbl(ubi, si, 1, leb[0]); |
@@ -620,30 +680,32 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, | |||
620 | static int check_sv(const struct ubi_volume *vol, | 680 | static int check_sv(const struct ubi_volume *vol, |
621 | const struct ubi_scan_volume *sv) | 681 | const struct ubi_scan_volume *sv) |
622 | { | 682 | { |
683 | int err; | ||
684 | |||
623 | if (sv->highest_lnum >= vol->reserved_pebs) { | 685 | if (sv->highest_lnum >= vol->reserved_pebs) { |
624 | dbg_err("bad highest_lnum"); | 686 | err = 1; |
625 | goto bad; | 687 | goto bad; |
626 | } | 688 | } |
627 | if (sv->leb_count > vol->reserved_pebs) { | 689 | if (sv->leb_count > vol->reserved_pebs) { |
628 | dbg_err("bad leb_count"); | 690 | err = 2; |
629 | goto bad; | 691 | goto bad; |
630 | } | 692 | } |
631 | if (sv->vol_type != vol->vol_type) { | 693 | if (sv->vol_type != vol->vol_type) { |
632 | dbg_err("bad vol_type"); | 694 | err = 3; |
633 | goto bad; | 695 | goto bad; |
634 | } | 696 | } |
635 | if (sv->used_ebs > vol->reserved_pebs) { | 697 | if (sv->used_ebs > vol->reserved_pebs) { |
636 | dbg_err("bad used_ebs"); | 698 | err = 4; |
637 | goto bad; | 699 | goto bad; |
638 | } | 700 | } |
639 | if (sv->data_pad != vol->data_pad) { | 701 | if (sv->data_pad != vol->data_pad) { |
640 | dbg_err("bad data_pad"); | 702 | err = 5; |
641 | goto bad; | 703 | goto bad; |
642 | } | 704 | } |
643 | return 0; | 705 | return 0; |
644 | 706 | ||
645 | bad: | 707 | bad: |
646 | ubi_err("bad scanning information"); | 708 | ubi_err("bad scanning information, error %d", err); |
647 | ubi_dbg_dump_sv(sv); | 709 | ubi_dbg_dump_sv(sv); |
648 | ubi_dbg_dump_vol_info(vol); | 710 | ubi_dbg_dump_vol_info(vol); |
649 | return -EINVAL; | 711 | return -EINVAL; |
@@ -672,14 +734,13 @@ static int check_scanning_info(const struct ubi_device *ubi, | |||
672 | return -EINVAL; | 734 | return -EINVAL; |
673 | } | 735 | } |
674 | 736 | ||
675 | if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&& | 737 | if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && |
676 | si->highest_vol_id < UBI_INTERNAL_VOL_START) { | 738 | si->highest_vol_id < UBI_INTERNAL_VOL_START) { |
677 | ubi_err("too large volume ID %d found by scanning", | 739 | ubi_err("too large volume ID %d found by scanning", |
678 | si->highest_vol_id); | 740 | si->highest_vol_id); |
679 | return -EINVAL; | 741 | return -EINVAL; |
680 | } | 742 | } |
681 | 743 | ||
682 | |||
683 | for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { | 744 | for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { |
684 | cond_resched(); | 745 | cond_resched(); |
685 | 746 | ||
@@ -717,8 +778,7 @@ static int check_scanning_info(const struct ubi_device *ubi, | |||
717 | } | 778 | } |
718 | 779 | ||
719 | /** | 780 | /** |
720 | * ubi_read_volume_table - read volume table. | 781 | * ubi_read_volume_table - read the volume table. |
721 | * information. | ||
722 | * @ubi: UBI device description object | 782 | * @ubi: UBI device description object |
723 | * @si: scanning information | 783 | * @si: scanning information |
724 | * | 784 | * |
@@ -797,11 +857,10 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
797 | 857 | ||
798 | out_free: | 858 | out_free: |
799 | vfree(ubi->vtbl); | 859 | vfree(ubi->vtbl); |
800 | for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) | 860 | for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { |
801 | if (ubi->volumes[i]) { | 861 | kfree(ubi->volumes[i]); |
802 | kfree(ubi->volumes[i]); | 862 | ubi->volumes[i] = NULL; |
803 | ubi->volumes[i] = NULL; | 863 | } |
804 | } | ||
805 | return err; | 864 | return err; |
806 | } | 865 | } |
807 | 866 | ||