From patchwork Tue Nov 11 05:31:32 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [RFC,2/2,MTDPARTS] Support erase regions with odd numbered blocks Date: Mon, 10 Nov 2008 19:31:32 -0000 From: Rohit X-Patchwork-Id: 8082 Message-Id: <491918B4.6040005@samsung.com> To: linux-mtd@lists.infradead.org Cc: 'David Woodhouse' 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 --- mtdpart.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) --- 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;