Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / mtd / ubi / io.c
index 811775a..eededf9 100644 (file)
@@ -91,7 +91,7 @@
 #include <linux/slab.h>
 #include "ubi.h"
 
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
 static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
 static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
 static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
@@ -146,6 +146,28 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
        if (err)
                return err;
 
+       /*
+        * Deliberately corrupt the buffer to improve robustness. Indeed, if we
+        * do not do this, the following may happen:
+        * 1. The buffer contains data from previous operation, e.g., read from
+        *    another PEB previously. The data looks like expected, e.g., if we
+        *    just do not read anything and return - the caller would not
+        *    notice this. E.g., if we are reading a VID header, the buffer may
+        *    contain a valid VID header from another PEB.
+        * 2. The driver is buggy and returns us success or -EBADMSG or
+        *    -EUCLEAN, but it does not actually put any data to the buffer.
+        *
+        * This may confuse UBI or upper layers - they may think the buffer
+        * contains valid data while in fact it is just old data. This is
+        * especially possible because UBI (and UBIFS) relies on CRC, and
+        * treats data as correct even in case of ECC errors if the CRC is
+        * correct.
+        *
+        * Try to prevent this situation by changing the first byte of the
+        * buffer.
+        */
+       *((uint8_t *)buf) ^= 0xFF;
+
        addr = (loff_t)pnum * ubi->peb_size + offset;
 retry:
        err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
@@ -166,7 +188,7 @@ retry:
                        return UBI_IO_BITFLIPS;
                }
 
