]> www.infradead.org Git - mtd-utils.git/commitdiff
ubiformat: torture eraseblocks on write errors
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sun, 26 Jul 2009 12:40:32 +0000 (15:40 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sun, 26 Jul 2009 12:40:32 +0000 (15:40 +0300)
When fail to write to PEBs, and the error is EIO, torture the
PEB before marking it as bad. Basically, the code is copied
from the kernel UBI.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/include/libmtd.h
ubi-utils/src/libmtd.c
ubi-utils/src/ubiformat.c

index 8d5bc4f074fa108986969f44357e3590d038258d..c8b44e848c64b40c75f42e461c3d44eb96cda016 100644 (file)
@@ -148,6 +148,17 @@ int mtd_get_dev_info1(libmtd_t desc, int dev_num, struct mtd_dev_info *mtd);
  */
 int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb);
 
+/**
+ * mtd_torture - torture an eraseblock.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to torture
+ *
+ * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb);
+
 /**
  * mtd_is_bad - check if eraseblock is bad.
  * @mtd: MTD device description object
@@ -160,13 +171,13 @@ int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb);
 int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
 
 /**
- * mtd_mark_bad - marks the block as bad.
+ * mtd_mark_bad - mark an eraseblock as bad.
  * @mtd: MTD device description object
  * @fd: MTD device node file descriptor
- * @eb: eraseblock to mark bad
+ * @eb: eraseblock to mark as bad
  *
- * This function marks the eraseblock @eb as bad. Returns %0 if success
- * %-1 if failure
+ * This function marks eraseblock @eb as bad. Returns %0 in case of success and
+ * %-1 in case of failure.
  */
 int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
 
index 4f1ef41cbc9d9c6974654b736912010148f8ef6c..249fa23b5ae95d68ca410528a4dc26f4764fd349 100644 (file)
@@ -798,6 +798,87 @@ int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb)
        return ioctl(fd, MEMERASE, &ei);
 }
 
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (((const uint8_t *)buf)[i] != patt)
+                       return 0;
+       return 1;
+}
+
+int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int err, i, patt_count;
+       void *buf;
+
+       normsg("run torture test for PEB %d", eb);
+       patt_count = ARRAY_SIZE(patterns);
+
+       buf = malloc(mtd->eb_size);
+       if (!buf) {
+               errmsg("cannot allocate %d bytes of memory", mtd->eb_size);
+               return -1;
+       }
+
+       for (i = 0; i < patt_count; i++) {
+               err = mtd_erase(mtd, fd, eb);
+               if (err)
+                       goto out;
+
+               /* Make sure the PEB contains only 0xFF bytes */
+               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+               if (err)
+                       goto out;
+
+               err = check_pattern(buf, 0xFF, mtd->eb_size);
+               if (err == 0) {
+                       errmsg("erased PEB %d, but a non-0xFF byte found", eb);
+                       errno = EIO;
+                       goto out;
+               }
+
+               /* Write a pattern and check it */
+               memset(buf, patterns[i], mtd->eb_size);
+               err = mtd_write(mtd, fd, eb, 0, buf, mtd->eb_size);
+               if (err)
+                       goto out;
+
+               memset(buf, ~patterns[i], mtd->eb_size);
+               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+               if (err)
+                       goto out;
+
+               err = check_pattern(buf, patterns[i], mtd->eb_size);
+               if (err == 0) {
+                       errmsg("pattern %x checking failed for PEB %d",
+                               patterns[i], eb);
+                       errno = EIO;
+                       goto out;
+               }
+       }
+
+       err = 0;
+       normsg("PEB %d passed torture test, do not mark it a bad", eb);
+
+out:
+       free(buf);
+       return -1;
+}
+
 int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
 {
        int ret;
index 2a62f3b91dbac5ecde5f3550fed9b2399c0f32dc..c15500ba688a234df42e3d6b55c0621e7f008c0c 100644 (file)
@@ -530,12 +530,14 @@ static int flash_image(const struct mtd_dev_info *mtd, struct ubi_scan_info *si)
                        if (errno != EIO)
                                goto out_close;
 
-                       if (mark_bad(mtd, si, eb)) {
-                               normsg("operation incomplete");
-                               goto out_close;
+                       err = mtd_torture(mtd, args.node_fd, eb);
+                       if (err) {
+                               if (mark_bad(mtd, si, eb)) {
+                                       normsg("operation incomplete");
+                                       goto out_close;
+                               }
+                               divisor += 1;
                        }
-
-                       divisor += 1;
                        continue;
                }
                if (++written_ebs >= img_ebs)