diff options
Diffstat (limited to 'target/linux/generic/patches-2.6.39/400-rootfs_split.patch')
| -rw-r--r-- | target/linux/generic/patches-2.6.39/400-rootfs_split.patch | 329 | 
1 files changed, 329 insertions, 0 deletions
diff --git a/target/linux/generic/patches-2.6.39/400-rootfs_split.patch b/target/linux/generic/patches-2.6.39/400-rootfs_split.patch new file mode 100644 index 000000000..45072bab2 --- /dev/null +++ b/target/linux/generic/patches-2.6.39/400-rootfs_split.patch @@ -0,0 +1,329 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -47,6 +47,16 @@ config MTD_PARTITIONS +  + if MTD_PARTITIONS +  ++config MTD_ROOTFS_ROOT_DEV ++	bool "Automatically set 'rootfs' partition to be root filesystem" ++	depends on MTD_PARTITIONS ++	default y ++ ++config MTD_ROOTFS_SPLIT ++	bool "Automatically split 'rootfs' partition for squashfs" ++	depends on MTD_PARTITIONS ++	default y ++ + config MTD_REDBOOT_PARTS + 	tristate "RedBoot partition table parsing" + 	---help--- +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -29,6 +29,8 @@ + #include <linux/kmod.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> ++#include <linux/root_dev.h> ++#include <linux/magic.h> + #include <linux/err.h> +  + /* Our partition linked list */ +@@ -48,7 +50,7 @@ struct mtd_part { +  * the pointer to that structure with this macro. +  */ + #define PART(x)  ((struct mtd_part *)(x)) +- ++#define IS_PART(mtd) (mtd->read == part_read) +  + /* +  * MTD methods which simply translate the effective address and pass through +@@ -636,6 +638,153 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); +  ++#ifdef CONFIG_MTD_ROOTFS_SPLIT ++#define ROOTFS_SPLIT_NAME "rootfs_data" ++#define ROOTFS_REMOVED_NAME "<removed>" ++ ++struct squashfs_super_block { ++	__le32 s_magic; ++	__le32 pad0[9]; ++	__le64 bytes_used; ++}; ++ ++ ++static int split_squashfs(struct mtd_info *master, int offset, int *split_offset) ++{ ++	struct squashfs_super_block sb; ++	int len, ret; ++ ++	ret = master->read(master, offset, sizeof(sb), &len, (void *) &sb); ++	if (ret || (len != sizeof(sb))) { ++		printk(KERN_ALERT "split_squashfs: error occured while reading " ++			"from \"%s\"\n", master->name); ++		return -EINVAL; ++	} ++ ++	if (SQUASHFS_MAGIC != le32_to_cpu(sb.s_magic) ) { ++		printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n", ++			master->name); ++		*split_offset = 0; ++		return 0; ++	} ++ ++	if (le64_to_cpu((sb.bytes_used)) <= 0) { ++		printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n", ++			master->name); ++		*split_offset = 0; ++		return 0; ++	} ++ ++	len = (u32) le64_to_cpu(sb.bytes_used); ++	len += (offset & 0x000fffff); ++	len +=  (master->erasesize - 1); ++	len &= ~(master->erasesize - 1); ++	len -= (offset & 0x000fffff); ++	*split_offset = offset + len; ++ ++	return 0; ++} ++ ++static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part) ++{ ++	struct mtd_partition *dpart; ++	struct mtd_part *slave = NULL; ++	int ret, split_offset = 0; ++ ++	ret = split_squashfs(master, part->offset, &split_offset); ++	if (ret) ++		return ret; ++ ++	if (split_offset <= 0) ++		return 0; ++ ++	dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL); ++	if (dpart == NULL) { ++		printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n", ++			ROOTFS_SPLIT_NAME); ++		return -ENOMEM; ++	} ++ ++	memcpy(dpart, part, sizeof(*part)); ++	dpart->name = (unsigned char *)&dpart[1]; ++	strcpy(dpart->name, ROOTFS_SPLIT_NAME); ++ ++	dpart->size -= split_offset - dpart->offset; ++	dpart->offset = split_offset; ++ ++	if (dpart == NULL) ++		return 1; ++ ++	printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n", ++		ROOTFS_SPLIT_NAME, dpart->offset, dpart->size); ++ ++	slave = allocate_partition(master, dpart, 0, split_offset); ++	if (IS_ERR(slave)) ++		return PTR_ERR(slave); ++	mutex_lock(&mtd_partitions_mutex); ++	list_add(&slave->list, &mtd_partitions); ++	mutex_unlock(&mtd_partitions_mutex); ++ ++	add_mtd_device(&slave->mtd); ++ ++	rpart->split = &slave->mtd; ++ ++	return 0; ++} ++ ++static int refresh_rootfs_split(struct mtd_info *mtd) ++{ ++	struct mtd_partition tpart; ++	struct mtd_part *part; ++	char *name; ++	//int index = 0; ++	int offset, size; ++	int ret; ++ ++	part = PART(mtd); ++ ++	/* check for the new squashfs offset first */ ++	ret = split_squashfs(part->master, part->offset, &offset); ++	if (ret) ++		return ret; ++ ++	if ((offset > 0) && !mtd->split) { ++		printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name); ++		/* if we don't have a rootfs split partition, create a new one */ ++		tpart.name = (char *) mtd->name; ++		tpart.size = mtd->size; ++		tpart.offset = part->offset; ++ ++		return split_rootfs_data(part->master, &part->mtd, &tpart); ++	} else if ((offset > 0) && mtd->split) { ++		/* update the offsets of the existing partition */ ++		size = mtd->size + part->offset - offset; ++ ++		part = PART(mtd->split); ++		part->offset = offset; ++		part->mtd.size = size; ++		printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n", ++			__func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"), ++			(u32) part->offset, (u32) part->mtd.size); ++		name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL); ++		strcpy(name, ROOTFS_SPLIT_NAME); ++		part->mtd.name = name; ++	} else if ((offset <= 0) && mtd->split) { ++		printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name); ++ ++		/* mark existing partition as removed */ ++		part = PART(mtd->split); ++		name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL); ++		strcpy(name, ROOTFS_REMOVED_NAME); ++		part->mtd.name = name; ++		part->offset = 0; ++		part->mtd.size = 0; ++	} ++ ++	return 0; ++} ++#endif /* CONFIG_MTD_ROOTFS_SPLIT */ ++ + /* +  * This function, given a master MTD object and a partition table, creates +  * and registers slave MTD objects which are bound to the master according to +@@ -652,6 +801,9 @@ int add_mtd_partitions(struct mtd_info * + 	struct mtd_part *slave; + 	uint64_t cur_offset = 0; + 	int i; ++#ifdef CONFIG_MTD_ROOTFS_SPLIT ++	int ret; ++#endif +  + 	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); +  +@@ -666,6 +818,21 @@ int add_mtd_partitions(struct mtd_info * +  + 		add_mtd_device(&slave->mtd); +  ++		if (!strcmp(parts[i].name, "rootfs")) { ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++			if (ROOT_DEV == 0) { ++				printk(KERN_NOTICE "mtd: partition \"rootfs\" " ++					"set to be root filesystem\n"); ++				ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index); ++			} ++#endif ++#ifdef CONFIG_MTD_ROOTFS_SPLIT ++			ret = split_rootfs_data(master, &slave->mtd, &parts[i]); ++			/* if (ret == 0) ++			 * 	j++; */ ++#endif ++		} ++ + 		cur_offset = slave->offset + slave->mtd.size; + 	} +  +@@ -673,6 +840,32 @@ int add_mtd_partitions(struct mtd_info * + } + EXPORT_SYMBOL(add_mtd_partitions); +  ++int refresh_mtd_partitions(struct mtd_info *mtd) ++{ ++	int ret = 0; ++ ++	if (IS_PART(mtd)) { ++		struct mtd_part *part; ++		struct mtd_info *master; ++ ++		part = PART(mtd); ++		master = part->master; ++		if (master->refresh_device) ++			ret = master->refresh_device(master); ++	} ++ ++	if (!ret && mtd->refresh_device) ++		ret = mtd->refresh_device(mtd); ++ ++#ifdef CONFIG_MTD_ROOTFS_SPLIT ++	if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs")) ++		refresh_rootfs_split(mtd); ++#endif ++ ++	return 0; ++} ++EXPORT_SYMBOL_GPL(refresh_mtd_partitions); ++ + static DEFINE_SPINLOCK(part_parser_lock); + static LIST_HEAD(part_parsers); +  +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -841,6 +841,13 @@ static int mtd_ioctl(struct file *file,  + 		file->f_pos = 0; + 		break; + 	} ++#ifdef CONFIG_MTD_PARTITIONS ++	case MTDREFRESH: ++	{ ++		ret = refresh_mtd_partitions(mtd); ++		break; ++	} ++#endif +  + 	case OTPGETREGIONCOUNT: + 	case OTPGETREGIONINFO: +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -125,6 +125,7 @@ struct nand_ecclayout { + 	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; + }; +  ++struct mtd_info; + struct mtd_info { + 	u_char type; + 	uint32_t flags; +@@ -277,6 +278,9 @@ struct mtd_info { + 	struct device dev; + 	int usecount; +  ++	int (*refresh_device)(struct mtd_info *mtd); ++	struct mtd_info *split; ++ + 	/* If the driver is something smart, like UBI, it may need to maintain + 	 * its own reference counting. The below functions are only for driver. + 	 * The driver may register its callbacks. These callbacks are not +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -34,12 +34,14 @@ +  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). +  */ +  ++struct mtd_partition; + struct mtd_partition { + 	char *name;			/* identifier string */ + 	uint64_t size;			/* partition size */ + 	uint64_t offset;		/* offset within the master MTD space */ + 	uint32_t mask_flags;		/* master MTD flags to mask out for this partition */ + 	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only) */ ++	int (*refresh_partition)(struct mtd_info *); + }; +  + #define MTDPART_OFS_NXTBLK	(-2) +@@ -51,6 +53,7 @@ struct mtd_info; +  + int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); + int del_mtd_partitions(struct mtd_info *); ++int refresh_mtd_partitions(struct mtd_info *); +  + /* +  * Functions dealing with the various ways of partitioning the space +--- a/include/mtd/mtd-abi.h ++++ b/include/mtd/mtd-abi.h +@@ -127,6 +127,7 @@ struct otp_info { + #define MEMWRITEOOB64		_IOWR('M', 21, struct mtd_oob_buf64) + #define MEMREADOOB64		_IOWR('M', 22, struct mtd_oob_buf64) + #define MEMISLOCKED		_IOR('M', 23, struct erase_info_user) ++#define MTDREFRESH		_IO('M', 23) +  + /* +  * Obsolete legacy interface. Keep it in order not to break userspace  | 
