📄 vtbl.c
字号:
err = create_vtbl(ubi, si, 1, leb[0]); if (err) goto out_free; ubi_msg("volume table was restored"); } /* Both LEB 1 and LEB 2 are OK and consistent */ vfree(leb[1]); return leb[0]; } else { /* LEB 0 is corrupted or does not exist */ if (leb[1]) { leb_corrupted[1] = vtbl_check(ubi, leb[1]); if (leb_corrupted[1] < 0) goto out_free; } if (leb_corrupted[1]) { /* Both LEB 0 and LEB 1 are corrupted */ ubi_err("both volume tables are corrupted"); goto out_free; } ubi_warn("volume table copy #1 is corrupted"); err = create_vtbl(ubi, si, 0, leb[1]); if (err) goto out_free; ubi_msg("volume table was restored"); vfree(leb[0]); return leb[1]; }out_free: vfree(leb[0]); vfree(leb[1]); return ERR_PTR(err);}/** * create_empty_lvol - create empty layout volume. * @ubi: UBI device description object * @si: scanning information * * This function returns volume table contents in case of success and a * negative error code in case of failure. */static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, struct ubi_scan_info *si){ int i; struct ubi_vtbl_record *vtbl; vtbl = vmalloc(ubi->vtbl_size); if (!vtbl) return ERR_PTR(-ENOMEM); memset(vtbl, 0, ubi->vtbl_size); for (i = 0; i < ubi->vtbl_slots; i++) memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { int err; err = create_vtbl(ubi, si, i, vtbl); if (err) { vfree(vtbl); return ERR_PTR(err); } } return vtbl;}/** * init_volumes - initialize volume information for existing volumes. * @ubi: UBI device description object * @si: scanning information * @vtbl: volume table * * This function allocates volume description objects for existing volumes. * Returns zero in case of success and a negative error code in case of * failure. */static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, const struct ubi_vtbl_record *vtbl){ int i, reserved_pebs = 0; struct ubi_scan_volume *sv; struct ubi_volume *vol; for (i = 0; i < ubi->vtbl_slots; i++) { cond_resched(); if (be32_to_cpu(vtbl[i].reserved_pebs) == 0) continue; /* Empty record */ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); if (!vol) return -ENOMEM; vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); vol->alignment = be32_to_cpu(vtbl[i].alignment); vol->data_pad = be32_to_cpu(vtbl[i].data_pad); vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; vol->name_len = be16_to_cpu(vtbl[i].name_len); vol->usable_leb_size = ubi->leb_size - vol->data_pad; memcpy(vol->name, vtbl[i].name, vol->name_len); vol->name[vol->name_len] = '\0'; vol->vol_id = i; if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { ubi_err("more then one auto-resize volume (%d " "and %d)", ubi->autoresize_vol_id, i); kfree(vol); return -EINVAL; } ubi->autoresize_vol_id = i; } ubi_assert(!ubi->volumes[i]); ubi->volumes[i] = vol; ubi->vol_count += 1; vol->ubi = ubi; reserved_pebs += vol->reserved_pebs; /* * In case of dynamic volume UBI knows nothing about how many * data is stored there. So assume the whole volume is used. */ if (vol->vol_type == UBI_DYNAMIC_VOLUME) { vol->used_ebs = vol->reserved_pebs; vol->last_eb_bytes = vol->usable_leb_size; vol->used_bytes = (long long)vol->used_ebs * vol->usable_leb_size; continue; } /* Static volumes only */ sv = ubi_scan_find_sv(si, i); if (!sv) { /* * No eraseblocks belonging to this volume found. We * don't actually know whether this static volume is * completely corrupted or just contains no data. And * we cannot know this as long as data size is not * stored on flash. So we just assume the volume is * empty. FIXME: this should be handled. */ continue; } if (sv->leb_count != sv->used_ebs) { /* * We found a static volume which misses several * eraseblocks. Treat it as corrupted. */ ubi_warn("static volume %d misses %d LEBs - corrupted", sv->vol_id, sv->used_ebs - sv->leb_count); vol->corrupted = 1; continue; } vol->used_ebs = sv->used_ebs; vol->used_bytes = (long long)(vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes += sv->last_data_size; vol->last_eb_bytes = sv->last_data_size; } /* And add the layout volume */ vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); if (!vol) return -ENOMEM; vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS; vol->alignment = 1; vol->vol_type = UBI_DYNAMIC_VOLUME; vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1; memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1); vol->usable_leb_size = ubi->leb_size; vol->used_ebs = vol->reserved_pebs; vol->last_eb_bytes = vol->reserved_pebs; vol->used_bytes = (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); vol->vol_id = UBI_LAYOUT_VOLUME_ID; vol->ref_count = 1; ubi_assert(!ubi->volumes[i]); ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; reserved_pebs += vol->reserved_pebs; ubi->vol_count += 1; vol->ubi = ubi; if (reserved_pebs > ubi->avail_pebs) ubi_err("not enough PEBs, required %d, available %d", reserved_pebs, ubi->avail_pebs); ubi->rsvd_pebs += reserved_pebs; ubi->avail_pebs -= reserved_pebs; return 0;}/** * check_sv - check volume scanning information. * @vol: UBI volume description object * @sv: volume scanning information * * This function returns zero if the volume scanning information is consistent * to the data read from the volume tabla, and %-EINVAL if not. */static int check_sv(const struct ubi_volume *vol, const struct ubi_scan_volume *sv){ int err; if (sv->highest_lnum >= vol->reserved_pebs) { err = 1; goto bad; } if (sv->leb_count > vol->reserved_pebs) { err = 2; goto bad; } if (sv->vol_type != vol->vol_type) { err = 3; goto bad; } if (sv->used_ebs > vol->reserved_pebs) { err = 4; goto bad; } if (sv->data_pad != vol->data_pad) { err = 5; goto bad; } return 0;bad: ubi_err("bad scanning information, error %d", err); ubi_dbg_dump_sv(sv); ubi_dbg_dump_vol_info(vol); return -EINVAL;}/** * check_scanning_info - check that scanning information. * @ubi: UBI device description object * @si: scanning information * * Even though we protect on-flash data by CRC checksums, we still don't trust * the media. This function ensures that scanning information is consistent to * the information read from the volume table. Returns zero if the scanning * information is OK and %-EINVAL if it is not. */static int check_scanning_info(const struct ubi_device *ubi, struct ubi_scan_info *si){ int err, i; struct ubi_scan_volume *sv; struct ubi_volume *vol; if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { ubi_err("scanning found %d volumes, maximum is %d + %d", si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); return -EINVAL; } if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && si->highest_vol_id < UBI_INTERNAL_VOL_START) { ubi_err("too large volume ID %d found by scanning", si->highest_vol_id); return -EINVAL; } for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { cond_resched(); sv = ubi_scan_find_sv(si, i); vol = ubi->volumes[i]; if (!vol) { if (sv) ubi_scan_rm_volume(si, sv); continue; } if (vol->reserved_pebs == 0) { ubi_assert(i < ubi->vtbl_slots); if (!sv) continue; /* * During scanning we found a volume which does not * exist according to the information in the volume * table. This must have happened due to an unclean * reboot while the volume was being removed. Discard * these eraseblocks. */ ubi_msg("finish volume %d removal", sv->vol_id); ubi_scan_rm_volume(si, sv); } else if (sv) { err = check_sv(vol, sv); if (err) return err; } } return 0;}/** * ubi_read_volume_table - read volume table. * information. * @ubi: UBI device description object * @si: scanning information * * This function reads volume table, checks it, recover from errors if needed, * or creates it if needed. Returns zero in case of success and a negative * error code in case of failure. */int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si){ int i, err; struct ubi_scan_volume *sv; empty_vtbl_record.crc = cpu_to_be32(0xf116c36b); /* * The number of supported volumes is limited by the eraseblock size * and by the UBI_MAX_VOLUMES constant. */ ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE; if (ubi->vtbl_slots > UBI_MAX_VOLUMES) ubi->vtbl_slots = UBI_MAX_VOLUMES; ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); if (!sv) { /* * No logical eraseblocks belonging to the layout volume were * found. This could mean that the flash is just empty. In * this case we create empty layout volume. * * But if flash is not empty this must be a corruption or the * MTD device just contains garbage. */ if (si->is_empty) { ubi->vtbl = create_empty_lvol(ubi, si); if (IS_ERR(ubi->vtbl)) return PTR_ERR(ubi->vtbl); } else { ubi_err("the layout volume was not found"); return -EINVAL; } } else { if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) { /* This must not happen with proper UBI images */ dbg_err("too many LEBs (%d) in layout volume", sv->leb_count); return -EINVAL; } ubi->vtbl = process_lvol(ubi, si, sv); if (IS_ERR(ubi->vtbl)) return PTR_ERR(ubi->vtbl); } ubi->avail_pebs = ubi->good_peb_count; /* * The layout volume is OK, initialize the corresponding in-RAM data * structures. */ err = init_volumes(ubi, si, ubi->vtbl); if (err) goto out_free; /* * Get sure that the scanning information is consistent to the * information stored in the volume table. */ err = check_scanning_info(ubi, si); if (err) goto out_free; return 0;out_free: vfree(ubi->vtbl); for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) if (ubi->volumes[i]) { kfree(ubi->volumes[i]); ubi->volumes[i] = NULL; } return err;}#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID/** * paranoid_vtbl_check - check volume table. * @ubi: UBI device description object */static void paranoid_vtbl_check(const struct ubi_device *ubi){ if (vtbl_check(ubi, ubi->vtbl)) { ubi_err("paranoid check failed"); BUG(); }}#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -