From patchwork Thu Aug 15 11:00:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Caizhiyong X-Patchwork-Id: 267352 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 86F202C0128 for ; Thu, 15 Aug 2013 21:04:30 +1000 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V9vJ5-0000QX-00; Thu, 15 Aug 2013 11:01:31 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V9vJ3-00050d-AI; Thu, 15 Aug 2013 11:01:29 +0000 Received: from szxga01-in.huawei.com ([119.145.14.64]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V9vIy-0004xc-P3 for linux-mtd@lists.infradead.org; Thu, 15 Aug 2013 11:01:27 +0000 Received: from 172.24.2.119 (EHLO szxeml206-edg.china.huawei.com) ([172.24.2.119]) by szxrg01-dlp.huawei.com (MOS 4.3.4-GA FastPath queued) with ESMTP id BGR01972; Thu, 15 Aug 2013 19:00:37 +0800 (CST) Received: from SZXEML409-HUB.china.huawei.com (10.82.67.136) by szxeml206-edg.china.huawei.com (172.24.2.59) with Microsoft SMTP Server (TLS) id 14.1.323.7; Thu, 15 Aug 2013 19:00:29 +0800 Received: from SZXEML512-MBX.china.huawei.com ([169.254.7.138]) by szxeml409-hub.china.huawei.com ([10.82.67.136]) with mapi id 14.01.0323.007; Thu, 15 Aug 2013 19:00:27 +0800 From: Caizhiyong To: Brian Norris Subject: [PATCH] mtd: cmdlinepart: use cmdline partition parser lib Thread-Topic: [PATCH] mtd: cmdlinepart: use cmdline partition parser lib Thread-Index: Ac6Zpp35Kq/9wx2iTfyvDoN+K+Ysfg== Date: Thu, 15 Aug 2013 11:00:27 +0000 Message-ID: Accept-Language: zh-CN, en-US Content-Language: zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-cr-hashedpuzzle: H/UL INx5 VfSp WHVM XH5D ZFOJ ZV+L Z2MW oouE qnJb tKBY uD8U zdyx 1SnL 4tQS AAxLWQ==; 7; YQBrAHAAbQBAAGwAaQBuAHUAeAAtAGYAbwB1AG4AZABhAHQAaQBvAG4ALgBvAHIAZwA7AGMAbwBtAHAAdQB0AGUAcgBzAGYAbwByAHAAZQBhAGMAZQBAAGcAbQBhAGkAbAAuAGMAbwBtADsAZABlAGQAZQBrAGkAbgBkADEAQABnAG0AYQBpAGwALgBjAG8AbQA7AGsAegBhAGsAQAByAGUAZABoAGEAdAAuAGMAbwBtADsAbABpAG4AdQB4AC0AawBlAHIAbgBlAGwAQAB2AGcAZQByAC4AawBlAHIAbgBlAGwALgBvAHIAZwA7AGwAaQBuAHUAeAAtAG0AdABkAEAAbABpAHMAdABzAC4AaQBuAGYAcgBhAGQAZQBhAGQALgBvAHIAZwA7AHMAaABtAHUAbABpAGsALgBsAGEAZABrAGEAbgBpAEAAZwBtAGEAaQBsAC4AYwBvAG0A; Sosha1_v1; 7; {36C21AC8-BA11-49A7-BBF6-7DD939E05DC4}; YwBhAGkAegBoAGkAeQBvAG4AZwBAAGgAdQBhAHcAZQBpAC4AYwBvAG0A; Thu, 15 Aug 2013 11:00:13 GMT; WwBQAEEAVABDAEgAXQAgAG0AdABkADoAIABjAG0AZABsAGkAbgBlAHAAYQByAHQAOgAgAHUAcwBlACAAYwBtAGQAbABpAG4AZQAgAHAAYQByAHQAaQB0AGkAbwBuACAAcABhAHIAcwBlAHIAIABsAGkAYgA= x-cr-puzzleid: {36C21AC8-BA11-49A7-BBF6-7DD939E05DC4} x-originating-ip: [10.67.223.18] MIME-Version: 1.0 X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130815_070125_779342_8B2207D0 X-CRM114-Status: GOOD ( 25.94 ) X-Spam-Score: -5.4 (-----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-5.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [119.145.14.64 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -2.8 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: "Wanglin \(Albert\)" , Artem Bityutskiy , "linux-kernel@vger.kernel.org" , Karel Zak , "linux-mtd@lists.infradead.org" , Shmulik Ladkani , Andrew Morton X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Cai Zhiyong MTD cmdline partition use cmdline partition parser lib reference: https://lkml.org/lkml/2013/8/6/550 Signed-off-by: Cai ZhiYong --- Documentation/block/cmdline-partition.txt | 93 +++++--- block/cmdline-parser.c | 6 +- drivers/mtd/Kconfig | 1 + drivers/mtd/cmdlinepart.c | 360 ++++-------------------------- 4 files changed, 101 insertions(+), 359 deletions(-) diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt index 651863d..adc5f7a 100644 --- a/Documentation/block/cmdline-partition.txt +++ b/Documentation/block/cmdline-partition.txt @@ -1,40 +1,59 @@ Embedded device command line partition -===================================================================== - -Read block device partition table from command line. -The partition used for fixed block device (eMMC) embedded device. -It is no MBR, save storage space. Bootloader can be easily accessed -by absolute address of data on the block device. -Users can easily change the partition. - -The format for the command line is just like mtdparts: - -blkdevparts=[;] +Authors: Cai Zhiyong + +The format for the command line is as follows, +it is used by MTD device (reference drivers/mtd/cmdlinepart.c) and +block device (reference block/partitions/cmdline.c) + +================================================================================ +For MTD device: + mtdparts=[; := :[,] + := [@][][ro][lk] + := unique name used in mapping driver/device (mtd->name) + := standard linux memsize OR "-" to denote all remaining space + size is automatically truncated at end of device + if specified or trucated size is 0 the part is skipped + := standard linux memsize + if omitted the part will immediately follow the previous part + or 0 if the first part + := '(' NAME ')' + NAME will appear in /proc/mtd + + and can be specified such that the parts are out of order + in physical memory and may even overlap. + + The parts are assigned MTD numbers in the order they are specified in the + command line regardless of their order in physical memory. + + Examples: + + 1 NOR Flash, with 1 single writable partition: + edb7312-nor:- + + 1 NOR Flash with 2 partitions, 1 NAND with one + edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) + +================================================================================ +For block device: + blkdevparts=[;] := :[,] - := [@](part-name) - - - block device disk name, embedded device used fixed block device, - it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0. - - - partition size, in bytes, such as: 512, 1m, 1G. - - - partition start address, in bytes. - -(part-name) - partition name, kernel send uevent with "PARTNAME". application can create - a link to block device partition with the name "PARTNAME". - user space application can access partition by partition name. - -Example: - eMMC disk name is "mmcblk0" and "mmcblk0boot0" - - bootargs: + := [@][] + + block device disk name, embedded device used fixed block device, + it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0. + := standard linux memsize OR "-" to denote all remaining space + size is automatically truncated at end of device + if specified or trucated size is 0 the part is skipped + := standard linux memsize + if omitted the part will immediately follow the previous part + or 0 if the first part + := '(' NAME ')' + partition name, kernel send uevent with "PARTNAME". application could + create a link to block device partition with the name "PARTNAME". + user space application can access partition by partition name. + + Example: + + eMMC disk name is "mmcblk0" and "mmcblk0boot0", bootargs: 'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)' - - dmesg: - mmcblk0: p1(data0) p2(data1) p3() - mmcblk0boot0: p1(boot) p2(kernel) - diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c index 18fb435..7ad2bc2 100644 --- a/block/cmdline-parser.c +++ b/block/cmdline-parser.c @@ -4,8 +4,6 @@ * Written by Cai Zhiyong * */ -#include -#include #include static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) @@ -158,6 +156,7 @@ void cmdline_parts_free(struct cmdline_parts **parts) *parts = next_parts; } } +EXPORT_SYMBOL(cmdline_parts_free); int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline) { @@ -205,6 +204,7 @@ fail: cmdline_parts_free(parts); goto done; } +EXPORT_SYMBOL(cmdline_parts_parse); struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, const char *bdev) @@ -213,6 +213,7 @@ struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, parts = parts->next_parts; return parts; } +EXPORT_SYMBOL(cmdline_parts_find); /* * add_part() @@ -247,3 +248,4 @@ void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, break; } } +EXPORT_SYMBOL(cmdline_parts_set); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5fab4e6e..6f7f9ca 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -75,6 +75,7 @@ endif # MTD_REDBOOT_PARTS config MTD_CMDLINE_PARTS tristate "Command line partition table parsing" + select CMDLINE_PARSER depends on MTD ---help--- Allow generic configuration of the MTD partition tables via the kernel diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 721caeb..240b4ac 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -18,34 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * The format for the command line is as follows: + * Verbose please reference "Documentation/block/cmdline-partition.txt" * - * mtdparts=[; := :[,] - * := [@][][ro][lk] - * := unique name used in mapping driver/device (mtd->name) - * := standard linux memsize OR "-" to denote all remaining space - * size is automatically truncated at end of device - * if specified or trucated size is 0 the part is skipped - * := standard linux memsize - * if omitted the part will immediately follow the previous part - * or 0 if the first part - * := '(' NAME ')' - * NAME will appear in /proc/mtd - * - * and can be specified such that the parts are out of order - * in physical memory and may even overlap. - * - * The parts are assigned MTD numbers in the order they are specified in the - * command line regardless of their order in physical memory. - * - * Examples: - * - * 1 NOR Flash, with 1 single writable partition: - * edb7312-nor:- - * - * 1 NOR Flash with 2 partitions, 1 NAND with one - * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) */ #include @@ -54,249 +28,43 @@ #include #include #include +#include -/* error message prefix */ -#define ERRP "mtd: " - -/* debug macro */ -#if 0 -#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) -#else -#define dbg(x) -#endif - - -/* special size referring to all the remaining space in a partition */ -#define SIZE_REMAINING ULLONG_MAX -#define OFFSET_CONTINUOUS ULLONG_MAX - -struct cmdline_mtd_partition { - struct cmdline_mtd_partition *next; - char *mtd_id; - int num_parts; - struct mtd_partition *parts; -}; - -/* mtdpart_setup() parses into here */ -static struct cmdline_mtd_partition *partitions; - -/* the command line passed to mtdpart_setup() */ static char *mtdparts; -static char *cmdline; -static int cmdline_parsed; +static struct cmdline_parts *mtd_cmdline_parts; -/* - * Parse one partition definition for an MTD. Since there can be many - * comma separated partition definitions, this function calls itself - * recursively until no more partition definitions are found. Nice side - * effect: the memory to keep the mtd_partition structs and the names - * is allocated upon the last definition being found. At that point the - * syntax has been verified ok. - */ -static struct mtd_partition * newpart(char *s, - char **retptr, - int *num_parts, - int this_part, - unsigned char **extra_mem_ptr, - int extra_mem_size) +static int add_part(int slot, struct cmdline_subpart *subpart, void *param) { - struct mtd_partition *parts; - unsigned long long size, offset = OFFSET_CONTINUOUS; - char *name; - int name_len; - unsigned char *extra_mem; - char delim; - unsigned int mask_flags; - - /* fetch the partition size */ - if (*s == '-') { - /* assign all remaining space to this partition */ - size = SIZE_REMAINING; - s++; - } else { - size = memparse(s, &s); - if (size < PAGE_SIZE) { - printk(KERN_ERR ERRP "partition size too small (%llx)\n", - size); - return ERR_PTR(-EINVAL); - } - } - - /* fetch partition name and flags */ - mask_flags = 0; /* this is going to be a regular partition */ - delim = 0; - - /* check for offset */ - if (*s == '@') { - s++; - offset = memparse(s, &s); - } - - /* now look for name */ - if (*s == '(') - delim = ')'; - - if (delim) { - char *p; + struct mtd_partition *mtdpart = &((struct mtd_partition *)param)[slot]; - name = ++s; - p = strchr(name, delim); - if (!p) { - printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); - return ERR_PTR(-EINVAL); - } - name_len = p - name; - s = p + 1; - } else { - name = NULL; - name_len = 13; /* Partition_000 */ - } - - /* record name length for memory allocation later */ - extra_mem_size += name_len + 1; + mtdpart->offset = subpart->from; + mtdpart->size = subpart->size; + mtdpart->name = subpart->name; + mtdpart->mask_flags = 0; - /* test for options */ - if (strncmp(s, "ro", 2) == 0) { - mask_flags |= MTD_WRITEABLE; - s += 2; - } + if (subpart->flags & PF_RDONLY) + mtdpart->mask_flags |= MTD_WRITEABLE; /* if lk is found do NOT unlock the MTD partition*/ - if (strncmp(s, "lk", 2) == 0) { - mask_flags |= MTD_POWERUP_LOCK; - s += 2; - } - - /* test if more partitions are following */ - if (*s == ',') { - if (size == SIZE_REMAINING) { - printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n"); - return ERR_PTR(-EINVAL); - } - /* more partitions follow, parse them */ - parts = newpart(s + 1, &s, num_parts, this_part + 1, - &extra_mem, extra_mem_size); - if (IS_ERR(parts)) - return parts; - } else { - /* this is the last partition: allocate space for all */ - int alloc_size; - - *num_parts = this_part + 1; - alloc_size = *num_parts * sizeof(struct mtd_partition) + - extra_mem_size; - - parts = kzalloc(alloc_size, GFP_KERNEL); - if (!parts) - return ERR_PTR(-ENOMEM); - extra_mem = (unsigned char *)(parts + *num_parts); - } - - /* enter this partition (offset will be calculated later if it is zero at this point) */ - parts[this_part].size = size; - parts[this_part].offset = offset; - parts[this_part].mask_flags = mask_flags; - if (name) - strlcpy(extra_mem, name, name_len + 1); - else - sprintf(extra_mem, "Partition_%03d", this_part); - parts[this_part].name = extra_mem; - extra_mem += name_len + 1; + if (subpart->flags & PF_POWERUP_LOCK) + mtdpart->mask_flags |= MTD_POWERUP_LOCK; - dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n", - this_part, parts[this_part].name, parts[this_part].offset, - parts[this_part].size, parts[this_part].mask_flags)); - - /* return (updated) pointer to extra_mem memory */ - if (extra_mem_ptr) - *extra_mem_ptr = extra_mem; - - /* return (updated) pointer command line string */ - *retptr = s; - - /* return partition table */ - return parts; + return 0; } /* - * Parse the command line. + * This is the handler for our kernel parameter, called from + * main.c::checksetup(). Note that we can not yet kmalloc() anything, + * so we only save the commandline for later processing. + * + * This function needs to be visible for bootloaders. */ -static int mtdpart_setup_real(char *s) +static int __init mtdpart_setup(char *s) { - cmdline_parsed = 1; - - for( ; s != NULL; ) - { - struct cmdline_mtd_partition *this_mtd; - struct mtd_partition *parts; - int mtd_id_len, num_parts; - char *p, *mtd_id; - - mtd_id = s; - - /* fetch */ - p = strchr(s, ':'); - if (!p) { - printk(KERN_ERR ERRP "no mtd-id\n"); - return -EINVAL; - } - mtd_id_len = p - mtd_id; - - dbg(("parsing <%s>\n", p+1)); - - /* - * parse one mtd. have it reserve memory for the - * struct cmdline_mtd_partition and the mtd-id string. - */ - parts = newpart(p + 1, /* cmdline */ - &s, /* out: updated cmdline ptr */ - &num_parts, /* out: number of parts */ - 0, /* first partition */ - (unsigned char**)&this_mtd, /* out: extra mem */ - mtd_id_len + 1 + sizeof(*this_mtd) + - sizeof(void*)-1 /*alignment*/); - if (IS_ERR(parts)) { - /* - * An error occurred. We're either: - * a) out of memory, or - * b) in the middle of the partition spec - * Either way, this mtd is hosed and we're - * unlikely to succeed in parsing any more - */ - return PTR_ERR(parts); - } - - /* align this_mtd */ - this_mtd = (struct cmdline_mtd_partition *) - ALIGN((unsigned long)this_mtd, sizeof(void *)); - /* enter results */ - this_mtd->parts = parts; - this_mtd->num_parts = num_parts; - this_mtd->mtd_id = (char*)(this_mtd + 1); - strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); - - /* link into chain */ - this_mtd->next = partitions; - partitions = this_mtd; - - dbg(("mtdid=<%s> num_parts=<%d>\n", - this_mtd->mtd_id, this_mtd->num_parts)); - - - /* EOS - we're done */ - if (*s == 0) - break; - - /* does another spec follow? */ - if (*s != ';') { - printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s); - return -EINVAL; - } - s++; - } - - return 0; + mtdparts = s; + return 1; } +__setup("mtdparts=", mtdpart_setup); /* * Main function to be called from the MTD mapping driver/device to @@ -309,82 +77,36 @@ static int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, struct mtd_part_parser_data *data) { - unsigned long long offset; - int i, err; - struct cmdline_mtd_partition *part; - const char *mtd_id = master->name; + struct cmdline_parts *parts; - /* parse command line */ - if (!cmdline_parsed) { - err = mtdpart_setup_real(cmdline); - if (err) - return err; - } + if (mtdparts) { + if (mtd_cmdline_parts) + cmdline_parts_free(&mtd_cmdline_parts); + + if (cmdline_parts_parse(&mtd_cmdline_parts, mtdparts)) { + mtdparts = NULL; + return -EINVAL; + } - /* - * Search for the partition definition matching master->name. - * If master->name is not set, stop at first partition definition. - */ - for (part = partitions; part; part = part->next) { - if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) - break; + mtdparts = NULL; } - if (!part) + if (!mtd_cmdline_parts) return 0; - for (i = 0, offset = 0; i < part->num_parts; i++) { - if (part->parts[i].offset == OFFSET_CONTINUOUS) - part->parts[i].offset = offset; - else - offset = part->parts[i].offset; - - if (part->parts[i].size == SIZE_REMAINING) - part->parts[i].size = master->size - offset; - - if (offset + part->parts[i].size > master->size) { - printk(KERN_WARNING ERRP - "%s: partitioning exceeds flash size, truncating\n", - part->mtd_id); - part->parts[i].size = master->size - offset; - } - offset += part->parts[i].size; - - if (part->parts[i].size == 0) { - printk(KERN_WARNING ERRP - "%s: skipping zero sized partition\n", - part->mtd_id); - part->num_parts--; - memmove(&part->parts[i], &part->parts[i + 1], - sizeof(*part->parts) * (part->num_parts - i)); - i--; - } - } + parts = cmdline_parts_find(mtd_cmdline_parts, master->name); + if (!parts) + return 0; - *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, - GFP_KERNEL); + *pparts = kzalloc(sizeof(**pparts) * parts->nr_subparts, GFP_KERNEL); if (!*pparts) return -ENOMEM; - return part->num_parts; -} + cmdline_parts_set(parts, master->size, 0, add_part, (void *)*pparts); - -/* - * This is the handler for our kernel parameter, called from - * main.c::checksetup(). Note that we can not yet kmalloc() anything, - * so we only save the commandline for later processing. - * - * This function needs to be visible for bootloaders. - */ -static int __init mtdpart_setup(char *s) -{ - cmdline = s; - return 1; + return parts->nr_subparts; } -__setup("mtdparts=", mtdpart_setup); - static struct mtd_part_parser cmdline_parser = { .owner = THIS_MODULE, .parse_fn = parse_cmdline_partitions, @@ -393,8 +115,6 @@ static struct mtd_part_parser cmdline_parser = { static int __init cmdline_parser_init(void) { - if (mtdparts) - mtdpart_setup(mtdparts); return register_mtd_parser(&cmdline_parser); }