x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / drivers / mtd / ubi / eba.c
index 32045dd..388e46b 100644 (file)
 /* Number of physical eraseblocks reserved for atomic LEB change operation */
 #define EBA_RESERVED_PEBS 1
 
+/**
+ * struct ubi_eba_entry - structure encoding a single LEB -> PEB association
+ * @pnum: the physical eraseblock number attached to the LEB
+ *
+ * This structure is encoding a LEB -> PEB association. Note that the LEB
+ * number is not stored here, because it is the index used to access the
+ * entries table.
+ */
+struct ubi_eba_entry {
+       int pnum;
+};
+
+/**
+ * struct ubi_eba_table - LEB -> PEB association information
+ * @entries: the LEB to PEB mapping (one entry per LEB).
+ *
+ * This structure is private to the EBA logic and should be kept here.
+ * It is encoding the LEB to PEB association table, and is subject to
+ * changes.
+ */
+struct ubi_eba_table {
+       struct ubi_eba_entry *entries;
+};
+
 /**
  * next_sqnum - get next sequence number.
  * @ubi: UBI device description object
@@ -83,6 +107,110 @@ static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
        return 0;
 }
 
+/**
+ * ubi_eba_get_ldesc - get information about a LEB
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @ldesc: the LEB descriptor to fill
+ *
+ * Used to query information about a specific LEB.
+ * It is currently only returning the physical position of the LEB, but will be
+ * extended to provide more information.
+ */
+void ubi_eba_get_ldesc(struct ubi_volume *vol, int lnum,
+                      struct ubi_eba_leb_desc *ldesc)
+{
+       ldesc->lnum = lnum;
+       ldesc->pnum = vol->eba_tbl->entries[lnum].pnum;
+}
+
+/**
+ * ubi_eba_create_table - allocate a new EBA table and initialize it with all
+ *                       LEBs unmapped
+ * @vol: volume containing the EBA table to copy
+ * @nentries: number of entries in the table
+ *
+ * Allocate a new EBA table and initialize it with all LEBs unmapped.
+ * Returns a valid pointer if it succeed, an ERR_PTR() otherwise.
+ */
+struct ubi_eba_table *ubi_eba_create_table(struct ubi_volume *vol,
+                                          int nentries)
+{
+       struct ubi_eba_table *tbl;
+       int err = -ENOMEM;
+       int i;
+
+       tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
+       if (!tbl)
+               return ERR_PTR(-ENOMEM);
+
+       tbl->entries = kmalloc_array(nentries, sizeof(*tbl->entries),
+                                    GFP_KERNEL);
+       if (!tbl->entries)
+               goto err;
+
+       for (i = 0; i < nentries; i++)
+               tbl->entries[i].pnum = UBI_LEB_UNMAPPED;
+
+       return tbl;
+
+err:
+       kfree(tbl->entries);
+       kfree(tbl);
+
+       return ERR_PTR(err);
+}
+
+/**
+ * ubi_eba_destroy_table - destroy an EBA table
+ * @tbl: the table to destroy
+ *
+ * Destroy an EBA table.
+ */
+void ubi_eba_destroy_table(struct ubi_eba_table *tbl)
+{
+       if (!tbl)
+               return;
+
+       kfree(tbl->entries);
+       kfree(tbl);
+}
+
+/**
+ * ubi_eba_copy_table - copy the EBA table attached to vol into another table
+ * @vol: volume containing the EBA table to copy
+ * @dst: destination
+ * @nentries: number of entries to copy
+ *
+ * Copy the EBA table stored in vol into the one pointed by dst.
+ */
+void ubi_eba_copy_table(struct ubi_volume *vol, struct ubi_eba_table *dst,
+                       int nentries)
+{
+       struct ubi_eba_table *src;
+       int i;
+
+       ubi_assert(dst && vol && vol->eba_tbl);
+
+       src = vol->eba_tbl;
+
+       for (i = 0; i < nentries; i++)
+               dst->entries[i].pnum = src->entries[i].pnum;
+}
+
+/**
+ * ubi_eba_replace_table - assign a new EBA table to a volume
+ * @vol: volume containing the EBA table to copy
+ * @tbl: new EBA table
+ *
+ * Assign a new EBA table to the volume and release the old one.
+ */
+void ubi_eba_replace_table(struct ubi_volume *vol, struct ubi_eba_table *tbl)
+{
+       ubi_eba_destroy_table(vol->eba_tbl);
+       vol->eba_tbl = tbl;
+}
+
 /**
  * ltree_lookup - look up the lock tree.
  * @ubi: UBI device description object
@@ -320,7 +448,7 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
  */
 bool ubi_eba_is_mapped(struct ubi_volume *vol, int lnum)
 {
-       return vol->eba_tbl[lnum] >= 0;
+       return vol->eba_tbl->entries[lnum].pnum >= 0;
 }
 
 /**
@@ -345,7 +473,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
        if (err)
                return err;
 
-       pnum = vol->eba_tbl[lnum];
+       pnum = vol->eba_tbl->entries[lnum].pnum;
        if (pnum < 0)
                /* This logical eraseblock is already unmapped */
                goto out_unlock;
