diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-06-10 08:32:05 (GMT) |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-06-10 13:13:28 (GMT) |
commit | 6b5c94c6b4e1630a8e1ee7d30383d9396603749f (patch) | |
tree | 28e1ab5143f317d561197b3bebfe2994c12ddec8 /drivers/mtd | |
parent | 815bc5f8fe516f55291aef90f2142073821e7a9c (diff) | |
download | linux-6b5c94c6b4e1630a8e1ee7d30383d9396603749f.tar.xz |
UBI: handle more error codes
The UBIFS WL worker may encounter read errors and there is logic
which makes a decision whether we should do one of:
1. cancel the operation and move the PEB with the read errors to
the 'erroneous' list;
2. switch to R/O mode.
ATM, only -EIO errors trigger 1., other errors trigger 2. The idea
is that if we know we encountered an I/O error, do 1. Otherwise,
we do not know how to react, and do 2., just in case. E.g., if
the underlying driver became crazy because of a bug, we do not
want to harm any data, and switch to R/O mode.
This patch does 2 things:
1. Makes sure reads from the source PEB always cause 1. This is
more consistent with other reads which come from the upper
layers and never cause R/O.
2. Teaches UBI to do 1. also on -EBADMSG, UBI_IO_BAD_VID_HDR,
-ENOMEM, and -ETIMEOUT. But this is only when reading the
target PEB.
This preblems were hunted by Adrian Hunter.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index b656556..0f2034c 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -941,6 +941,33 @@ write_error: } /** + * is_error_sane - check whether a read error is sane. + * @err: code of the error happened during reading + * + * This is a helper function for 'ubi_eba_copy_leb()' which is called when we + * cannot read data from the target PEB (an error @err happened). If the error + * code is sane, then we treat this error as non-fatal. Otherwise the error is + * fatal and UBI will be switched to R/O mode later. + * + * The idea is that we try not to switch to R/O mode if the read error is + * something which suggests there was a real read problem. E.g., %-EIO. Or a + * memory allocation failed (-%ENOMEM). Otherwise, it is safer to switch to R/O + * mode, simply because we do not know what happened at the MTD level, and we + * cannot handle this. E.g., the underlying driver may have become crazy, and + * it is safer to switch to R/O mode to preserve the data. + * + * And bear in mind, this is about reading from the target PEB, i.e. the PEB + * which we have just written. + */ +static int is_error_sane(int err) +{ + if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR || + err == -ETIMEDOUT) + return 0; + return 1; +} + +/** * ubi_eba_copy_leb - copy logical eraseblock. * @ubi: UBI device description object * @from: physical eraseblock number from where to copy @@ -1033,8 +1060,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, if (err && err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data from PEB %d", err, from); - if (err == -EIO) - err = MOVE_SOURCE_RD_ERR; + err = MOVE_SOURCE_RD_ERR; goto out_unlock_buf; } @@ -1082,8 +1108,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("cannot read VID header back from PEB %d", to); - if (err == -EIO) + ubi_warn("error %d while reading VID header back from " + "PEB %d", err, to); + if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; } else err = MOVE_CANCEL_BITFLIPS; @@ -1108,9 +1135,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("cannot read data back from PEB %d", - to); - if (err == -EIO) + ubi_warn("error %d while reading data back " + "from PEB %d", err, to); + if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; } else err = MOVE_CANCEL_BITFLIPS; |