|
@@ -49,6 +49,30 @@
|
|
|
/* 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
|
|
@@ -311,6 +439,18 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
|
|
|
spin_unlock(&ubi->ltree_lock);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ubi_eba_is_mapped - check if a LEB is mapped.
|
|
|
+ * @vol: volume description object
|
|
|
+ * @lnum: logical eraseblock number
|
|
|
+ *
|
|
|
+ * This function returns true if the LEB is mapped, false otherwise.
|
|
|
+ */
|
|
|
+bool ubi_eba_is_mapped(struct ubi_volume *vol, int lnum)
|
|
|
+{
|
|
|
+ return vol->eba_tbl->entries[lnum].pnum >= 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ubi_eba_unmap_leb - un-map logical eraseblock.
|
|
|
* @ubi: UBI device description object
|
|
@@ -333,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;
|
|
@@ -341,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);
|
|
|
|
|
@@ -373,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);
|
|
|
|
|
@@ -380,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
|
|
@@ -403,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) {
|
|
|
/*
|
|
@@ -455,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);
|
|
@@ -492,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;
|
|
@@ -554,49 +697,47 @@ int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * recover_peb - recover from write failure.
|
|
|
- * @ubi: UBI device description object
|
|
|
+ * try_recover_peb - try to recover from write failure.
|
|
|
+ * @vol: volume description object
|
|
|
* @pnum: the physical eraseblock to recover
|
|
|
- * @vol_id: volume ID
|
|
|
* @lnum: logical eraseblock number
|
|
|
* @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
|
|
|
+ * @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
|
|
|
* from the potentially bad physical eraseblock to a good physical eraseblock.
|
|
|
* This function also writes the data which was not written due to the failure.
|
|
|
- * Returns new physical eraseblock number in case of success, and a negative
|
|
|
- * error code in case of failure.
|
|
|
+ * Returns 0 in case of success, and a negative error code in case of failure.
|
|
|
+ * In case of failure, the %retry parameter is set to false if this is a fatal
|
|
|
+ * error (retrying won't help), and true otherwise.
|
|
|
*/
|
|
|
-static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
|
|
|
- const void *buf, int offset, int len)
|
|
|
+static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
|
|
|
+ const void *buf, int offset, int len,
|
|
|
+ struct ubi_vid_io_buf *vidb, bool *retry)
|
|
|
{
|
|
|
- int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
|
|
|
- struct ubi_volume *vol = ubi->volumes[idx];
|
|
|
+ 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;
|
|
|
|
|
|
- vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
|
|
- if (!vid_hdr)
|
|
|
- return -ENOMEM;
|
|
|
+ *retry = false;
|
|
|
|
|
|
-retry:
|
|
|
new_pnum = ubi_wl_get_peb(ubi);
|
|
|
if (new_pnum < 0) {
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- return new_pnum;
|
|
|
+ err = new_pnum;
|
|
|
+ goto out_put;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
goto out_put;
|
|
|
}
|
|
|
|
|
@@ -608,12 +749,12 @@ retry:
|
|
|
/* Read everything before the area where the write failure happened */
|
|
|
if (offset > 0) {
|
|
|
err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
|
|
|
- if (err && err != UBI_IO_BITFLIPS) {
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
+ if (err && err != UBI_IO_BITFLIPS)
|
|
|
goto out_unlock;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
+ *retry = true;
|
|
|
+
|
|
|
memcpy(ubi->peb_buf + offset, buf, len);
|
|
|
|
|
|
data_size = offset + len;
|
|
@@ -622,50 +763,140 @@ retry:
|
|
|
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);
|
|
|
- if (err) {
|
|
|
- mutex_unlock(&ubi->buf_mutex);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
+ err = ubi_io_write_vid_hdr(ubi, new_pnum, vidb);
|
|
|
+ if (err)
|
|
|
+ goto out_unlock;
|
|
|
|
|
|
err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
|
|
|
- if (err) {
|
|
|
- mutex_unlock(&ubi->buf_mutex);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
|
|
|
+out_unlock:
|
|
|
mutex_unlock(&ubi->buf_mutex);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
|
|
|
- vol->eba_tbl[lnum] = new_pnum;
|
|
|
+ if (!err)
|
|
|
+ vol->eba_tbl->entries[lnum].pnum = new_pnum;
|
|
|
+
|
|
|
+out_put:
|
|
|
up_read(&ubi->fm_eba_sem);
|
|
|
- ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
|
|
|
- ubi_msg(ubi, "data was successfully recovered");
|
|
|
- return 0;
|
|
|
+ if (!err) {
|
|
|
+ ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
+ ubi_msg(ubi, "data was successfully recovered");
|
|
|
+ } else if (new_pnum >= 0) {
|
|
|
+ /*
|
|
|
+ * Bad luck? This physical eraseblock is bad too? Crud. Let's
|
|
|
+ * try to get another one.
|
|
|
+ */
|
|
|
+ ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
|
|
|
+ ubi_warn(ubi, "failed to write to PEB %d", new_pnum);
|
|
|
+ }
|
|
|
|
|
|
-out_unlock:
|
|
|
- mutex_unlock(&ubi->buf_mutex);
|
|
|
-out_put:
|
|
|
- ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
return err;
|
|
|
+}
|
|
|
|
|
|
-write_error:
|
|
|
- /*
|
|
|
- * Bad luck? This physical eraseblock is bad too? Crud. Let's try to
|
|
|
- * get another one.
|
|
|
- */
|
|
|
- ubi_warn(ubi, "failed to write to PEB %d", new_pnum);
|
|
|
- ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
|
|
|
- if (++tries > UBI_IO_RETRIES) {
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
+/**
|
|
|
+ * recover_peb - recover from write failure.
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ * @pnum: the physical eraseblock to recover
|
|
|
+ * @vol_id: volume ID
|
|
|
+ * @lnum: logical eraseblock number
|
|
|
+ * @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
|
|
|
+ *
|
|
|
+ * This function is called in case of a write failure and moves all good data
|
|
|
+ * from the potentially bad physical eraseblock to a good physical eraseblock.
|
|
|
+ * This function also writes the data which was not written due to the failure.
|
|
|
+ * Returns 0 in case of success, and a negative error code in case of failure.
|
|
|
+ * This function tries %UBI_IO_RETRIES before giving up.
|
|
|
+ */
|
|
|
+static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
|
|
|
+ const void *buf, int offset, int len)
|
|
|
+{
|
|
|
+ int err, idx = vol_id2idx(ubi, vol_id), tries;
|
|
|
+ struct ubi_volume *vol = ubi->volumes[idx];
|
|
|
+ struct ubi_vid_io_buf *vidb;
|
|
|
+
|
|
|
+ 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, vidb,
|
|
|
+ &retry);
|
|
|
+ if (!err || !retry)
|
|
|
+ break;
|
|
|
+
|
|
|
+ ubi_msg(ubi, "try again");
|
|
|
}
|
|
|
- ubi_msg(ubi, "try again");
|
|
|
- goto retry;
|
|
|
+
|
|
|
+ ubi_free_vid_buf(vidb);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * try_write_vid_and_data - try to write VID header and data to a new PEB.
|
|
|
+ * @vol: volume description object
|
|
|
+ * @lnum: logical eraseblock number
|
|
|
+ * @vidb: the VID buffer to write
|
|
|
+ * @buf: buffer containing the data
|
|
|
+ * @offset: where to start writing data
|
|
|
+ * @len: how many bytes should be written
|
|
|
+ *
|
|
|
+ * This function tries to write VID header and data belonging to logical
|
|
|
+ * eraseblock @lnum of volume @vol to a new physical eraseblock. Returns zero
|
|
|
+ * in case of success and a negative error code in case of failure.
|
|
|
+ * In case of error, it is possible that something was still written to the
|
|
|
+ * flash media, but may be some garbage.
|
|
|
+ */
|
|
|
+static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
|
|
|
+ struct ubi_vid_io_buf *vidb, const void *buf,
|
|
|
+ int offset, int len)
|
|
|
+{
|
|
|
+ struct ubi_device *ubi = vol->ubi;
|
|
|
+ int pnum, opnum, err, vol_id = vol->vol_id;
|
|
|
+
|
|
|
+ pnum = ubi_wl_get_peb(ubi);
|
|
|
+ if (pnum < 0) {
|
|
|
+ err = pnum;
|
|
|
+ goto out_put;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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, vidb);
|
|
|
+ if (err) {
|
|
|
+ ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
|
|
|
+ vol_id, lnum, pnum);
|
|
|
+ goto out_put;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (len) {
|
|
|
+ err = ubi_io_write_data(ubi, buf, pnum, offset, len);
|
|
|
+ if (err) {
|
|
|
+ ubi_warn(ubi,
|
|
|
+ "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
|
|
|
+ len, offset, vol_id, lnum, pnum);
|
|
|
+ goto out_put;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ vol->eba_tbl->entries[lnum].pnum = pnum;
|
|
|
+
|
|
|
+out_put:
|
|
|
+ up_read(&ubi->fm_eba_sem);
|
|
|
+
|
|
|
+ if (err && pnum >= 0)
|
|
|
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
+ else if (!err && opnum >= 0)
|
|
|
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -681,11 +912,13 @@ write_error:
|
|
|
* @vol. Returns zero in case of success and a negative error code in case
|
|
|
* of failure. In case of error, it is possible that something was still
|
|
|
* written to the flash media, but may be some garbage.
|
|
|
+ * This function retries %UBI_IO_RETRIES times before giving up.
|
|
|
*/
|
|
|
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 = 0, vol_id = vol->vol_id;
|
|
|
+ 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)
|
|
@@ -695,7 +928,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);
|
|
@@ -706,23 +939,23 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
|
|
|
if (err == -EIO && ubi->bad_allowed)
|
|
|
err = recover_peb(ubi, pnum, vol_id, lnum, buf,
|
|
|
offset, len);
|
|
|
- if (err)
|
|
|
- ubi_ro_mode(ubi);
|
|
|
}
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- return err;
|
|
|
+
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* 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);
|
|
@@ -730,67 +963,30 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
|
|
|
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
|
|
|
vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
|
|
|
|
|
|
-retry:
|
|
|
- pnum = ubi_wl_get_peb(ubi);
|
|
|
- if (pnum < 0) {
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- return 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);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
|
|
|
- vol_id, lnum, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
+ for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
|
|
|
+ err = try_write_vid_and_data(vol, lnum, vidb, buf, offset, len);
|
|
|
+ if (err != -EIO || !ubi->bad_allowed)
|
|
|
+ break;
|
|
|
|
|
|
- if (len) {
|
|
|
- err = ubi_io_write_data(ubi, buf, pnum, offset, len);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
|
|
|
- len, offset, vol_id, lnum, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Fortunately, this is the first write operation to this
|
|
|
+ * physical eraseblock, so just put it and request a new one.
|
|
|
+ * We assume that if this physical eraseblock went bad, the
|
|
|
+ * erase code will handle that.
|
|
|
+ */
|
|
|
+ vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
+ ubi_msg(ubi, "try another PEB");
|
|
|
}
|
|
|
|
|
|
- vol->eba_tbl[lnum] = pnum;
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
-
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return 0;
|
|
|
+ ubi_free_vid_buf(vidb);
|
|
|
|
|
|
-write_error:
|
|
|
- if (err != -EIO || !ubi->bad_allowed) {
|
|
|
+out:
|
|
|
+ if (err)
|
|
|
ubi_ro_mode(ubi);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
- }
|
|
|
|
|
|
- /*
|
|
|
- * Fortunately, this is the first write operation to this physical
|
|
|
- * eraseblock, so just put it and request a new one. We assume that if
|
|
|
- * this physical eraseblock went bad, the erase code will handle that.
|
|
|
- */
|
|
|
- err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
- if (err || ++tries > UBI_IO_RETRIES) {
|
|
|
- ubi_ro_mode(ubi);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
- }
|
|
|
+ leb_write_unlock(ubi, vol_id, lnum);
|
|
|
|
|
|
- vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
- ubi_msg(ubi, "try another PEB");
|
|
|
- goto retry;
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -818,7 +1014,8 @@ write_error:
|
|
|
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, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
|
|
|
+ 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;
|
|
|
|
|
@@ -831,15 +1028,15 @@ 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) {
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
- }
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
|
|
|
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
vid_hdr->vol_id = cpu_to_be32(vol_id);
|
|
@@ -853,66 +1050,26 @@ 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);
|
|
|
|
|
|
-retry:
|
|
|
- pnum = ubi_wl_get_peb(ubi);
|
|
|
- if (pnum < 0) {
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- return pnum;
|
|
|
- }
|
|
|
+ ubi_assert(vol->eba_tbl->entries[lnum].pnum < 0);
|
|
|
|
|
|
- dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d",
|
|
|
- len, vol_id, lnum, pnum, used_ebs);
|
|
|
+ for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
|
|
|
+ err = try_write_vid_and_data(vol, lnum, vidb, buf, 0, len);
|
|
|
+ if (err != -EIO || !ubi->bad_allowed)
|
|
|
+ break;
|
|
|
|
|
|
- err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
|
|
|
- vol_id, lnum, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
+ vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
+ ubi_msg(ubi, "try another PEB");
|
|
|
}
|
|
|
|
|
|
- err = ubi_io_write_data(ubi, buf, pnum, 0, len);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
|
|
|
- len, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
-
|
|
|
- ubi_assert(vol->eba_tbl[lnum] < 0);
|
|
|
- vol->eba_tbl[lnum] = pnum;
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
+ if (err)
|
|
|
+ ubi_ro_mode(ubi);
|
|
|
|
|
|
leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return 0;
|
|
|
-
|
|
|
-write_error:
|
|
|
- if (err != -EIO || !ubi->bad_allowed) {
|
|
|
- /*
|
|
|
- * This flash device does not admit of bad eraseblocks or
|
|
|
- * something nasty and unexpected happened. Switch to read-only
|
|
|
- * mode just in case.
|
|
|
- */
|
|
|
- ubi_ro_mode(ubi);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
- }
|
|
|
|
|
|
- err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
- if (err || ++tries > UBI_IO_RETRIES) {
|
|
|
- ubi_ro_mode(ubi);
|
|
|
- leb_write_unlock(ubi, vol_id, lnum);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
- return err;
|
|
|
- }
|
|
|
+out:
|
|
|
+ ubi_free_vid_buf(vidb);
|
|
|
|
|
|
- vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
- ubi_msg(ubi, "try another PEB");
|
|
|
- goto retry;
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -935,7 +1092,8 @@ write_error:
|
|
|
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
|
|
int lnum, const void *buf, int len)
|
|
|
{
|
|
|
- int err, pnum, old_pnum, tries = 0, vol_id = vol->vol_id;
|
|
|
+ int err, tries, vol_id = vol->vol_id;
|
|
|
+ struct ubi_vid_io_buf *vidb;
|
|
|
struct ubi_vid_hdr *vid_hdr;
|
|
|
uint32_t crc;
|
|
|
|
|
@@ -953,10 +1111,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)
|
|
@@ -974,70 +1134,31 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
|
|
vid_hdr->copy_flag = 1;
|
|
|
vid_hdr->data_crc = cpu_to_be32(crc);
|
|
|
|
|
|
-retry:
|
|
|
- pnum = ubi_wl_get_peb(ubi);
|
|
|
- if (pnum < 0) {
|
|
|
- err = pnum;
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto out_leb_unlock;
|
|
|
- }
|
|
|
-
|
|
|
- dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
|
|
|
- vol_id, lnum, vol->eba_tbl[lnum], pnum);
|
|
|
+ dbg_eba("change LEB %d:%d", vol_id, lnum);
|
|
|
|
|
|
- err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
|
|
|
- vol_id, lnum, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
- }
|
|
|
+ for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
|
|
|
+ err = try_write_vid_and_data(vol, lnum, vidb, buf, 0, len);
|
|
|
+ if (err != -EIO || !ubi->bad_allowed)
|
|
|
+ break;
|
|
|
|
|
|
- err = ubi_io_write_data(ubi, buf, pnum, 0, len);
|
|
|
- if (err) {
|
|
|
- ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
|
|
|
- len, pnum);
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
- goto write_error;
|
|
|
+ vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
+ ubi_msg(ubi, "try another PEB");
|
|
|
}
|
|
|
|
|
|
- old_pnum = vol->eba_tbl[lnum];
|
|
|
- vol->eba_tbl[lnum] = pnum;
|
|
|
- up_read(&ubi->fm_eba_sem);
|
|
|
-
|
|
|
- if (old_pnum >= 0) {
|
|
|
- err = ubi_wl_put_peb(ubi, vol_id, lnum, old_pnum, 0);
|
|
|
- if (err)
|
|
|
- goto out_leb_unlock;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * This flash device does not admit of bad eraseblocks or
|
|
|
+ * something nasty and unexpected happened. Switch to read-only
|
|
|
+ * mode just in case.
|
|
|
+ */
|
|
|
+ if (err)
|
|
|
+ ubi_ro_mode(ubi);
|
|
|
|
|
|
-out_leb_unlock:
|
|
|
leb_write_unlock(ubi, vol_id, lnum);
|
|
|
+
|
|
|
out_mutex:
|
|
|
mutex_unlock(&ubi->alc_mutex);
|
|
|
- ubi_free_vid_hdr(ubi, vid_hdr);
|
|
|
+ ubi_free_vid_buf(vidb);
|
|
|
return err;
|
|
|
-
|
|
|
-write_error:
|
|
|
- if (err != -EIO || !ubi->bad_allowed) {
|
|
|
- /*
|
|
|
- * This flash device does not admit of bad eraseblocks or
|
|
|
- * something nasty and unexpected happened. Switch to read-only
|
|
|
- * mode just in case.
|
|
|
- */
|
|
|
- ubi_ro_mode(ubi);
|
|
|
- goto out_leb_unlock;
|
|
|
- }
|
|
|
-
|
|
|
- err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
|
|
|
- if (err || ++tries > UBI_IO_RETRIES) {
|
|
|
- ubi_ro_mode(ubi);
|
|
|
- goto out_leb_unlock;
|
|
|
- }
|
|
|
-
|
|
|
- vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
|
|
|
- ubi_msg(ubi, "try another PEB");
|
|
|
- goto retry;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1082,12 +1203,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);
|
|
|
|
|
@@ -1142,9 +1266,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;
|
|
|
}
|
|
@@ -1196,7 +1320,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;
|
|
@@ -1206,7 +1330,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",
|
|
@@ -1229,10 +1353,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);
|
|
@@ -1388,7 +1510,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;
|
|
@@ -1404,35 +1526,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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1469,8 +1595,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;
|
|
|
}
|