@@ -353,7 +481,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
        dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
 
        down_read(&ubi->fm_eba_sem);
-       vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
+       vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED;
        up_read(&ubi->fm_eba_sem);
        err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
 
@@ -385,6 +513,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                     void *buf, int offset, int len, int check)
 {
        int err, pnum, scrub = 0, vol_id = vol->vol_id;
+       struct ubi_vid_io_buf *vidb;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t uninitialized_var(crc);
 
@@ -392,7 +521,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
        if (err)
                return err;
 
-       pnum = vol->eba_tbl[lnum];
+       pnum = vol->eba_tbl->entries[lnum].pnum;
        if (pnum < 0) {
                /*
                 * The logical eraseblock is not mapped, fill the whole buffer
@@ -415,13 +544,15 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 
 retry:
        if (check) {
-               vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
-               if (!vid_hdr) {
+               vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
+               if (!vidb) {
                        err = -ENOMEM;
                        goto out_unlock;
                }
 
-               err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+               vid_hdr = ubi_get_vid_hdr(vidb);
+
+               err = ubi_io_read_vid_hdr(ubi, pnum, vidb, 1);
                if (err && err != UBI_IO_BITFLIPS) {
                        if (err > 0) {
                                /*
@@ -467,7 +598,7 @@ retry:
                ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
 
                crc = be32_to_cpu(vid_hdr->data_crc);
-               ubi_free_vid_hdr(ubi, vid_hdr);
+               ubi_free_vid_buf(vidb);
        }
 
        err = ubi_io_read_data(ubi, buf, pnum, offset, len);
@@ -504,7 +635,7 @@ retry:
        return err;
 
 out_free:
-       ubi_free_vid_hdr(ubi, vid_hdr);
+       ubi_free_vid_buf(vidb);
 out_unlock:
        leb_read_unlock(ubi, vol_id, lnum);
        return err;
@@ -573,7 +704,7 @@ int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
  * @buf: data which was not written because of the write failure
  * @offset: offset of the failed write
  * @len: how many bytes should have been written
- * @vid: VID header
+ * @vidb: VID buffer
  * @retry: whether the caller should retry in case of failure
  *
  * This function is called in case of a write failure and moves all good data
@@ -585,9 +716,10 @@ int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
  */
 static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
                           const void *buf, int offset, int len,
-                          struct ubi_vid_hdr *vid_hdr, bool *retry)
+                          struct ubi_vid_io_buf *vidb, bool *retry)
 {
        struct ubi_device *ubi = vol->ubi;
+       struct ubi_vid_hdr *vid_hdr;
        int new_pnum, err, vol_id = vol->vol_id, data_size;
        uint32_t crc;
 
@@ -602,13 +734,14 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
        ubi_msg(ubi, "recover PEB %d, move data to PEB %d",
                pnum, new_pnum);
 
-       err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+       err = ubi_io_read_vid_hdr(ubi, pnum, vidb, 1);
        if (err && err != UBI_IO_BITFLIPS) {
                if (err > 0)
                        err = -EIO;
                goto out_put;
        }
 
+       vid_hdr = ubi_get_vid_hdr(vidb);
        ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
 
        mutex_lock(&ubi->buf_mutex);
@@ -631,7 +764,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
        vid_hdr->copy_flag = 1;
        vid_hdr->data_size = cpu_to_be32(data_size);
        vid_hdr->data_crc = cpu_to_be32(crc);
-       err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+       err = ubi_io_write_vid_hdr(ubi, new_pnum, vidb);
        if (err)
                goto out_unlock;
 
@@ -641,7 +774,7 @@ out_unlock:
        mutex_unlock(&ubi->buf_mutex);
 
        if (!err)
-               vol->eba_tbl[lnum] = new_pnum;
+               vol->eba_tbl->entries[lnum].pnum = new_pnum;
 
 out_put:
        up_read(&ubi->fm_eba_sem);
@@ -682,24 +815,24 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
 {
        int err, idx = vol_id2idx(ubi, vol_id), tries;
        struct ubi_volume *vol = ubi->volumes[idx];
-       struct ubi_vid_hdr *vid_hdr;
+       struct ubi_vid_io_buf *vidb;
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
-       if (!vid_hdr)
+       vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
+       if (!vidb)
                return -ENOMEM;
 
        for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
                bool retry;
 
-               err = try_recover_peb(vol, pnum, lnum, buf, offset, len,
-                                     vid_hdr, &retry);
+               err = try_recover_peb(vol, pnum, lnum, buf, offset, len, vidb,
+                                     &retry);
                if (!err || !retry)
                        break;
 
                ubi_msg(ubi, "try again");
        }
 
-       ubi_free_vid_hdr(ubi, vid_hdr);
+       ubi_free_vid_buf(vidb);
 
        return err;
 }
