📄 scan.c
字号:
return -EINVAL; } /* * Now we have to drop the older one and preserve the newer * one. */ cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr); if (cmp_res < 0) return cmp_res; if (cmp_res & 1) { /* * This logical eraseblock is newer then the one * found earlier. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; if (cmp_res & 4) err = add_to_list(si, seb->pnum, seb->ec, &si->corr); else err = add_to_list(si, seb->pnum, seb->ec, &si->erase); if (err) return err; seb->ec = ec; seb->pnum = pnum; seb->scrub = ((cmp_res & 2) || bitflips); seb->sqnum = sqnum; if (sv->highest_lnum == lnum) sv->last_data_size = be32_to_cpu(vid_hdr->data_size); return 0; } else { /* * This logical eraseblock is older then the one found * previously. */ if (cmp_res & 4) return add_to_list(si, pnum, ec, &si->corr); else return add_to_list(si, pnum, ec, &si->erase); } } /* * We've met this logical eraseblock for the first time, add it to the * scanning information. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); if (!seb) return -ENOMEM; seb->ec = ec; seb->pnum = pnum; seb->lnum = lnum; seb->sqnum = sqnum; seb->scrub = bitflips; if (sv->highest_lnum <= lnum) { sv->highest_lnum = lnum; sv->last_data_size = be32_to_cpu(vid_hdr->data_size); } sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); return 0;}/** * ubi_scan_find_sv - find volume in the scanning information. * @si: scanning information * @vol_id: the requested volume ID * * This function returns a pointer to the volume description or %NULL if there * are no data about this volume in the scanning information. */struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, int vol_id){ struct ubi_scan_volume *sv; struct rb_node *p = si->volumes.rb_node; while (p) { sv = rb_entry(p, struct ubi_scan_volume, rb); if (vol_id == sv->vol_id) return sv; if (vol_id > sv->vol_id) p = p->rb_left; else p = p->rb_right; } return NULL;}/** * ubi_scan_find_seb - find LEB in the volume scanning information. * @sv: a pointer to the volume scanning information * @lnum: the requested logical eraseblock * * This function returns a pointer to the scanning logical eraseblock or %NULL * if there are no data about it in the scanning volume information. */struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, int lnum){ struct ubi_scan_leb *seb; struct rb_node *p = sv->root.rb_node; while (p) { seb = rb_entry(p, struct ubi_scan_leb, u.rb); if (lnum == seb->lnum) return seb; if (lnum > seb->lnum) p = p->rb_left; else p = p->rb_right; } return NULL;}/** * ubi_scan_rm_volume - delete scanning information about a volume. * @si: scanning information * @sv: the volume scanning information to delete */void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv){ struct rb_node *rb; struct ubi_scan_leb *seb; dbg_bld("remove scanning information about volume %d", sv->vol_id); while ((rb = rb_first(&sv->root))) { seb = rb_entry(rb, struct ubi_scan_leb, u.rb); rb_erase(&seb->u.rb, &sv->root); list_add_tail(&seb->u.list, &si->erase); } rb_erase(&sv->rb, &si->volumes); kfree(sv); si->vols_found -= 1;}/** * ubi_scan_erase_peb - erase a physical eraseblock. * @ubi: UBI device description object * @si: scanning information * @pnum: physical eraseblock number to erase; * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown) * * This function erases physical eraseblock 'pnum', and writes the erase * counter header to it. This function should only be used on UBI device * initialization stages, when the EBA sub-system had not been yet initialized. * This function returns zero in case of success and a negative error code in * case of failure. */int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, int pnum, int ec){ int err; struct ubi_ec_hdr *ec_hdr; if ((long long)ec >= UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); return -EINVAL; } ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); if (!ec_hdr) return -ENOMEM; ec_hdr->ec = cpu_to_be64(ec); err = ubi_io_sync_erase(ubi, pnum, 0); if (err < 0) goto out_free; err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);out_free: kfree(ec_hdr); return err;}/** * ubi_scan_get_free_peb - get a free physical eraseblock. * @ubi: UBI device description object * @si: scanning information * * This function returns a free physical eraseblock. It is supposed to be * called on the UBI initialization stages when the wear-leveling sub-system is * not initialized yet. This function picks a physical eraseblocks from one of * the lists, writes the EC header if it is needed, and removes it from the * list. * * This function returns scanning physical eraseblock information in case of * success and an error code in case of failure. */struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, struct ubi_scan_info *si){ int err = 0, i; struct ubi_scan_leb *seb; if (!list_empty(&si->free)) { seb = list_entry(si->free.next, struct ubi_scan_leb, u.list); list_del(&seb->u.list); dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec); return seb; } for (i = 0; i < 2; i++) { struct list_head *head; struct ubi_scan_leb *tmp_seb; if (i == 0) head = &si->erase; else head = &si->corr; /* * We try to erase the first physical eraseblock from the @head * list and pick it if we succeed, or try to erase the * next one if not. And so forth. We don't want to take care * about bad eraseblocks here - they'll be handled later. */ list_for_each_entry_safe(seb, tmp_seb, head, u.list) { if (seb->ec == UBI_SCAN_UNKNOWN_EC) seb->ec = si->mean_ec; err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1); if (err) continue; seb->ec += 1; list_del(&seb->u.list); dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec); return seb; } } ubi_err("no eraseblocks found"); return ERR_PTR(-ENOSPC);}/** * process_eb - read, check UBI headers, and add them to scanning information. * @ubi: UBI device description object * @si: scanning information * @pnum: the physical eraseblock number * * This function returns a zero if the physical eraseblock was successfully * handled and a negative error code in case of failure. */static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum){ long long uninitialized_var(ec); int err, bitflips = 0, vol_id, ec_corr = 0; dbg_bld("scan PEB %d", pnum); /* Skip bad physical eraseblocks */ err = ubi_io_is_bad(ubi, pnum); if (err < 0) return err; else if (err) { /* * FIXME: this is actually duty of the I/O sub-system to * initialize this, but MTD does not provide enough * information. */ si->bad_peb_count += 1; return 0; } err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (err < 0) return err; else if (err == UBI_IO_BITFLIPS) bitflips = 1; else if (err == UBI_IO_PEB_EMPTY) return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); else if (err == UBI_IO_BAD_EC_HDR) { /* * We have to also look at the VID header, possibly it is not * corrupted. Set %bitflips flag in order to make this PEB be * moved and EC be re-created. */ ec_corr = 1; ec = UBI_SCAN_UNKNOWN_EC; bitflips = 1; } si->is_empty = 0; if (!ec_corr) { /* Make sure UBI version is OK */ if (ech->version != UBI_VERSION) { ubi_err("this UBI version is %d, image version is %d", UBI_VERSION, (int)ech->version); return -EINVAL; } ec = be64_to_cpu(ech->ec); if (ec > UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. The EC headers have 64 bits * reserved, but we anyway make use of only 31 bit * values, as this seems to be enough for any existing * flash. Upgrade UBI and use 64-bit erase counters * internally. */ ubi_err("erase counter overflow, max is %d", UBI_MAX_ERASECOUNTER); ubi_dbg_dump_ec_hdr(ech); return -EINVAL; } } /* OK, we've done with the EC header, let's look at the VID header */ err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); if (err < 0) return err; else if (err == UBI_IO_BITFLIPS) bitflips = 1; else if (err == UBI_IO_BAD_VID_HDR || (err == UBI_IO_PEB_FREE && ec_corr)) { /* VID header is corrupted */ err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; goto adjust_mean_ec; } else if (err == UBI_IO_PEB_FREE) { /* No VID header - the physical eraseblock is free */ err = add_to_list(si, pnum, ec, &si->free); if (err) return err; goto adjust_mean_ec; } vol_id = be32_to_cpu(vidh->vol_id); if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { int lnum = be32_to_cpu(vidh->lnum); /* Unsupported internal volume */ switch (vidh->compat) { case UBI_COMPAT_DELETE: ubi_msg("\"delete\" compatible internal volume %d:%d" " found, remove it", vol_id, lnum); err = add_to_list(si, pnum, ec, &si->corr); if (err) return err; break; case UBI_COMPAT_RO: ubi_msg("read-only compatible internal volume %d:%d" " found, switch to read-only mode", vol_id, lnum); ubi->ro_mode = 1; break; case UBI_COMPAT_PRESERVE: ubi_msg("\"preserve\" compatible internal volume %d:%d" " found", vol_id, lnum); err = add_to_list(si, pnum, ec, &si->alien); if (err) return err; si->alien_peb_count += 1; return 0; case UBI_COMPAT_REJECT: ubi_err("incompatible internal volume %d:%d found", vol_id, lnum); return -EINVAL; } } /* Both UBI headers seem to be fine */ err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips); if (err) return err;adjust_mean_ec: if (!ec_corr) { si->ec_sum += ec; si->ec_count += 1; if (ec > si->max_ec) si->max_ec = ec; if (ec < si->min_ec) si->min_ec = ec; } return 0;}/** * ubi_scan - scan an MTD device. * @ubi: UBI device description object * * This function does full scanning of an MTD device and returns complete * information about it. In case of failure, an error code is returned. */struct ubi_scan_info *ubi_scan(struct ubi_device *ubi){ int err, pnum; struct rb_node *rb1, *rb2; struct ubi_scan_volume *sv; struct ubi_scan_leb *seb; struct ubi_scan_info *si; si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL); if (!si) return ERR_PTR(-ENOMEM);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -