📄 scan.c
字号:
INIT_LIST_HEAD(&si->corr); INIT_LIST_HEAD(&si->free); INIT_LIST_HEAD(&si->erase); INIT_LIST_HEAD(&si->alien); si->volumes = RB_ROOT; si->is_empty = 1; err = -ENOMEM; ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); if (!ech) goto out_si; vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vidh) goto out_ech; for (pnum = 0; pnum < ubi->peb_count; pnum++) { cond_resched(); dbg_gen("process PEB %d", pnum); err = process_eb(ubi, si, pnum); if (err < 0) goto out_vidh; } dbg_msg("scanning is finished"); /* Calculate mean erase counter */ if (si->ec_count) { do_div(si->ec_sum, si->ec_count); si->mean_ec = si->ec_sum; } if (si->is_empty) ubi_msg("empty MTD device detected"); /* * In case of unknown erase counter we use the mean erase counter * value. */ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) if (seb->ec == UBI_SCAN_UNKNOWN_EC) seb->ec = si->mean_ec; } list_for_each_entry(seb, &si->free, u.list) { if (seb->ec == UBI_SCAN_UNKNOWN_EC) seb->ec = si->mean_ec; } list_for_each_entry(seb, &si->corr, u.list) if (seb->ec == UBI_SCAN_UNKNOWN_EC) seb->ec = si->mean_ec; list_for_each_entry(seb, &si->erase, u.list) if (seb->ec == UBI_SCAN_UNKNOWN_EC) seb->ec = si->mean_ec; err = paranoid_check_si(ubi, si); if (err) { if (err > 0) err = -EINVAL; goto out_vidh; } ubi_free_vid_hdr(ubi, vidh); kfree(ech); return si;out_vidh: ubi_free_vid_hdr(ubi, vidh);out_ech: kfree(ech);out_si: ubi_scan_destroy_si(si); return ERR_PTR(err);}/** * destroy_sv - free the scanning volume information * @sv: scanning volume information * * This function destroys the volume RB-tree (@sv->root) and the scanning * volume information. */static void destroy_sv(struct ubi_scan_volume *sv){ struct ubi_scan_leb *seb; struct rb_node *this = sv->root.rb_node; while (this) { if (this->rb_left) this = this->rb_left; else if (this->rb_right) this = this->rb_right; else { seb = rb_entry(this, struct ubi_scan_leb, u.rb); this = rb_parent(this); if (this) { if (this->rb_left == &seb->u.rb) this->rb_left = NULL; else this->rb_right = NULL; } kfree(seb); } } kfree(sv);}/** * ubi_scan_destroy_si - destroy scanning information. * @si: scanning information */void ubi_scan_destroy_si(struct ubi_scan_info *si){ struct ubi_scan_leb *seb, *seb_tmp; struct ubi_scan_volume *sv; struct rb_node *rb; list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) { list_del(&seb->u.list); kfree(seb); } list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) { list_del(&seb->u.list); kfree(seb); } list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) { list_del(&seb->u.list); kfree(seb); } list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) { list_del(&seb->u.list); kfree(seb); } /* Destroy the volume RB-tree */ rb = si->volumes.rb_node; while (rb) { if (rb->rb_left) rb = rb->rb_left; else if (rb->rb_right) rb = rb->rb_right; else { sv = rb_entry(rb, struct ubi_scan_volume, rb); rb = rb_parent(rb); if (rb) { if (rb->rb_left == &sv->rb) rb->rb_left = NULL; else rb->rb_right = NULL; } destroy_sv(sv); } } kfree(si);}#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID/** * paranoid_check_si - check the scanning information. * @ubi: UBI device description object * @si: scanning information * * This function returns zero if the scanning information is all right, %1 if * not and a negative error code if an error occurred. */static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si){ int pnum, err, vols_found = 0; struct rb_node *rb1, *rb2; struct ubi_scan_volume *sv; struct ubi_scan_leb *seb, *last_seb; uint8_t *buf; /* * At first, check that scanning information is OK. */ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { int leb_count = 0; cond_resched(); vols_found += 1; if (si->is_empty) { ubi_err("bad is_empty flag"); goto bad_sv; } if (sv->vol_id < 0 || sv->highest_lnum < 0 || sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 || sv->data_pad < 0 || sv->last_data_size < 0) { ubi_err("negative values"); goto bad_sv; } if (sv->vol_id >= UBI_MAX_VOLUMES && sv->vol_id < UBI_INTERNAL_VOL_START) { ubi_err("bad vol_id"); goto bad_sv; } if (sv->vol_id > si->highest_vol_id) { ubi_err("highest_vol_id is %d, but vol_id %d is there", si->highest_vol_id, sv->vol_id); goto out; } if (sv->vol_type != UBI_DYNAMIC_VOLUME && sv->vol_type != UBI_STATIC_VOLUME) { ubi_err("bad vol_type"); goto bad_sv; } if (sv->data_pad > ubi->leb_size / 2) { ubi_err("bad data_pad"); goto bad_sv; } last_seb = NULL; ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { cond_resched(); last_seb = seb; leb_count += 1; if (seb->pnum < 0 || seb->ec < 0) { ubi_err("negative values"); goto bad_seb; } if (seb->ec < si->min_ec) { ubi_err("bad si->min_ec (%d), %d found", si->min_ec, seb->ec); goto bad_seb; } if (seb->ec > si->max_ec) { ubi_err("bad si->max_ec (%d), %d found", si->max_ec, seb->ec); goto bad_seb; } if (seb->pnum >= ubi->peb_count) { ubi_err("too high PEB number %d, total PEBs %d", seb->pnum, ubi->peb_count); goto bad_seb; } if (sv->vol_type == UBI_STATIC_VOLUME) { if (seb->lnum >= sv->used_ebs) { ubi_err("bad lnum or used_ebs"); goto bad_seb; } } else { if (sv->used_ebs != 0) { ubi_err("non-zero used_ebs"); goto bad_seb; } } if (seb->lnum > sv->highest_lnum) { ubi_err("incorrect highest_lnum or lnum"); goto bad_seb; } } if (sv->leb_count != leb_count) { ubi_err("bad leb_count, %d objects in the tree", leb_count); goto bad_sv; } if (!last_seb) continue; seb = last_seb; if (seb->lnum != sv->highest_lnum) { ubi_err("bad highest_lnum"); goto bad_seb; } } if (vols_found != si->vols_found) { ubi_err("bad si->vols_found %d, should be %d", si->vols_found, vols_found); goto out; } /* Check that scanning information is correct */ ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { last_seb = NULL; ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { int vol_type; cond_resched(); last_seb = seb; err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1); if (err && err != UBI_IO_BITFLIPS) { ubi_err("VID header is not OK (%d)", err); if (err > 0) err = -EIO; return err; } vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; if (sv->vol_type != vol_type) { ubi_err("bad vol_type"); goto bad_vid_hdr; } if (seb->sqnum != be64_to_cpu(vidh->sqnum)) { ubi_err("bad sqnum %llu", seb->sqnum); goto bad_vid_hdr; } if (sv->vol_id != be32_to_cpu(vidh->vol_id)) { ubi_err("bad vol_id %d", sv->vol_id); goto bad_vid_hdr; } if (sv->compat != vidh->compat) { ubi_err("bad compat %d", vidh->compat); goto bad_vid_hdr; } if (seb->lnum != be32_to_cpu(vidh->lnum)) { ubi_err("bad lnum %d", seb->lnum); goto bad_vid_hdr; } if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) { ubi_err("bad used_ebs %d", sv->used_ebs); goto bad_vid_hdr; } if (sv->data_pad != be32_to_cpu(vidh->data_pad)) { ubi_err("bad data_pad %d", sv->data_pad); goto bad_vid_hdr; } } if (!last_seb) continue; if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) { ubi_err("bad highest_lnum %d", sv->highest_lnum); goto bad_vid_hdr; } if (sv->last_data_size != be32_to_cpu(vidh->data_size)) { ubi_err("bad last_data_size %d", sv->last_data_size); goto bad_vid_hdr; } } /* * Make sure that all the physical eraseblocks are in one of the lists * or trees. */ buf = kzalloc(ubi->peb_count, GFP_KERNEL); if (!buf) return -ENOMEM; for (pnum = 0; pnum < ubi->peb_count; pnum++) { err = ubi_io_is_bad(ubi, pnum); if (err < 0) { kfree(buf); return err; } else if (err) buf[pnum] = 1; } ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) buf[seb->pnum] = 1; list_for_each_entry(seb, &si->free, u.list) buf[seb->pnum] = 1; list_for_each_entry(seb, &si->corr, u.list) buf[seb->pnum] = 1; list_for_each_entry(seb, &si->erase, u.list) buf[seb->pnum] = 1; list_for_each_entry(seb, &si->alien, u.list) buf[seb->pnum] = 1; err = 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) if (!buf[pnum]) { ubi_err("PEB %d is not referred", pnum); err = 1; } kfree(buf); if (err) goto out; return 0;bad_seb: ubi_err("bad scanning information about LEB %d", seb->lnum); ubi_dbg_dump_seb(seb, 0); ubi_dbg_dump_sv(sv); goto out;bad_sv: ubi_err("bad scanning information about volume %d", sv->vol_id); ubi_dbg_dump_sv(sv); goto out;bad_vid_hdr: ubi_err("bad scanning information about volume %d", sv->vol_id); ubi_dbg_dump_sv(sv); ubi_dbg_dump_vid_hdr(vidh);out: ubi_dbg_dump_stack(); return 1;}#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -