diff options
| author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-09-21 09:58:36 +0000 | 
|---|---|---|
| committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-09-21 09:58:36 +0000 | 
| commit | b93baae0249cc7cac36138c0733dcd9d9a717c7c (patch) | |
| tree | 46ce9bd76eafa5714c52be9621ebc552c26ea7d9 /target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch | |
| parent | f5f7f6efeead53d7cedc9af0135a6c4b95a0eea5 (diff) | |
implement write support for partitions covering only a part of an eraseblock (buffer data that would otherwise be erased)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17658 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch')
| -rw-r--r-- | target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch | 146 | 
1 files changed, 146 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch b/target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch new file mode 100644 index 000000000..d3234f004 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.31/222-partial_eraseblock_write.patch @@ -0,0 +1,146 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -21,6 +21,8 @@ + #include <linux/root_dev.h> + #include <linux/magic.h> +  ++#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +  +@@ -226,13 +228,60 @@ static int part_erase(struct mtd_info *m + 		return -EROFS; + 	if (instr->addr >= mtd->size) + 		return -EINVAL; ++ ++	instr->partial_start = false; ++	if (mtd->flags & MTD_ERASE_PARTIAL) { ++		size_t readlen = 0; ++		u64 mtd_ofs; ++ ++		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++		if (!instr->erase_buf) ++			return -ENOMEM; ++ ++		mtd_ofs = part->offset + instr->addr; ++		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); ++ ++		if (instr->erase_buf_ofs > 0) { ++			instr->addr -= instr->erase_buf_ofs; ++			ret = part->master->read(part->master, ++				instr->addr + part->offset, ++				part->master->erasesize, ++				&readlen, instr->erase_buf); ++ ++			instr->partial_start = true; ++		} else { ++			mtd_ofs = part->offset + part->mtd.size; ++			instr->erase_buf_ofs = part->master->erasesize - ++				do_div(mtd_ofs, part->master->erasesize); ++ ++			if (instr->erase_buf_ofs > 0) { ++				instr->len += instr->erase_buf_ofs; ++				ret = part->master->read(part->master, ++					part->offset + instr->addr + ++					instr->len - part->master->erasesize, ++					part->master->erasesize, &readlen, ++					instr->erase_buf); ++			} else { ++				ret = 0; ++			} ++		} ++		if (ret < 0) { ++			kfree(instr->erase_buf); ++			return ret; ++		} ++ ++	} ++ + 	instr->addr += part->offset; + 	ret = part->master->erase(part->master, instr); + 	if (ret) { + 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + 			instr->fail_addr -= part->offset; + 		instr->addr -= part->offset; ++		if (mtd->flags & MTD_ERASE_PARTIAL) ++			kfree(instr->erase_buf); + 	} ++ + 	return ret; + } +  +@@ -240,7 +289,25 @@ void mtd_erase_callback(struct erase_inf + { + 	if (instr->mtd->erase == part_erase) { + 		struct mtd_part *part = PART(instr->mtd); ++		size_t wrlen = 0; +  ++		if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++			if (instr->partial_start) { ++				part->master->write(part->master, ++					instr->addr, instr->erase_buf_ofs, ++					&wrlen, instr->erase_buf); ++				instr->addr += instr->erase_buf_ofs; ++			} else { ++				instr->len -= instr->erase_buf_ofs; ++				part->master->write(part->master, ++					instr->addr + instr->len, ++					instr->erase_buf_ofs, &wrlen, ++					instr->erase_buf + ++					part->master->erasesize - ++					instr->erase_buf_ofs); ++			} ++			kfree(instr->erase_buf); ++		} + 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + 			instr->fail_addr -= part->offset; + 		instr->addr -= part->offset; +@@ -472,18 +539,24 @@ static struct mtd_part *add_one_partitio + 	if ((slave->mtd.flags & MTD_WRITEABLE) && + 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) { + 		/* Doesn't start on a boundary of major erase size */ +-		/* FIXME: Let it be writable if it is on a boundary of +-		 * _minor_ erase size though */ +-		slave->mtd.flags &= ~MTD_WRITEABLE; +-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", +-			part->name); ++		slave->mtd.flags |= MTD_ERASE_PARTIAL; ++		if (((u32) slave->mtd.size) > master->erasesize) ++			slave->mtd.flags &= ~MTD_WRITEABLE; ++		else ++			slave->mtd.erasesize = slave->mtd.size; + 	} + 	if ((slave->mtd.flags & MTD_WRITEABLE) && +-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { +-		slave->mtd.flags &= ~MTD_WRITEABLE; +-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", +-			part->name); +-	} ++	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { ++		slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++		if ((u32) slave->mtd.size > master->erasesize) ++			slave->mtd.flags &= ~MTD_WRITEABLE; ++		else ++			slave->mtd.erasesize = slave->mtd.size; ++	} ++	if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL) ++		printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n", ++				part->name); +  + 	slave->mtd.ecclayout = master->ecclayout; + 	if (master->block_isbad) { +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -46,6 +46,10 @@ struct erase_info { + 	u_long priv; + 	u_char state; + 	struct erase_info *next; ++ ++	u8 *erase_buf; ++	u32 erase_buf_ofs; ++	bool partial_start; + }; +  + struct mtd_erase_region_info {  | 