@@ -708,7 +841,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
  * try_write_vid_and_data - try to write VID header and data to a new PEB.
  * @vol: volume description object
  * @lnum: logical eraseblock number
- * @vid_hdr: VID header to write
+ * @vidb: the VID buffer to write
  * @buf: buffer containing the data
  * @offset: where to start writing data
  * @len: how many bytes should be written
@@ -720,7 +853,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
  * flash media, but may be some garbage.
  */
 static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
-                                 struct ubi_vid_hdr *vid_hdr, const void *buf,
+                                 struct ubi_vid_io_buf *vidb, const void *buf,
                                  int offset, int len)
 {
        struct ubi_device *ubi = vol->ubi;
@@ -732,12 +865,12 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
                goto out_put;
        }
 
-       opnum = vol->eba_tbl[lnum];
+       opnum = vol->eba_tbl->entries[lnum].pnum;
 
        dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
                len, offset, vol_id, lnum, pnum);
 
-       err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+       err = ubi_io_write_vid_hdr(ubi, pnum, vidb);
        if (err) {
                ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
                         vol_id, lnum, pnum);
@@ -754,7 +887,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
                }
        }
 
-       vol->eba_tbl[lnum] = pnum;
+       vol->eba_tbl->entries[lnum].pnum = pnum;
 
 out_put:
        up_read(&ubi->fm_eba_sem);
@@ -786,6 +919,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                      const void *buf, int offset, int len)
 {
        int err, pnum, tries, vol_id = vol->vol_id;
+       struct ubi_vid_io_buf *vidb;
        struct ubi_vid_hdr *vid_hdr;
 
        if (ubi->ro_mode)
@@ -795,7 +929,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
        if (err)
                return err;
 
-       pnum = vol->eba_tbl[lnum];
+       pnum = vol->eba_tbl->entries[lnum].pnum;
        if (pnum >= 0) {
                dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
                        len, offset, vol_id, lnum, pnum);
@@ -815,12 +949,14 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
         * The logical eraseblock is not mapped. We have to get a free physical
         * eraseblock and write the volume identifier header there first.
         */
-       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
-       if (!vid_hdr) {
+       vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
+       if (!vidb) {
                leb_write_unlock(ubi, vol_id, lnum);
                return -ENOMEM;
        }
 
+       vid_hdr = ubi_get_vid_hdr(vidb);
+
        vid_hdr->vol_type = UBI_VID_DYNAMIC;
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
        vid_hdr->vol_id = cpu_to_be32(vol_id);
@@ -829,8 +965,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
        vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
        for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
-               err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, offset,
-                                            len);
+               err = try_write_vid_and_data(vol, lnum, vidb, buf, offset, len);
                if (err != -EIO || !ubi->bad_allowed)
                        break;
 
@@ -844,7 +979,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                ubi_msg(ubi, "try another PEB");
        }
 
