UBI: provide an helper to query LEB information
[cascardo/linux.git] / drivers / mtd / ubi / fastmap.c
index 48eb55f..27a94f2 100644 (file)
@@ -145,12 +145,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 +184,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 +274,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 +285,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->ec, aeb->pnum);
                        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 +302,7 @@ 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);
+                       ubi_free_aeb(ai, new_aeb);
 
                /* new_aeb is older */
                } else {
@@ -370,41 +344,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 +380,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;
                        }
                }
@@ -515,10 +468,11 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
                        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 +480,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;
@@ -841,11 +792,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;
@@ -919,7 +870,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)
@@ -1037,8 +988,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);
@@ -1306,8 +1257,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);
@@ -1352,8 +1307,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);