-               if (read != len && retries++ < UBI_IO_RETRIES) {
+               if (retries++ < UBI_IO_RETRIES) {
                        dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
                               " read only %zd bytes, retry",
                               err, errstr, len, pnum, offset, read);
@@ -480,6 +502,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
        size_t written;
        loff_t addr;
        uint32_t data = 0;
+       /*
+        * Note, we cannot generally define VID header buffers on stack,
+        * because of the way we deal with these buffers (see the header
+        * comment in this file). But we know this is a NOR-specific piece of
+        * code, so we can do this. But yes, this is error-prone and we should
+        * (pre-)allocate VID header buffer instead.
+        */
        struct ubi_vid_hdr vid_hdr;
 
        /*
@@ -507,11 +536,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
         * PEB.
         */
        err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
-       if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
+       if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
+           err1 == UBI_IO_FF) {
                struct ubi_ec_hdr ec_hdr;
 
                err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
-               if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
+               if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
+                   err1 == UBI_IO_FF)
                        /*
                         * Both VID and EC headers are corrupted, so we can
                         * safely erase this PEB and not afraid that it will be
@@ -752,9 +783,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                        if (verbose)
                                ubi_warn("no EC header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
-                       else if (UBI_IO_DEBUG)
-                               dbg_msg("no EC header found at PEB %d, "
-                                       "only 0xFF bytes", pnum);
+                       dbg_bld("no EC header found at PEB %d, "
+                               "only 0xFF bytes", pnum);
                        if (!read_err)
                                return UBI_IO_FF;
                        else
@@ -769,9 +799,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                        ubi_warn("bad magic number at PEB %d: %08x instead of "
                                 "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
                        ubi_dbg_dump_ec_hdr(ec_hdr);
-               } else if (UBI_IO_DEBUG)
-                       dbg_msg("bad magic number at PEB %d: %08x instead of "
-                               "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+               }
+               dbg_bld("bad magic number at PEB %d: %08x instead of "
+                       "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
                return UBI_IO_BAD_HDR;
        }
 
@@ -783,9 +813,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
                        ubi_warn("bad EC header CRC at PEB %d, calculated "
                                 "%#08x, read %#08x", pnum, crc, hdr_crc);
                        ubi_dbg_dump_ec_hdr(ec_hdr);
-               } else if (UBI_IO_DEBUG)
-                       dbg_msg("bad EC header CRC at PEB %d, calculated "
-                               "%#08x, read %#08x", pnum, crc, hdr_crc);
+               }
+               dbg_bld("bad EC header CRC at PEB %d, calculated "
+                       "%#08x, read %#08x", pnum, crc, hdr_crc);
 
                if (!read_err)
                        return UBI_IO_BAD_HDR;
@@ -1008,9 +1038,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                        if (verbose)
                                ubi_warn("no VID header found at PEB %d, "
                                         "only 0xFF bytes", pnum);
-                       else if (UBI_IO_DEBUG)
-                               dbg_msg("no VID header found at PEB %d, "
-                                       "only 0xFF bytes", pnum);
+                       dbg_bld("no VID header found at PEB %d, "
+                               "only 0xFF bytes", pnum);
                        if (!read_err)
                                return UBI_IO_FF;
                        else
@@ -1021,9 +1050,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                        ubi_warn("bad magic number at PEB %d: %08x instead of "
                                 "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
                        ubi_dbg_dump_vid_hdr(vid_hdr);
-               } else if (UBI_IO_DEBUG)
-                       dbg_msg("bad magic number at PEB %d: %08x instead of "
-                               "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+               }
+               dbg_bld("bad magic number at PEB %d: %08x instead of "
+                       "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
                return UBI_IO_BAD_HDR;
        }
 
@@ -1035,9 +1064,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
                        ubi_warn("bad CRC at PEB %d, calculated %#08x, "
                                 "read %#08x", pnum, crc, hdr_crc);
                        ubi_dbg_dump_vid_hdr(vid_hdr);
-               } else if (UBI_IO_DEBUG)
-                       dbg_msg("bad CRC at PEB %d, calculated %#08x, "
-                               "read %#08x", pnum, crc, hdr_crc);
+               }
+               dbg_bld("bad CRC at PEB %d, calculated %#08x, "
+                       "read %#08x", pnum, crc, hdr_crc);
                if (!read_err)
                        return UBI_IO_BAD_HDR;
                else
@@ -1097,7 +1126,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
        return err;
 }
 
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
 
 /**
  * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
@@ -1111,6 +1140,9 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
 {
        int err;
 
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
        err = ubi_io_is_bad(ubi, pnum);
        if (!err)
                return err;
@@ -1135,6 +1167,9 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
        magic = be32_to_cpu(ec_hdr->magic);
        if (magic != UBI_EC_HDR_MAGIC) {
                ubi_err("bad magic %#08x, must be %#08x",
@@ -1170,6 +1205,9 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
        uint32_t crc, hdr_crc;
        struct ubi_ec_hdr *ec_hdr;
 
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
        ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
        if (!ec_hdr)
                return -ENOMEM;
@@ -1211,6 +1249,9 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
        magic = be32_to_cpu(vid_hdr->magic);
        if (magic != UBI_VID_HDR_MAGIC) {
                ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
@@ -1249,6 +1290,9 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
        struct ubi_vid_hdr *vid_hdr;
        void *p;
 
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
        if (!vid_hdr)
                return -ENOMEM;
@@ -1294,15 +1338,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
                        int offset, int len)
 {
        int err, i;
+       size_t read;
+       void *buf1;
+       loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       mutex_lock(&ubi->dbg_buf_mutex);
-       err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
-       if (err)
-               goto out_unlock;
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
+       buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
+       if (!buf1) {
+               ubi_err("cannot allocate memory to check writes");
+               return 0;
+       }
+
+       err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
+       if (err && err != -EUCLEAN)
+               goto out_free;
 
        for (i = 0; i < len; i++) {
                uint8_t c = ((uint8_t *)buf)[i];
-               uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
+               uint8_t c1 = ((uint8_t *)buf1)[i];
                int dump_len;
 
                if (c == c1)
@@ -1319,17 +1374,17 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
                ubi_msg("hex dump of the read buffer from %d to %d",
                        i, i + dump_len);
                print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-                              ubi->dbg_peb_buf + i, dump_len, 1);
+                              buf1 + i, dump_len, 1);
                ubi_dbg_dump_stack();
                err = -EINVAL;
-               goto out_unlock;
+               goto out_free;
        }
-       mutex_unlock(&ubi->dbg_buf_mutex);
 
+       vfree(buf1);
        return 0;
 
-out_unlock:
-       mutex_unlock(&ubi->dbg_buf_mutex);
+out_free:
+       vfree(buf1);
        return err;
 }
 
@@ -1348,36 +1403,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 {
        size_t read;
        int err;
+       void *buf;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       mutex_lock(&ubi->dbg_buf_mutex);
-       err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
+       if (!(ubi_chk_flags & UBI_CHK_IO))
+               return 0;
+
+       buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
+       if (!buf) {
+               ubi_err("cannot allocate memory to check for 0xFFs");
+               return 0;
+       }
+
+       err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
        if (err && err != -EUCLEAN) {
                ubi_err("error %d while reading %d bytes from PEB %d:%d, "
                        "read %zd bytes", err, len, pnum, offset, read);
                goto error;
        }
 
-       err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len);
+       err = ubi_check_pattern(buf, 0xFF, len);
        if (err == 0) {
                ubi_err("flash region at PEB %d:%d, length %d does not "
                        "contain all 0xFF bytes", pnum, offset, len);
                goto fail;
        }
-       mutex_unlock(&ubi->dbg_buf_mutex);
 
+       vfree(buf);
        return 0;
 
 fail:
        ubi_err("paranoid check failed for PEB %d", pnum);
        ubi_msg("hex dump of the %d-%d region", offset, offset + len);
-       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-                      ubi->dbg_peb_buf, len, 1);
+       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
        err = -EINVAL;
 error:
        ubi_dbg_dump_stack();
-       mutex_unlock(&ubi->dbg_buf_mutex);
+       vfree(buf);
        return err;
 }
 
-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
+#endif /* CONFIG_MTD_UBI_DEBUG */