-       ubi_free_vid_hdr(ubi, vid_hdr);
+       ubi_free_vid_buf(vidb);
 
 out:
        if (err)
@@ -881,6 +1016,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
                         int lnum, const void *buf, int len, int used_ebs)
 {
        int err, tries, data_size = len, vol_id = vol->vol_id;
+       struct ubi_vid_io_buf *vidb;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
@@ -893,10 +1029,12 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
        else
                ubi_assert(!(len & (ubi->min_io_size - 1)));
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
-       if (!vid_hdr)
+       vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
+       if (!vidb)
                return -ENOMEM;
 
+       vid_hdr = ubi_get_vid_hdr(vidb);
+
        err = leb_write_lock(ubi, vol_id, lnum);
        if (err)
                goto out;
@@ -913,10 +1051,10 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
        vid_hdr->used_ebs = cpu_to_be32(used_ebs);
        vid_hdr->data_crc = cpu_to_be32(crc);
 
-       ubi_assert(vol->eba_tbl[lnum] < 0);
+       ubi_assert(vol->eba_tbl->entries[lnum].pnum < 0);
 
        for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
-               err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, 0, len);
+               err = try_write_vid_and_data(vol, lnum, vidb, buf, 0, len);
                if (err != -EIO || !ubi->bad_allowed)
                        break;
 
@@ -930,7 +1068,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
        leb_write_unlock(ubi, vol_id, lnum);
 
 out:
-       ubi_free_vid_hdr(ubi, vid_hdr);
+       ubi_free_vid_buf(vidb);
 
        return err;
 }
@@ -956,6 +1094,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
                              int lnum, const void *buf, int len)
 {
        int err, tries, vol_id = vol->vol_id;
+       struct ubi_vid_io_buf *vidb;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
@@ -973,10 +1112,12 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
                return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
        }
 
-       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
-       if (!vid_hdr)
+       vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
+       if (!vidb)
                return -ENOMEM;
 
+       vid_hdr = ubi_get_vid_hdr(vidb);
+
        mutex_lock(&ubi->alc_mutex);
        err = leb_write_lock(ubi, vol_id, lnum);
        if (err)
@@ -997,7 +1138,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
        dbg_eba("change LEB %d:%d", vol_id, lnum);
 
        for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
-               err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, 0, len);
+               err = try_write_vid_and_data(vol, lnum, vidb, buf, 0, len);
                if (err != -EIO || !ubi->bad_allowed)
                        break;
 
@@ -1017,7 +1158,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
 
 out_mutex:
        mutex_unlock(&ubi->alc_mutex);
-       ubi_free_vid_hdr(ubi, vid_hdr);
+       ubi_free_vid_buf(vidb);
        return err;
 }
 
