in ubi/attach.c [1658:1923]
static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
struct ubi_vid_io_buf *vidb = ai->vidb;
struct ubi_vid_hdr *vidh = ubi_get_vid_hdr(vidb);
int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2;
struct ubi_ainf_volume *av;
struct ubi_ainf_peb *aeb, *last_aeb;
uint8_t *buf;
if (!ubi_dbg_chk_gen(ubi))
return 0;
/*
* At first, check that attaching information is OK.
*/
ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
int leb_count = 0;
cond_resched();
vols_found += 1;
if (ai->is_empty) {
ubi_err(ubi, "bad is_empty flag");
goto bad_av;
}
if (av->vol_id < 0 || av->highest_lnum < 0 ||
av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
av->data_pad < 0 || av->last_data_size < 0) {
ubi_err(ubi, "negative values");
goto bad_av;
}
if (av->vol_id >= UBI_MAX_VOLUMES &&
av->vol_id < UBI_INTERNAL_VOL_START) {
ubi_err(ubi, "bad vol_id");
goto bad_av;
}
if (av->vol_id > ai->highest_vol_id) {
ubi_err(ubi, "highest_vol_id is %d, but vol_id %d is there",
ai->highest_vol_id, av->vol_id);
goto out;
}
if (av->vol_type != UBI_DYNAMIC_VOLUME &&
av->vol_type != UBI_STATIC_VOLUME) {
ubi_err(ubi, "bad vol_type");
goto bad_av;
}
if (av->data_pad > ubi->leb_size / 2) {
ubi_err(ubi, "bad data_pad");
goto bad_av;
}
last_aeb = NULL;
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
cond_resched();
last_aeb = aeb;
leb_count += 1;
if (aeb->pnum < 0 || aeb->ec < 0) {
ubi_err(ubi, "negative values");
goto bad_aeb;
}
if (aeb->ec < ai->min_ec) {
ubi_err(ubi, "bad ai->min_ec (%d), %d found",
ai->min_ec, aeb->ec);
goto bad_aeb;
}
if (aeb->ec > ai->max_ec) {
ubi_err(ubi, "bad ai->max_ec (%d), %d found",
ai->max_ec, aeb->ec);
goto bad_aeb;
}
if (aeb->pnum >= ubi->peb_count) {
ubi_err(ubi, "too high PEB number %d, total PEBs %d",
aeb->pnum, ubi->peb_count);
goto bad_aeb;
}
if (av->vol_type == UBI_STATIC_VOLUME) {
if (aeb->lnum >= av->used_ebs) {
ubi_err(ubi, "bad lnum or used_ebs");
goto bad_aeb;
}
} else {
if (av->used_ebs != 0) {
ubi_err(ubi, "non-zero used_ebs");
goto bad_aeb;
}
}
if (aeb->lnum > av->highest_lnum) {
ubi_err(ubi, "incorrect highest_lnum or lnum");
goto bad_aeb;
}
}
if (av->leb_count != leb_count) {
ubi_err(ubi, "bad leb_count, %d objects in the tree",
leb_count);
goto bad_av;
}
if (!last_aeb)
continue;
aeb = last_aeb;
if (aeb->lnum != av->highest_lnum) {
ubi_err(ubi, "bad highest_lnum");
goto bad_aeb;
}
}
if (vols_found != ai->vols_found) {
ubi_err(ubi, "bad ai->vols_found %d, should be %d",
ai->vols_found, vols_found);
goto out;
}
/* Check that attaching information is correct */
ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
last_aeb = NULL;
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
int vol_type;
cond_resched();
last_aeb = aeb;
err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidb, 1);
if (err && err != UBI_IO_BITFLIPS) {
ubi_err(ubi, "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 (av->vol_type != vol_type) {
ubi_err(ubi, "bad vol_type");
goto bad_vid_hdr;
}
if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
ubi_err(ubi, "bad sqnum %llu", aeb->sqnum);
goto bad_vid_hdr;
}
if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
ubi_err(ubi, "bad vol_id %d", av->vol_id);
goto bad_vid_hdr;
}
if (av->compat != vidh->compat) {
ubi_err(ubi, "bad compat %d", vidh->compat);
goto bad_vid_hdr;
}
if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
ubi_err(ubi, "bad lnum %d", aeb->lnum);
goto bad_vid_hdr;
}
if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
ubi_err(ubi, "bad used_ebs %d", av->used_ebs);
goto bad_vid_hdr;
}
if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
ubi_err(ubi, "bad data_pad %d", av->data_pad);
goto bad_vid_hdr;
}
}
if (!last_aeb)
continue;
if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
ubi_err(ubi, "bad highest_lnum %d", av->highest_lnum);
goto bad_vid_hdr;
}
if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
ubi_err(ubi, "bad last_data_size %d",
av->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, av, &ai->volumes, rb)
ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
buf[aeb->pnum] = 1;
list_for_each_entry(aeb, &ai->free, u.list)
buf[aeb->pnum] = 1;
list_for_each_entry(aeb, &ai->corr, u.list)
buf[aeb->pnum] = 1;
list_for_each_entry(aeb, &ai->erase, u.list)
buf[aeb->pnum] = 1;
list_for_each_entry(aeb, &ai->alien, u.list)
buf[aeb->pnum] = 1;
err = 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++)
if (!buf[pnum]) {
ubi_err(ubi, "PEB %d is not referred", pnum);
err = 1;
}
kfree(buf);
if (err)
goto out;
return 0;
bad_aeb:
ubi_err(ubi, "bad attaching information about LEB %d", aeb->lnum);
ubi_dump_aeb(aeb, 0);
ubi_dump_av(av);
goto out;
bad_av:
ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
ubi_dump_av(av);
goto out;
bad_vid_hdr:
ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
ubi_dump_av(av);
ubi_dump_vid_hdr(vidh);
out:
dump_stack();
return -EINVAL;
}