lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 21 Aug 2008 19:00:55 -0700 (GMT-07:00)
From:	Bruce Leonard <brucle@...thlink.net>
To:	linux-kernel@...r.kernel.org
Subject: [PATCH 2/2][MTD] Add support for > 2GiB MTD devices

>From 3e33a3cfc289e9baa41f6e7cf4d612d41b88e19b Mon Sep 17 00:00:00 2001
From: brucle <brucle@...inc.com>
Date: Wed, 13 Aug 2008 18:07:19 -0700
Subject: [PATCH] Add support for > 2GiB MTD devices

Signed-off-by: Bruce D. Leonard <brucle@...inc.com>

---
 drivers/mtd/mtdchar.c        |   16 ++++++++--------
 drivers/mtd/mtdcore.c        |    6 +++---
 drivers/mtd/nand/nand_base.c |   36 ++++++++++++++++++++++++------------
 drivers/mtd/nand/nand_bbt.c  |   30 +++++++++++++++---------------
 drivers/mtd/ubi/build.c      |    5 +++--
 include/linux/mtd/mtd.h      |   27 ++++++++++++++++++++++-----
 include/mtd/mtd-abi.h        |    4 ++--
 7 files changed, 77 insertions(+), 47 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index d2f3318..2829faa 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -70,13 +70,13 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
 		offset += file->f_pos;
 		break;
 	case SEEK_END:
-		offset += mtd->size;
+		offset += device_size(mtd);
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (offset >= 0 && offset <= mtd->size)
+	if (offset >= 0 && offset <= device_size(mtd))
 		return file->f_pos = offset;
 
 	return -EINVAL;
@@ -173,8 +173,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
 
-	if (*ppos + count > mtd->size)
-		count = mtd->size - *ppos;
+	if (*ppos + count > device_size(mtd))
+		count = device_size(mtd) - *ppos;
 
 	if (!count)
 		return 0;
@@ -266,11 +266,11 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
 
 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
 
-	if (*ppos == mtd->size)
+	if (*ppos == device_size(mtd))
 		return -ENOSPC;
 
-	if (*ppos + count > mtd->size)
-		count = mtd->size - *ppos;
+	if (*ppos + count > device_size(mtd))
+		count = device_size(mtd) - *ppos;
 
 	if (!count)
 		return 0;
@@ -426,7 +426,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 	case MEMGETINFO:
 		info.type	= mtd->type;
 		info.flags	= mtd->flags;
-		info.size	= mtd->size;
+		info.size	= device_size(mtd);
 		info.erasesize	= mtd->erasesize;
 		info.writesize	= mtd->writesize;
 		info.oobsize	= mtd->oobsize;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index a9d2469..98bc81f 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -60,7 +60,7 @@ int add_mtd_device(struct mtd_info *mtd)
 			/* Some chips always power up locked. Unlock them now */
 			if ((mtd->flags & MTD_WRITEABLE)
 			    && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
-				if (mtd->unlock(mtd, 0, mtd->size))
+				if (mtd->unlock(mtd, 0, device_size(mtd)))
 					printk(KERN_WARNING
 					       "%s: unlock failed, "
 					       "writes may not work\n",
@@ -344,8 +344,8 @@ static inline int mtd_proc_info (char *buf, int i)
 	if (!this)
 		return 0;
 
-	return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,
-		       this->erasesize, this->name);
+	return sprintf(buf, "mtd%d: %16.16llx %8.8x   \"%s\"\n", i,
+		       device_size(this), this->erasesize, this->name);
 }
 
 static int mtd_read_proc (char *page, char **start, off_t off, int count,
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d5ac675..2463250 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1179,7 +1179,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
 	int ret;
 
 	/* Do not allow reads past end of device */
-	if ((from + len) > mtd->size)
+	if ((from + len) > device_size(mtd))
 		return -EINVAL;
 	if (!len)
 		return 0;
@@ -1371,8 +1371,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 	}
 
 	/* Do not allow reads past end of device */
-	if (unlikely(from >= mtd->size ||
-		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
+	if (unlikely(from >= device_size(mtd) ||
+		     ops->ooboffs + readlen > ((device_size(mtd) >> chip->page_shift) -
 					(from >> chip->page_shift)) * len)) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
 			"Attempt read beyond end of device\n");
@@ -1448,7 +1448,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
 	ops->retlen = 0;
 
 	/* Do not allow reads past end of device */
-	if (ops->datbuf && (from + ops->len) > mtd->size) {
+	if (ops->datbuf && (from + ops->len) > device_size(mtd)) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
 		      "Attempt read beyond end of device\n");
 		return -EINVAL;
@@ -1813,7 +1813,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 	int ret;
 
 	/* Do not allow reads past end of device */
-	if ((to + len) > mtd->size)
+	if ((to + len) > device_size(mtd))
 		return -EINVAL;
 	if (!len)
 		return 0;
@@ -1869,9 +1869,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	}
 
 	/* Do not allow reads past end of device */