@@ -1063,12 +1204,15 @@ static int is_error_sane(int err)
  *   o a negative error code in case of failure.
  */
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
-                    struct ubi_vid_hdr *vid_hdr)
+                    struct ubi_vid_io_buf *vidb)
 {
        int err, vol_id, lnum, data_size, aldata_size, idx;
+       struct ubi_vid_hdr *vid_hdr = ubi_get_vid_hdr(vidb);
        struct ubi_volume *vol;
        uint32_t crc;
 
+       ubi_assert(rwsem_is_locked(&ubi->fm_eba_sem));
+
        vol_id = be32_to_cpu(vid_hdr->vol_id);
        lnum = be32_to_cpu(vid_hdr->lnum);
 
@@ -1123,9 +1267,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         * probably waiting on @ubi->move_mutex. No need to continue the work,
         * cancel it.
         */
-       if (vol->eba_tbl[lnum] != from) {
+       if (vol->eba_tbl->entries[lnum].pnum != from) {
                dbg_wl("LEB %d:%d is no longer mapped to PEB %d, mapped to PEB %d, cancel",
-                      vol_id, lnum, from, vol->eba_tbl[lnum]);
+                      vol_id, lnum, from, vol->eba_tbl->entries[lnum].pnum);
                err = MOVE_CANCEL_RACE;
                goto out_unlock_leb;
        }
@@ -1177,7 +1321,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        }
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
 
-       err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
+       err = ubi_io_write_vid_hdr(ubi, to, vidb);
        if (err) {
                if (err == -EIO)
                        err = MOVE_TARGET_WR_ERR;
@@ -1187,7 +1331,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        cond_resched();
 
        /* Read the VID header back and check if it was written correctly */
-       err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
+       err = ubi_io_read_vid_hdr(ubi, to, vidb, 1);
        if (err) {
                if (err != UBI_IO_BITFLIPS) {
                        ubi_warn(ubi, "error %d while reading VID header back from PEB %d",
@@ -1210,10 +1354,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                cond_resched();
        }
 
-       ubi_assert(vol->eba_tbl[lnum] == from);
-       down_read(&ubi->fm_eba_sem);
-       vol->eba_tbl[lnum] = to;
-       up_read(&ubi->fm_eba_sem);
+       ubi_assert(vol->eba_tbl->entries[lnum].pnum == from);
+       vol->eba_tbl->entries[lnum].pnum = to;
 
 out_unlock_buf:
        mutex_unlock(&ubi->buf_mutex);
@@ -1369,7 +1511,7 @@ out_free:
  */
 int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 {
-       int i, j, err, num_volumes;
+       int i, err, num_volumes;
        struct ubi_ainf_volume *av;
        struct ubi_volume *vol;
        struct ubi_ainf_peb *aeb;
@@ -1385,35 +1527,39 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
        num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
 
        for (i = 0; i < num_volumes; i++) {
+               struct ubi_eba_table *tbl;
+
                vol = ubi->volumes[i];
                if (!vol)
                        continue;
 
                cond_resched();
 
-               vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int),
-                                      GFP_KERNEL);
-               if (!vol->eba_tbl) {
-                       err = -ENOMEM;
+               tbl = ubi_eba_create_table(vol, vol->reserved_pebs);
+               if (IS_ERR(tbl)) {
+                       err = PTR_ERR(tbl);
                        goto out_free;
                }
 
-               for (j = 0; j < vol->reserved_pebs; j++)
-                       vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
+               ubi_eba_replace_table(vol, tbl);
 
                av = ubi_find_av(ai, idx2vol_id(ubi, i));
                if (!av)
                        continue;
 
                ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
-                       if (aeb->lnum >= vol->reserved_pebs)
+                       if (aeb->lnum >= vol->reserved_pebs) {
                                /*
                                 * This may happen in case of an unclean reboot
                                 * during re-size.
                                 */
                                ubi_move_aeb_to_list(av, aeb, &ai->erase);
-                       else
-                               vol->eba_tbl[aeb->lnum] = aeb->pnum;
+                       } else {
+                               struct ubi_eba_entry *entry;
+
+                               entry = &vol->eba_tbl->entries[aeb->lnum];
+                               entry->pnum = aeb->pnum;
+                       }
                }
        }
 
@@ -1450,8 +1596,7 @@ out_free:
        for (i = 0; i < num_volumes; i++) {
                if (!ubi->volumes[i])
                        continue;
-               kfree(ubi->volumes[i]->eba_tbl);
-               ubi->volumes[i]->eba_tbl = NULL;
+               ubi_eba_replace_table(ubi->volumes[i], NULL);
        }
        return err;
 }