Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b887ef1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6

* 'linux-next' of git://git.infradead.org/ubi-2.6:
  UBI: improve NOR flash erasure quirk
  UBI: introduce flash dump helper
  UBI: eliminate possible undefined behaviour
  UBI: print a warning if too many PEBs are corrupted
  UBI: amend NOR flash pre-erase quirk
  UBI: print a message if ECH is corrupted and VIDH is ok
parents 44040f10 de75c771
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -196,4 +196,36 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
	printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
}

/**
 * ubi_dbg_dump_flash - dump a region of flash.
 * @ubi: UBI device description object
 * @pnum: the physical eraseblock number to dump
 * @offset: the starting offset within the physical eraseblock to dump
 * @len: the length of the region to dump
 */
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
{
	int err;
	size_t read;
	void *buf;
	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;

	buf = vmalloc(len);
	if (!buf)
		return;
	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 out;
	}

	dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
		len, pnum, offset);
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
out:
	vfree(buf);
	return;
}

#endif /* CONFIG_MTD_UBI_DEBUG */
+2 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);

#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* General debugging messages */
@@ -167,6 +168,7 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_dump_sv(sv)              ({})
#define ubi_dbg_dump_seb(seb, type)      ({})
#define ubi_dbg_dump_mkvol_req(req)      ({})
#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})

#define UBI_IO_DEBUG               0
#define DBG_DISABLE_BGT            0
+33 −16
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
		ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
			"%zd bytes", err, len, pnum, offset, written);
		ubi_dbg_dump_stack();
		ubi_dbg_dump_flash(ubi, pnum, offset, len);
	} else
		ubi_assert(written == len);

@@ -475,30 +476,46 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
 */
static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
{
	int err;
	int err, err1;
	size_t written;
	loff_t addr;
	uint32_t data = 0;
	struct ubi_vid_hdr vid_hdr;

	addr = (loff_t)pnum * ubi->peb_size;
	err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
	if (err) {
		ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
			"%zd bytes", err, pnum, 0, written);
		ubi_dbg_dump_stack();
		return err;
	}

	addr += ubi->vid_hdr_aloffset;
	addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
	err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
	if (err) {
		ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
			"%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
		ubi_dbg_dump_stack();
		return err;
	if (!err) {
		addr -= ubi->vid_hdr_aloffset;
		err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
				      (void *)&data);
		if (!err)
			return 0;
	}

	/*
	 * We failed to write to the media. This was observed with Spansion
	 * S29GL512N NOR flash. Most probably the eraseblock erasure was
	 * interrupted at a very inappropriate moment, so it became unwritable.
	 * In this case we probably anyway have garbage in this PEB.
	 */
	err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
	if (err1 == UBI_IO_BAD_VID_HDR)
		/*
		 * The VID header is corrupted, so we can safely erase this
		 * PEB and not afraid that it will be treated as a valid PEB in
		 * case of an unclean reboot.
		 */
		return 0;

	/*
	 * The PEB contains a valid VID header, but we cannot invalidate it.
	 * Supposedly the flash media or the driver is screwed up, so return an
	 * error.
	 */
	ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
		pnum, err, err1);
	ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
	return -EIO;
}

/**
+19 −3
Original line number Diff line number Diff line
@@ -75,9 +75,10 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
		dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
	else if (list == &si->erase)
		dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
	else if (list == &si->corr)
	else if (list == &si->corr) {
		dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
	else if (list == &si->alien)
		si->corr_count += 1;
	} else if (list == &si->alien)
		dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
	else
		BUG();
@@ -864,7 +865,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
		}
	}

	/* Both UBI headers seem to be fine */
	if (ec_corr)
		ubi_warn("valid VID header but corrupted EC header at PEB %d",
			 pnum);
	err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
	if (err)
		return err;
@@ -935,6 +938,19 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
	if (si->is_empty)
		ubi_msg("empty MTD device detected");

	/*
	 * Few corrupted PEBs are not a problem and may be just a result of
	 * unclean reboots. However, many of them may indicate some problems
	 * with the flash HW or driver. Print a warning in this case.
	 */
	if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
		ubi_warn("%d PEBs are corrupted", si->corr_count);
		printk(KERN_WARNING "corrupted PEBs are:");
		list_for_each_entry(seb, &si->corr, u.list)
			printk(KERN_CONT " %d", seb->pnum);
		printk(KERN_CONT "\n");
	}

	/*
	 * In case of unknown erase counter we use the mean erase counter
	 * value.
+2 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ struct ubi_scan_volume {
 * @mean_ec: mean erase counter value
 * @ec_sum: a temporary variable used when calculating @mean_ec
 * @ec_count: a temporary variable used when calculating @mean_ec
 * @corr_count: count of corrupted PEBs
 * @image_seq_set: indicates @ubi->image_seq is known
 *
 * This data structure contains the result of scanning and may be used by other
@@ -125,6 +126,7 @@ struct ubi_scan_info {
	int mean_ec;
	uint64_t ec_sum;
	int ec_count;
	int corr_count;
	int image_seq_set;
};

Loading