-	if (unlikely(to >= mtd->size ||
+	if (unlikely(to >= device_size(mtd) ||
 		     ops->ooboffs + ops->ooblen >
-			((mtd->size >> chip->page_shift) -
+			((device_size(mtd) >> chip->page_shift) -
 			 (to >> chip->page_shift)) * len)) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
 			"Attempt write beyond end of device\n");
@@ -1928,7 +1928,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
 	ops->retlen = 0;
 
 	/* Do not allow writes past end of device */
-	if (ops->datbuf && (to + ops->len) > mtd->size) {
+	if (ops->datbuf && (to + ops->len) > device_size(mtd)) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
 		      "Attempt read beyond end of device\n");
 		return -EINVAL;
@@ -2019,8 +2019,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 	int rewrite_bbt[NAND_MAX_CHIPS]={0};
 	unsigned int bbt_masked_page = 0xffffffff;
 
-	DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
-	      (unsigned int)instr->addr, (unsigned int)instr->len);
+	DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%016llx, len = %i\n",
+	      instr->addr, (unsigned int)instr->len);
 
 	/* Start address must align on block boundary */
 	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
@@ -2036,7 +2036,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 	}
 
 	/* Do not allow erase past end of device */
-	if ((instr->len + instr->addr) > mtd->size) {
+	if ((instr->len + instr->addr) > device_size(mtd)) {
 		DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
 		      "Erase past end of device\n");
 		return -EINVAL;
@@ -2208,7 +2208,7 @@ static void nand_sync(struct mtd_info *mtd)
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
 	/* Check for invalid offset */
-	if (offs > mtd->size)
+	if (offs > device_size(mtd))
 		return -EINVAL;
 
 	return nand_block_checkbad(mtd, offs, 1, 0);
@@ -2502,6 +2502,18 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
 	chip->numchips = i;
 	mtd->size = i * chip->chipsize;
 
+	/* Because mtd->size is 32 bits, if the total 'device size'
+	 * is greater than 2GiB it will overflow mtd->size and signal
+	 * that we need to use the new MTD mio interface.
+	 */
+	if (mtd->size == 0) {
+		mtd->num_eraseblocks = (i * (__u64)(chip->chipsize)) >>
+					chip->phys_erase_shift;
+	} else {
+		/* Can't guarantee mtd was kzalloc'ed */
+		mtd->num_eraseblocks = 0;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 2f9f0f5..ae6e1a5 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 				if (tmp == msk)
 					continue;
 				if (reserved_block_code && (tmp == reserved_block_code)) {
-					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
-					       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%016llx\n",
+					       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
 					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
 					mtd->ecc_stats.bbtblocks++;
 					continue;
 				}
 				/* Leave it for now, if its matured we can move this
 				 * message to MTD_DEBUG_LEVEL0 */
-				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
-				       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%016llx\n",
+				       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
 				/* Factory marked bad or worn out ? */
 				if (tmp == 0)
 					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -399,7 +399,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 	if (chip == -1) {
 		/* Note that numblocks is 2 * (real numblocks) here, see i+=2
 		 * below as it makes shifting and masking less painful */
-		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
+		numblocks = device_size(mtd) >> (this->bbt_erase_shift - 1);
 		startblock = 0;
 		from = 0;
 	} else {
@@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 		if (ret) {
 			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-			printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
-			       i >> 1, (unsigned int)from);
+			printk(KERN_WARNING "Bad eraseblock %d at 0x%016llx\n",
+			       i >> 1, from);
 			mtd->ecc_stats.badblocks++;
 		}
 
@@ -467,7 +467,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
 	/* Search direction top -> down ? */
 	if (td->options & NAND_BBT_LASTBLOCK) {
-		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
+		startblock = (device_size(mtd) >> this->bbt_erase_shift) - 1;
 		dir = -1;
 	} else {
 		startblock = 0;
@@ -481,7 +481,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 		startblock &= bbtblocks - 1;
 	} else {
 		chips = 1;
-		bbtblocks = mtd->size >> this->bbt_erase_shift;
+		bbtblocks = device_size(mtd) >> this->bbt_erase_shift;
 	}
 
 	/* Number of bits for each erase block in the bbt */
@@ -587,7 +587,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			chip = chipsel;
 		}
 	} else {
-		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
+		numblocks = (int)(device_size(mtd) >> this->bbt_erase_shift);
 		nrchips = 1;
 	}
 
