Merge tag 'sound-4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[cascardo/linux.git] / drivers / mtd / ubi / fastmap.c
index 1bfb4ae..2ff6215 100644 (file)
@@ -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;
@@ -276,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;
                }
@@ -287,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))
@@ -307,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 {
@@ -353,7 +351,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai,
        struct ubi_ainf_volume *av;
 
        if (vol_id == UBI_FM_SB_VOLUME_ID || vol_id == UBI_FM_DATA_VOLUME_ID) {
-               kmem_cache_free(ai->aeb_slab_cache, new_aeb);
+               ubi_free_aeb(ai, new_aeb);
 
                return 0;
        }
@@ -362,7 +360,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai,
        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;
        }
 
@@ -390,7 +388,7 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum)
                        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;
                        }
                }
@@ -413,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;
@@ -422,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);
 
        /*
@@ -468,7 +469,7 @@ 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);
@@ -485,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;
@@ -517,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;
 }
@@ -800,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;
@@ -845,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;
@@ -878,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)
@@ -920,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;
 
@@ -968,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);
@@ -996,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);
@@ -1058,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);
@@ -1067,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);
@@ -1095,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;
@@ -1105,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);
@@ -1265,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);
@@ -1281,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;
@@ -1302,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);
@@ -1311,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);
@@ -1327,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;
@@ -1398,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;
@@ -1410,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)
@@ -1424,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;
@@ -1436,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:
@@ -1481,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;
        }
@@ -1605,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;