summaryrefslogtreecommitdiff
path: root/drivers/mtd/ubi/eba.c
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2016-09-16 16:59:26 +0200
committerRichard Weinberger <richard@nod.at>2016-10-02 22:48:14 +0200
commit3291b52f9ff0acc80a8ee3f92a960db937dccecb (patch)
treed781fc235723086fe4e07a3f30d2147d56a4aa0b /drivers/mtd/ubi/eba.c
parent799dca34ac543485f581bd8464ec9b1c4f0f852a (diff)
UBI: introduce the VID buffer concept
Currently, all VID headers are allocated and freed using the ubi_zalloc_vid_hdr() and ubi_free_vid_hdr() function. These functions make sure to align allocation on ubi->vid_hdr_alsize and adjust the vid_hdr pointer to match the ubi->vid_hdr_shift requirements. This works fine, but is a bit convoluted. Moreover, the future introduction of LEB consolidation (needed to support MLC/TLC NANDs) will allows a VID buffer to contain more than one VID header. Hence the creation of a ubi_vid_io_buf struct to attach extra information to the VID header. We currently only store the actual pointer of the underlying buffer, but will soon add the number of VID headers contained in the buffer. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/ubi/eba.c')
-rw-r--r--drivers/mtd/ubi/eba.c81
1 files changed, 47 insertions, 34 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 884c91ffe7ba..ddf4e63eed76 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -513,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);
@@ -543,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) {
/*
@@ -595,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);
@@ -632,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;
@@ -701,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
@@ -713,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;
@@ -730,7 +734,7 @@ 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;
@@ -759,7 +763,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;
@@ -810,24 +814,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;
}
@@ -836,7 +840,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
@@ -848,7 +852,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;
@@ -865,7 +869,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
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);
@@ -914,6 +918,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)
@@ -943,12 +948,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);
@@ -957,8 +964,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;
@@ -972,7 +978,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)
@@ -1009,6 +1015,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;
@@ -1021,10 +1028,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;
@@ -1044,7 +1053,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
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;
@@ -1058,7 +1067,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;
}
@@ -1084,6 +1093,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;
@@ -1101,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)
@@ -1125,7 +1137,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;
@@ -1145,7 +1157,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;
}
@@ -1191,9 +1203,10 @@ 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;
@@ -1305,7 +1318,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;
@@ -1315,7 +1328,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",