diff options
Diffstat (limited to 'drivers/mtd/ubi/fastmap.c')
-rw-r--r-- | drivers/mtd/ubi/fastmap.c | 203 |
1 files changed, 90 insertions, 113 deletions
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 48eb55f344eb..2ff62157d3bb 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -110,21 +110,23 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi) * Returns a new struct ubi_vid_hdr on success. * NULL indicates out of memory. */ -static struct ubi_vid_hdr *new_fm_vhdr(struct ubi_device *ubi, int vol_id) +static struct ubi_vid_io_buf *new_fm_vbuf(struct ubi_device *ubi, int vol_id) { - struct ubi_vid_hdr *new; + struct ubi_vid_io_buf *new; + struct ubi_vid_hdr *vh; - new = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + new = ubi_alloc_vid_buf(ubi, GFP_KERNEL); if (!new) goto out; - new->vol_type = UBI_VID_DYNAMIC; - new->vol_id = cpu_to_be32(vol_id); + vh = ubi_get_vid_hdr(new); + vh->vol_type = UBI_VID_DYNAMIC; + vh->vol_id = cpu_to_be32(vol_id); /* UBI implementations without fastmap support have to delete the * fastmap. */ - new->compat = UBI_COMPAT_DELETE; + vh->compat = UBI_COMPAT_DELETE; out: return new; @@ -145,12 +147,10 @@ static int add_aeb(struct ubi_attach_info *ai, struct list_head *list, { struct ubi_ainf_peb *aeb; - aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL); + aeb = ubi_alloc_aeb(ai, pnum, ec); if (!aeb) return -ENOMEM; - aeb->pnum = pnum; - aeb->ec = ec; aeb->lnum = -1; aeb->scrub = scrub; aeb->copy_flag = aeb->sqnum = 0; @@ -186,40 +186,19 @@ static struct ubi_ainf_volume *add_vol(struct ubi_attach_info *ai, int vol_id, int last_eb_bytes) { struct ubi_ainf_volume *av; - struct rb_node **p = &ai->volumes.rb_node, *parent = NULL; - - while (*p) { - parent = *p; - av = rb_entry(parent, struct ubi_ainf_volume, rb); - - if (vol_id > av->vol_id) - p = &(*p)->rb_left; - else if (vol_id < av->vol_id) - p = &(*p)->rb_right; - else - return ERR_PTR(-EINVAL); - } - av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL); - if (!av) - goto out; + av = ubi_add_av(ai, vol_id); + if (IS_ERR(av)) + return av; - av->highest_lnum = av->leb_count = av->used_ebs = 0; - av->vol_id = vol_id; av->data_pad = data_pad; av->last_data_size = last_eb_bytes; av->compat = 0; av->vol_type = vol_type; - av->root = RB_ROOT; if (av->vol_type == UBI_STATIC_VOLUME) av->used_ebs = used_ebs; dbg_bld("found volume (ID %i)", vol_id); - - rb_link_node(&av->rb, parent, p); - rb_insert_color(&av->rb, &ai->volumes); - -out: return av; } @@ -297,7 +276,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, */ if (aeb->pnum == new_aeb->pnum) { ubi_assert(aeb->lnum == new_aeb->lnum); - kmem_cache_free(ai->aeb_slab_cache, new_aeb); + ubi_free_aeb(ai, new_aeb); return 0; } @@ -308,13 +287,10 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, /* new_aeb is newer */ if (cmp_res & 1) { - victim = kmem_cache_alloc(ai->aeb_slab_cache, - GFP_KERNEL); + victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec); if (!victim) return -ENOMEM; - victim->ec = aeb->ec; - victim->pnum = aeb->pnum; list_add_tail(&victim->u.list, &ai->erase); if (av->highest_lnum == be32_to_cpu(new_vh->lnum)) @@ -328,7 +304,8 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, aeb->pnum = new_aeb->pnum; aeb->copy_flag = new_vh->copy_flag; aeb->scrub = new_aeb->scrub; - kmem_cache_free(ai->aeb_slab_cache, new_aeb); + aeb->sqnum = new_aeb->sqnum; + ubi_free_aeb(ai, new_aeb); /* new_aeb is older */ } else { @@ -370,41 +347,24 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_vid_hdr *new_vh, struct ubi_ainf_peb *new_aeb) { - struct ubi_ainf_volume *av, *tmp_av = NULL; - struct rb_node **p = &ai->volumes.rb_node, *parent = NULL; - int found = 0; + int vol_id = be32_to_cpu(new_vh->vol_id); + struct ubi_ainf_volume *av; - if (be32_to_cpu(new_vh->vol_id) == UBI_FM_SB_VOLUME_ID || - be32_to_cpu(new_vh->vol_id) == UBI_FM_DATA_VOLUME_ID) { - kmem_cache_free(ai->aeb_slab_cache, new_aeb); + if (vol_id == UBI_FM_SB_VOLUME_ID || vol_id == UBI_FM_DATA_VOLUME_ID) { + ubi_free_aeb(ai, new_aeb); return 0; } /* Find the volume this SEB belongs to */ - while (*p) { - parent = *p; - tmp_av = rb_entry(parent, struct ubi_ainf_volume, rb); - - if (be32_to_cpu(new_vh->vol_id) > tmp_av->vol_id) - p = &(*p)->rb_left; - else if (be32_to_cpu(new_vh->vol_id) < tmp_av->vol_id) - p = &(*p)->rb_right; - else { - found = 1; - break; - } - } - - if (found) - av = tmp_av; - else { + av = ubi_find_av(ai, vol_id); + if (!av) { ubi_err(ubi, "orphaned volume in fastmap pool!"); - kmem_cache_free(ai->aeb_slab_cache, new_aeb); + ubi_free_aeb(ai, new_aeb); return UBI_BAD_FASTMAP; } - ubi_assert(be32_to_cpu(new_vh->vol_id) == av->vol_id); + ubi_assert(vol_id == av->vol_id); return update_vol(ubi, ai, av, new_vh, new_aeb); } @@ -423,16 +383,12 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum) struct rb_node *node, *node2; struct ubi_ainf_peb *aeb; - for (node = rb_first(&ai->volumes); node; node = rb_next(node)) { - av = rb_entry(node, struct ubi_ainf_volume, rb); - - for (node2 = rb_first(&av->root); node2; - node2 = rb_next(node2)) { - aeb = rb_entry(node2, struct ubi_ainf_peb, u.rb); + ubi_rb_for_each_entry(node, av, &ai->volumes, rb) { + ubi_rb_for_each_entry(node2, aeb, &av->root, u.rb) { if (aeb->pnum == pnum) { rb_erase(&aeb->u.rb, &av->root); av->leb_count--; - kmem_cache_free(ai->aeb_slab_cache, aeb); + ubi_free_aeb(ai, aeb); return; } } @@ -455,6 +411,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, __be32 *pebs, int pool_size, unsigned long long *max_sqnum, struct list_head *free) { + struct ubi_vid_io_buf *vb; struct ubi_vid_hdr *vh; struct ubi_ec_hdr *ech; struct ubi_ainf_peb *new_aeb; @@ -464,12 +421,14 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, if (!ech) return -ENOMEM; - vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); - if (!vh) { + vb = ubi_alloc_vid_buf(ubi, GFP_KERNEL); + if (!vb) { kfree(ech); return -ENOMEM; } + vh = ubi_get_vid_hdr(vb); + dbg_bld("scanning fastmap pool: size = %i", pool_size); /* @@ -510,15 +469,16 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, goto out; } - err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); + err = ubi_io_read_vid_hdr(ubi, pnum, vb, 0); if (err == UBI_IO_FF || err == UBI_IO_FF_BITFLIPS) { unsigned long long ec = be64_to_cpu(ech->ec); unmap_peb(ai, pnum); dbg_bld("Adding PEB to free: %i", pnum); + if (err == UBI_IO_FF_BITFLIPS) - add_aeb(ai, free, pnum, ec, 1); - else - add_aeb(ai, free, pnum, ec, 0); + scrub = 1; + + add_aeb(ai, free, pnum, ec, scrub); continue; } else if (err == 0 || err == UBI_IO_BITFLIPS) { dbg_bld("Found non empty PEB:%i in pool", pnum); @@ -526,15 +486,12 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, if (err == UBI_IO_BITFLIPS) scrub = 1; - new_aeb = kmem_cache_alloc(ai->aeb_slab_cache, - GFP_KERNEL); + new_aeb = ubi_alloc_aeb(ai, pnum, be64_to_cpu(ech->ec)); if (!new_aeb) { ret = -ENOMEM; goto out; } - new_aeb->ec = be64_to_cpu(ech->ec); - new_aeb->pnum = pnum; new_aeb->lnum = be32_to_cpu(vh->lnum); new_aeb->sqnum = be64_to_cpu(vh->sqnum); new_aeb->copy_flag = vh->copy_flag; @@ -558,7 +515,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } out: - ubi_free_vid_hdr(ubi, vh); + ubi_free_vid_buf(vb); kfree(ech); return ret; } @@ -841,11 +798,11 @@ fail_bad: fail: list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) { list_del(&tmp_aeb->u.list); - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); + ubi_free_aeb(ai, tmp_aeb); } list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) { list_del(&tmp_aeb->u.list); - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); + ubi_free_aeb(ai, tmp_aeb); } return ret; @@ -886,6 +843,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_attach_info *scan_ai) { struct ubi_fm_sb *fmsb, *fmsb2; + struct ubi_vid_io_buf *vb; struct ubi_vid_hdr *vh; struct ubi_ec_hdr *ech; struct ubi_fastmap_layout *fm; @@ -919,7 +877,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, goto out; } - ret = ubi_io_read(ubi, fmsb, fm_anchor, ubi->leb_start, sizeof(*fmsb)); + ret = ubi_io_read_data(ubi, fmsb, fm_anchor, 0, sizeof(*fmsb)); if (ret && ret != UBI_IO_BITFLIPS) goto free_fm_sb; else if (ret == UBI_IO_BITFLIPS) @@ -961,12 +919,14 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, goto free_fm_sb; } - vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); - if (!vh) { + vb = ubi_alloc_vid_buf(ubi, GFP_KERNEL); + if (!vb) { ret = -ENOMEM; goto free_hdr; } + vh = ubi_get_vid_hdr(vb); + for (i = 0; i < used_blocks; i++) { int image_seq; @@ -1009,7 +969,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, goto free_hdr; } - ret = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); + ret = ubi_io_read_vid_hdr(ubi, pnum, vb, 0); if (ret && ret != UBI_IO_BITFLIPS) { ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i)", i, pnum); @@ -1037,8 +997,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, if (sqnum < be64_to_cpu(vh->sqnum)) sqnum = be64_to_cpu(vh->sqnum); - ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum, - ubi->leb_start, ubi->leb_size); + ret = ubi_io_read_data(ubi, ubi->fm_buf + (ubi->leb_size * i), + pnum, 0, ubi->leb_size); if (ret && ret != UBI_IO_BITFLIPS) { ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i, " "err: %i)", i, pnum, ret); @@ -1099,7 +1059,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ubi->fm_disabled = 0; ubi->fast_attach = 1; - ubi_free_vid_hdr(ubi, vh); + ubi_free_vid_buf(vb); kfree(ech); out: up_write(&ubi->fm_protect); @@ -1108,7 +1068,7 @@ out: return ret; free_hdr: - ubi_free_vid_hdr(ubi, vh); + ubi_free_vid_buf(vb); kfree(ech); free_fm_sb: kfree(fmsb); @@ -1136,6 +1096,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, struct ubi_fm_eba *feba; struct ubi_wl_entry *wl_e; struct ubi_volume *vol; + struct ubi_vid_io_buf *avbuf, *dvbuf; struct ubi_vid_hdr *avhdr, *dvhdr; struct ubi_work *ubi_wrk; struct rb_node *tmp_rb; @@ -1146,18 +1107,21 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fm_raw = ubi->fm_buf; memset(ubi->fm_buf, 0, ubi->fm_size); - avhdr = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID); - if (!avhdr) { + avbuf = new_fm_vbuf(ubi, UBI_FM_SB_VOLUME_ID); + if (!avbuf) { ret = -ENOMEM; goto out; } - dvhdr = new_fm_vhdr(ubi, UBI_FM_DATA_VOLUME_ID); - if (!dvhdr) { + dvbuf = new_fm_vbuf(ubi, UBI_FM_DATA_VOLUME_ID); + if (!dvbuf) { ret = -ENOMEM; goto out_kfree; } + avhdr = ubi_get_vid_hdr(avbuf); + dvhdr = ubi_get_vid_hdr(dvbuf); + seen_pebs = init_seen(ubi); if (IS_ERR(seen_pebs)) { ret = PTR_ERR(seen_pebs); @@ -1306,8 +1270,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs); ubi_assert(fm_pos <= ubi->fm_size); - for (j = 0; j < vol->reserved_pebs; j++) - feba->pnum[j] = cpu_to_be32(vol->eba_tbl[j]); + for (j = 0; j < vol->reserved_pebs; j++) { + struct ubi_eba_leb_desc ldesc; + + ubi_eba_get_ldesc(vol, j, &ldesc); + feba->pnum[j] = cpu_to_be32(ldesc.pnum); + } feba->reserved_pebs = cpu_to_be32(j); feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); @@ -1322,7 +1290,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, spin_unlock(&ubi->volumes_lock); dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum); - ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avhdr); + ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avbuf); if (ret) { ubi_err(ubi, "unable to write vid_hdr to fastmap SB!"); goto out_kfree; @@ -1343,7 +1311,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, dvhdr->lnum = cpu_to_be32(i); dbg_bld("writing fastmap data to PEB %i sqnum %llu", new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum)); - ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvhdr); + ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvbuf); if (ret) { ubi_err(ubi, "unable to write vid_hdr to PEB %i!", new_fm->e[i]->pnum); @@ -1352,8 +1320,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, } for (i = 0; i < new_fm->used_blocks; i++) { - ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size), - new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size); + ret = ubi_io_write_data(ubi, fm_raw + (i * ubi->leb_size), + new_fm->e[i]->pnum, 0, ubi->leb_size); if (ret) { ubi_err(ubi, "unable to write fastmap to PEB %i!", new_fm->e[i]->pnum); @@ -1368,8 +1336,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, dbg_bld("fastmap written!"); out_kfree: - ubi_free_vid_hdr(ubi, avhdr); - ubi_free_vid_hdr(ubi, dvhdr); + ubi_free_vid_buf(avbuf); + ubi_free_vid_buf(dvbuf); free_seen(seen_pebs); out: return ret; @@ -1439,7 +1407,8 @@ static int invalidate_fastmap(struct ubi_device *ubi) int ret; struct ubi_fastmap_layout *fm; struct ubi_wl_entry *e; - struct ubi_vid_hdr *vh = NULL; + struct ubi_vid_io_buf *vb = NULL; + struct ubi_vid_hdr *vh; if (!ubi->fm) return 0; @@ -1451,10 +1420,12 @@ static int invalidate_fastmap(struct ubi_device *ubi) if (!fm) goto out; - vh = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID); - if (!vh) + vb = new_fm_vbuf(ubi, UBI_FM_SB_VOLUME_ID); + if (!vb) goto out_free_fm; + vh = ubi_get_vid_hdr(vb); + ret = -ENOSPC; e = ubi_wl_get_fm_peb(ubi, 1); if (!e) @@ -1465,7 +1436,7 @@ static int invalidate_fastmap(struct ubi_device *ubi) * to scanning mode. */ vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ret = ubi_io_write_vid_hdr(ubi, e->pnum, vh); + ret = ubi_io_write_vid_hdr(ubi, e->pnum, vb); if (ret < 0) { ubi_wl_put_fm_peb(ubi, e, 0, 0); goto out_free_fm; @@ -1477,7 +1448,7 @@ static int invalidate_fastmap(struct ubi_device *ubi) ubi->fm = fm; out: - ubi_free_vid_hdr(ubi, vh); + ubi_free_vid_buf(vb); return ret; out_free_fm: @@ -1522,22 +1493,30 @@ int ubi_update_fastmap(struct ubi_device *ubi) struct ubi_wl_entry *tmp_e; down_write(&ubi->fm_protect); + down_write(&ubi->work_sem); + down_write(&ubi->fm_eba_sem); ubi_refill_pools(ubi); if (ubi->ro_mode || ubi->fm_disabled) { + up_write(&ubi->fm_eba_sem); + up_write(&ubi->work_sem); up_write(&ubi->fm_protect); return 0; } ret = ubi_ensure_anchor_pebs(ubi); if (ret) { + up_write(&ubi->fm_eba_sem); + up_write(&ubi->work_sem); up_write(&ubi->fm_protect); return ret; } new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL); if (!new_fm) { + up_write(&ubi->fm_eba_sem); + up_write(&ubi->work_sem); up_write(&ubi->fm_protect); return -ENOMEM; } @@ -1646,16 +1625,14 @@ int ubi_update_fastmap(struct ubi_device *ubi) new_fm->e[0] = tmp_e; } - down_write(&ubi->work_sem); - down_write(&ubi->fm_eba_sem); ret = ubi_write_fastmap(ubi, new_fm); - up_write(&ubi->fm_eba_sem); - up_write(&ubi->work_sem); if (ret) goto err; out_unlock: + up_write(&ubi->fm_eba_sem); + up_write(&ubi->work_sem); up_write(&ubi->fm_protect); kfree(old_fm); return ret; |