diff mbox

[RFC,2/2,MTDPARTS] Support erase regions with odd numbered blocks

Message ID 491918B4.6040005@samsung.com
State RFC
Headers show

Commit Message

Rohit Nov. 11, 2008, 5:31 a.m. UTC
An erroneous partition spanning across erase regions with odd
number of blocks may go undetected.

Examples are:

     1. Region 0 has 1 block of 128KB, region 1 has blocks of 256KB.
	A partition with offset 0 and length 256KB (gets erase size 256KB)
	is invalid but passes all checks.

     2. Region 0 has 1 block of 128KB, region 1 has 1 block of 256KB
	and region 2 has 128KB blocks. A partition with offset 0
	and length 512KB (gets biggest erasesize ie 256KB) is invalid.
	Such a partition passes all checks.

The patch checks if the portion of a partition present in
each region is multiple of erase size of partition.

Signed-off-by: Rohit Hagargundgi <h.rohit@samsung.com>
---
 mtdpart.c |   25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

---
diff mbox

Patch

diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 3728913..f091943 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -425,7 +425,7 @@  static struct mtd_part *add_one_partition(struct mtd_info *master,
 	}
 	if (master->numeraseregions > 1) {
 		/* Deal with variable erase size stuff */
-		int i, max = master->numeraseregions;
+		int i, rgn, max = master->numeraseregions;
 		u32 end = slave->offset + slave->mtd.size;
 		struct mtd_erase_region_info *regions = master->eraseregions;
 
@@ -437,12 +437,35 @@  static struct mtd_part *add_one_partition(struct mtd_info *master,
 		i--;
 
 		/* Pick biggest erasesize */
+		rgn = i;
 		for (; i < max && regions[i].offset < end; i++) {
 			if (slave->mtd.erasesize < regions[i].erasesize) {
 				slave->mtd.erasesize = regions[i].erasesize;
 			}
 		}
 		BUG_ON(slave->mtd.erasesize == 0);
+
+		if (slave->mtd.flags & MTD_WRITEABLE) {
+			/* If partition spans many erase regions,
+			 * the partition portion present in each region
+			 * should be multiple of biggest erase size
+			 */
+			unsigned portion_start, portion_end, region_end;
+
+			for (i = rgn; i < max && regions[i].offset < end; i++) {
+				portion_start = max(regions[i].offset, slave->offset);
+				region_end = regions[i].offset +
+					     regions[i].erasesize * regions[i].numblocks;
+				portion_end = min(end, region_end);
+
+				if ((portion_end - portion_start) % slave->mtd.erasesize) {
+					slave->mtd.flags &= ~MTD_WRITEABLE;
+					printk(KERN_WARNING"mtd: partition \"%s\" is not erase block"
+						" aligned within erase region -- force read-only\n", part->name);
+					break;
+				}
+			}
+		}
 	} else {
 		/* Single erase size */
 		slave->mtd.erasesize = master->erasesize;