--- zzzz-none-000/linux-3.10.107/drivers/mtd/ubi/vtbl.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/mtd/ubi/vtbl.c 2021-02-04 17:41:59.000000000 +0000 @@ -30,9 +30,12 @@ * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each * other. This redundancy guarantees robustness to unclean reboots. The volume * table is basically an array of volume table records. Each record contains - * full information about the volume and protected by a CRC checksum. + * full information about the volume and protected by a CRC checksum. Note, + * nowadays we use the atomic LEB change operation when updating the volume + * table, so we do not really need 2 LEBs anymore, but we preserve the older + * design for the backward compatibility reasons. * - * The volume table is changed, it is first changed in RAM. Then LEB 0 is + * When the volume table is changed, it is first changed in RAM. Then LEB 0 is * erased, and the updated volume table is written back to LEB 0. Then same for * LEB 1. This scheme guarantees recoverability from unclean reboots. * @@ -67,6 +70,26 @@ static struct ubi_vtbl_record empty_vtbl_record; /** + * ubi_update_layout_vol - helper for updatting layout volumes on flash + * @ubi: UBI device description object + */ +static int ubi_update_layout_vol(struct ubi_device *ubi) +{ + struct ubi_volume *layout_vol; + int i, err; + + layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; + for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { + err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl, + ubi->vtbl_size); + if (err) + return err; + } + + return 0; +} + +/** * ubi_change_vtbl_record - change volume table record. * @ubi: UBI device description object * @idx: table index to change @@ -80,12 +103,10 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, struct ubi_vtbl_record *vtbl_rec) { - int i, err; + int err; uint32_t crc; - struct ubi_volume *layout_vol; ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); - layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; if (!vtbl_rec) vtbl_rec = &empty_vtbl_record; @@ -95,19 +116,10 @@ } memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { - err = ubi_eba_unmap_leb(ubi, layout_vol, i); - if (err) - return err; - - err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, - ubi->vtbl_size); - if (err) - return err; - } + err = ubi_update_layout_vol(ubi); self_vtbl_check(ubi); - return 0; + return err ? err : 0; } /** @@ -122,9 +134,7 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) { - int i, err; struct ubi_rename_entry *re; - struct ubi_volume *layout_vol; list_for_each_entry(re, rename_list, list) { uint32_t crc; @@ -146,19 +156,7 @@ vtbl_rec->crc = cpu_to_be32(crc); } - layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { - err = ubi_eba_unmap_leb(ubi, layout_vol, i); - if (err) - return err; - - err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, - ubi->vtbl_size); - if (err) - return err; - } - - return 0; + return ubi_update_layout_vol(ubi); } /** @@ -190,7 +188,7 @@ crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); if (be32_to_cpu(vtbl[i].crc) != crc) { - ubi_err("bad CRC at record %u: %#08x, not %#08x", + ubi_err(ubi, "bad CRC at record %u: %#08x, not %#08x", i, crc, be32_to_cpu(vtbl[i].crc)); ubi_dump_vtbl_record(&vtbl[i], i); return 1; @@ -224,7 +222,7 @@ n = ubi->leb_size % alignment; if (data_pad != n) { - ubi_err("bad data_pad, has to be %d", n); + ubi_err(ubi, "bad data_pad, has to be %d", n); err = 6; goto bad; } @@ -240,7 +238,7 @@ } if (reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs %d, good PEBs %d", + ubi_err(ubi, "too large reserved_pebs %d, good PEBs %d", reserved_pebs, ubi->good_peb_count); err = 9; goto bad; @@ -270,7 +268,7 @@ if (len1 > 0 && len1 == len2 && !strncmp(vtbl[i].name, vtbl[n].name, len1)) { - ubi_err("volumes %d and %d have the same name \"%s\"", + ubi_err(ubi, "volumes %d and %d have the same name \"%s\"", i, n, vtbl[i].name); ubi_dump_vtbl_record(&vtbl[i], i); ubi_dump_vtbl_record(&vtbl[n], n); @@ -282,7 +280,7 @@ return 0; bad: - ubi_err("volume table check failed: record %d, error %d", i, err); + ubi_err(ubi, "volume table check failed: record %d, error %d", i, err); ubi_dump_vtbl_record(&vtbl[i], i); return -EINVAL; } @@ -446,11 +444,11 @@ leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); if (leb_corrupted[1]) { - ubi_warn("volume table copy #2 is corrupted"); + ubi_warn(ubi, "volume table copy #2 is corrupted"); err = create_vtbl(ubi, ai, 1, leb[0]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi, "volume table was restored"); } /* Both LEB 1 and LEB 2 are OK and consistent */ @@ -465,15 +463,15 @@ } if (leb_corrupted[1]) { /* Both LEB 0 and LEB 1 are corrupted */ - ubi_err("both volume tables are corrupted"); + ubi_err(ubi, "both volume tables are corrupted"); goto out_free; } - ubi_warn("volume table copy #1 is corrupted"); + ubi_warn(ubi, "volume table copy #1 is corrupted"); err = create_vtbl(ubi, ai, 0, leb[1]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi, "volume table was restored"); vfree(leb[0]); return leb[1]; @@ -559,10 +557,11 @@ vol->name[vol->name_len] = '\0'; vol->vol_id = i; - if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { + if (vtbl[i].flags & (UBI_VTBL_AUTORESIZE_FLG | + UBI_VTBL_AUTORESIZE_FLG_LINUX)) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { - ubi_err("more than one auto-resize volume (%d and %d)", + ubi_err(ubi, "more than one auto-resize volume (%d and %d)", ubi->autoresize_vol_id, i); kfree(vol); return -EINVAL; @@ -591,7 +590,7 @@ /* Static volumes only */ av = ubi_find_av(ai, i); - if (!av) { + if (!av || !av->leb_count) { /* * No eraseblocks belonging to this volume found. We * don't actually know whether this static volume is @@ -608,7 +607,7 @@ * We found a static volume which misses several * eraseblocks. Treat it as corrupted. */ - ubi_warn("static volume %d misses %d LEBs - corrupted", + ubi_warn(ubi, "static volume %d misses %d LEBs - corrupted", av->vol_id, av->used_ebs - av->leb_count); vol->corrupted = 1; continue; @@ -646,10 +645,10 @@ vol->ubi = ubi; if (reserved_pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs, required %d, available %d", + ubi_err(ubi, "not enough PEBs, required %d, available %d", reserved_pebs, ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, "%d PEBs are corrupted and not used", ubi->corr_peb_count); return -ENOSPC; } @@ -695,7 +694,7 @@ return 0; bad: - ubi_err("bad attaching information, error %d", err); + ubi_err(vol->ubi, "bad attaching information, error %d", err); ubi_dump_av(av); ubi_dump_vol_info(vol); return -EINVAL; @@ -719,14 +718,15 @@ struct ubi_volume *vol; if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { - ubi_err("found %d volumes while attaching, maximum is %d + %d", + ubi_err(ubi, "found %d volumes while attaching, maximum is %d + %d", ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); return -EINVAL; } if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && ai->highest_vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("too large volume ID %d found", ai->highest_vol_id); + ubi_err(ubi, "too large volume ID %d found", + ai->highest_vol_id); return -EINVAL; } @@ -754,7 +754,7 @@ * reboot while the volume was being removed. Discard * these eraseblocks. */ - ubi_msg("finish volume %d removal", av->vol_id); + ubi_msg(ubi, "finish volume %d removal", av->vol_id); ubi_remove_av(ai, av); } else if (av) { err = check_av(vol, av); @@ -808,13 +808,13 @@ if (IS_ERR(ubi->vtbl)) return PTR_ERR(ubi->vtbl); } else { - ubi_err("the layout volume was not found"); + ubi_err(ubi, "the layout volume was not found"); return -EINVAL; } } else { if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { /* This must not happen with proper UBI images */ - ubi_err("too many LEBs (%d) in layout volume", + ubi_err(ubi, "too many LEBs (%d) in layout volume", av->leb_count); return -EINVAL; } @@ -863,7 +863,7 @@ return; if (vtbl_check(ubi, ubi->vtbl)) { - ubi_err("self-check failed"); + ubi_err(ubi, "self-check failed"); BUG(); } }