@@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 		memset(&einfo, 0, sizeof(einfo));
 		einfo.mtd = mtd;
-		einfo.addr = (unsigned long)to;
+		einfo.addr = to;
 		einfo.len = 1 << this->bbt_erase_shift;
 		res = nand_erase_nand(mtd, &einfo, 1);
 		if (res < 0)
@@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		if (res < 0)
 			goto outerr;
 
-		printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
-		       "0x%02X\n", (unsigned int)to, td->version[chip]);
+		printk(KERN_DEBUG "Bad block table written to 0x%016llx, version "
+		       "0x%02X\n", to, td->version[chip]);
 
 		/* Mark it as used */
 		td->pages[chip] = page;
@@ -896,7 +896,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
 	} else {
 		chips = 1;
-		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+		nrblocks = (int)(device_size(mtd) >> this->bbt_erase_shift);
 	}
 
 	for (i = 0; i < chips; i++) {
@@ -957,7 +957,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
 
-	len = mtd->size >> (this->bbt_erase_shift + 2);
+	len = device_size(mtd) >> (this->bbt_erase_shift + 2);
 	/* Allocate memory (2bit per block) and clear the memory bad block table */
 	this->bbt = kzalloc(len, GFP_KERNEL);
 	if (!this->bbt) {
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index c7630a2..6a576d8 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -561,8 +561,9 @@ static int io_init(struct ubi_device *ubi)
 	 */
 
 	ubi->peb_size   = ubi->mtd->erasesize;
-	ubi->peb_count  = ubi->mtd->size / ubi->mtd->erasesize;
-	ubi->flash_size = ubi->mtd->size;
+	ubi->peb_count  = device_size(ubi->mtd) >>
+				(ffs(ubi->mtd->erasesize) - 1);
+	ubi->flash_size = device_size(ubi->mtd);
 
 	if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
 		ubi->bad_allowed = 1;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9226365..ffa24b6 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -26,13 +26,13 @@
 #define MTD_ERASE_FAILED        0x10
 
 /* If the erase fails, fail_addr might indicate exactly which block failed.  If
-   fail_addr = 0xffffffff, the failure was not at the device level or was not
+   fail_addr = 0xffffffffffffffff, the failure was not at the device level or was not
    specific to any particular block. */
 struct erase_info {
 	struct mtd_info *mtd;
-	u_int32_t addr;
+	u_int64_t addr;
 	u_int32_t len;
-	u_int32_t fail_addr;
+	u_int64_t fail_addr;
 	u_long time;
 	u_long retries;
 	u_int dev;
@@ -101,6 +101,14 @@ struct mtd_info {
 	u_int32_t flags;
 	u_int32_t size;	 // Total size of the MTD
 
+	/* 'size' is becoming problematic as flash densities increase.  Since
+	 * the device's size can be calculated by multiplying the number of
+	 * erase blocks by the size of the erase block, I've added a new
+	 * field 'num_eraseblocks', and wrapped it up in a inline function
+	 * (see below).
+	 */
+	u_int64_t num_eraseblocks;
+
 	/* "Major" erase size for the device. Naïve users may take this
 	 * to be the only erase size available, or may use the more detailed
 	 * information below if they desire
@@ -188,8 +196,8 @@ struct mtd_info {
 	void (*sync) (struct mtd_info *mtd);
 
 	/* Chip-supported device locking */
-	int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
-	int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
+	int (*lock) (struct mtd_info *mtd, loff_t ofs, u_int64_t len);
+	int (*unlock) (struct mtd_info *mtd, loff_t ofs, u_int64_t len);
 
 	/* Power Management functions */
 	int (*suspend) (struct mtd_info *mtd);
@@ -219,6 +227,15 @@ struct mtd_info {
 	void (*put_device) (struct mtd_info *mtd);
 };
 
+/*
+ * Inline function for determining the size of the MTD device, independant
+ * of old or new way of doing things.
+ *
+ */
+static inline u_int64_t device_size(struct mtd_info *a)
+{
+	return a->num_eraseblocks == 0 ? a->size : a->num_eraseblocks * a->erasesize;
+}
 
 	/* Kernel-side ioctl definitions */
 
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index c6c61cd..86347cf 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -6,7 +6,7 @@
 #define __MTD_ABI_H__
 
 struct erase_info_user {
-	uint32_t start;
+	uint64_t start;
 	uint32_t length;
 };
 
@@ -50,7 +50,7 @@ struct mtd_oob_buf {
 struct mtd_info_user {
 	uint8_t type;
 	uint32_t flags;
-	uint32_t size;	 // Total size of the MTD
+	uint64_t size;	 // Total size of the MTD
 	uint32_t erasesize;
 	uint32_t writesize;
 	uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
-- 
1.5.3.4


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