All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] block: support embedded device command line partition
@ 2013-07-27 13:56 Caizhiyong
  2013-07-30 23:13 ` Andrew Morton
  2013-07-31 13:25 ` Karel Zak
  0 siblings, 2 replies; 15+ messages in thread
From: Caizhiyong @ 2013-07-27 13:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, Wanglin (Albert), Quyaxin

From: Cai Zhiyong <caizhiyong@huawei.com>

Read block device partition table from command line. This partition used for fixed block device (eMMC) embedded device.
It no MBR, can save storage space. Bootloader can be easily accessed by absolute address of data on the block device. It support partition name, provides partition interface.

This code reference MTD partition, source "./drivers/mtd/cmdlinepart.c"
The format for the command line is just like mtdparts.

Examples: eMMC disk name is "mmcblk0"
bootargs 'cmdlineparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'

Signed-off-by: Cai Zhiyong <caizhiyong@huawei.com>
---
 block/partitions/Kconfig   |   6 +
 block/partitions/Makefile  |   1 +
 block/partitions/check.c   |   4 +
 block/partitions/cmdline.c | 346 +++++++++++++++++++++++++++++++++++++++++++++
 block/partitions/cmdline.h |   2 +
 5 files changed, 359 insertions(+)
 create mode 100644 block/partitions/cmdline.c  create mode 100644 block/partitions/cmdline.h

diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig index 4cebb2f..2ebf251 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -260,3 +260,9 @@ config SYSV68_PARTITION
 	  partition table format used by Motorola Delta machines (using
 	  sysv68).
 	  Otherwise, say N.
+
+config CMDLINE_PARTITION
+	bool "Command line partition support" if PARTITION_ADVANCED
+	help
+	  Say Y here if you would read the partitions table from bootargs.
+	  The format for the command line is just like mtdparts.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile index 2be4d7b..4e9d584 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_KARMA_PARTITION) += karma.o
 obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
diff --git a/block/partitions/check.c b/block/partitions/check.c index 19ba207..9ac1df7 100644
--- a/block/partitions/check.c
+++ b/block/partitions/check.c
@@ -34,6 +34,7 @@
 #include "efi.h"
 #include "karma.h"
 #include "sysv68.h"
+#include "cmdline.h"
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
@@ -65,6 +66,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
 	adfspart_check_ADFS,
 #endif
 
+#ifdef CONFIG_CMDLINE_PARTITION
+	cmdline_partition,
+#endif
 #ifdef CONFIG_EFI_PARTITION
 	efi_partition,		/* this must come before msdos */
 #endif
diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c new file mode 100644 index 0000000..05c7e17
--- /dev/null
+++ b/block/partitions/cmdline.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2013 HUAWEI
+ * Author: Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ * Read block device partition table from command line.
+ * Design the partition for eMMC device.
+ * This code reference MTD partition, source "./drivers/mtd/cmdlinepart.c"
+ * The format for the command line is just like mtdparts.
+ *
+ * Examples:
+ *
+ * eMMC disk name is "mmcblk0"
+ * bootargs:
+ * 'cmdlineparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
+ *
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+
+#include "check.h"
+#include "cmdline.h"
+
+#define SIZE_REMAINING              ULLONG_MAX
+#define OFFSET_CONTINUOUS           ULLONG_MAX
+
+struct cmdline_subpart {
+	char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
+	uint64_t from;
+	uint64_t size;
+	struct cmdline_subpart *next_subpart;
+};
+
+struct cmdline_parts {
+	char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
+	struct cmdline_subpart *subpart;
+	struct cmdline_parts *next_parts;
+};
+
+static DEFINE_MUTEX(cmdline_string_mutex);
+
+static char cmdline_string[512] = { 0 }; static struct cmdline_parts 
+*cmdline_parts;
+
+static int parse_subpart(struct cmdline_subpart **subpart, char
+*cmdline) {
+	int ret = 0;
+	struct cmdline_subpart *new_subpart;
+
+	(*subpart) = NULL;
+
+	new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
+	if (!new_subpart)
+		return -ENOMEM;
+
+	if ((*cmdline) == '-') {
+		new_subpart->size = SIZE_REMAINING;
+		cmdline++;
+	} else {
+		new_subpart->size = memparse(cmdline, &cmdline);
+		if (new_subpart->size < PAGE_SIZE) {
+			pr_warn("cmdline partition size is invalid.");
+			ret = -EFAULT;
+			goto fail;
+		}
+	}
+
+	if ((*cmdline) == '@') {
+		cmdline++;
+		new_subpart->from = memparse(cmdline, &cmdline);
+	} else {
+		new_subpart->from = OFFSET_CONTINUOUS;
+	}
+
+	if ((*cmdline) == '(') {
+
+		int length;
+		char *next = strchr(++cmdline, ')');
+
+		if (!next) {
+			pr_warn("cmdline partition format is invalid.");
+			ret = -EFAULT;
+			goto fail;
+		}
+
+		length = min((int)(next - cmdline),
+			     (int)(sizeof(new_subpart->name) - 1));
+		strncpy(new_subpart->name, cmdline, length);
+		new_subpart->name[length] = '\0';
+
+		cmdline = ++next;
+	} else
+		new_subpart->name[0] = '\0';
+
+	(*subpart) = new_subpart;
+	return 0;
+fail:
+	kfree(new_subpart);
+	return ret;
+}
+
+static void free_subpart(struct cmdline_parts *parts) {
+	struct cmdline_subpart *subpart;
+
+	while (parts->subpart) {
+		subpart = parts->subpart;
+		parts->subpart = subpart->next_subpart;
+		kfree(subpart);
+	}
+}
+
+static void free_parts(struct cmdline_parts **parts) {
+	struct cmdline_parts *next_parts;
+
+	while ((*parts)) {
+		next_parts = (*parts)->next_parts;
+		free_subpart((*parts));
+		kfree((*parts));
+		(*parts) = next_parts;
+	}
+}
+
+static int parse_parts(struct cmdline_parts **parts, const char
+*cmdline) {
+	int ret = -EFAULT;
+	char *next;
+	int length;
+	struct cmdline_subpart **next_subpart;
+	struct cmdline_parts *newparts;
+	char buf[BDEVNAME_SIZE + 32 + 4];
+
+	(*parts) = NULL;
+
+	newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
+	if (!newparts)
+		return -ENOMEM;
+
+	next = strchr(cmdline, ':');
+	if (!next) {
+		pr_warn("cmdline partition has not block device.");
+		goto fail;
+	}
+
+	length = min((int)(next - cmdline), (int)(sizeof(newparts->name) - 1));
+	strncpy(newparts->name, cmdline, length);
+	newparts->name[length] = '\0';
+
+	next_subpart = &newparts->subpart;
+
+	while (next && *(++next)) {
+
+		cmdline = next;
+		next = strchr(cmdline, ',');
+
+		length = (!next) ? (sizeof(buf) - 1) :
+			min((int)(next - cmdline), (int)(sizeof(buf) - 1));
+
+		strncpy(buf, cmdline, length);
+		buf[length] = '\0';
+
+		ret = parse_subpart(next_subpart, buf);
+		if (ret)
+			goto fail;
+
+		next_subpart = &(*next_subpart)->next_subpart;
+	}
+
+	if (!newparts->subpart) {
+		pr_warn("cmdline partition has not valid partition.");
+		goto fail;
+	}
+
+	(*parts) = newparts;
+
+	return 0;
+fail:
+	free_subpart(newparts);
+	kfree(newparts);
+	return ret;
+}
+
+static int parse_cmdline(struct cmdline_parts **parts, const char
+*cmdline) {
+	int ret;
+	char *buf;
+	char *pbuf;
+	char *next;
+	struct cmdline_parts **next_parts;
+
+	(*parts) = NULL;
+
+	next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	next_parts = parts;
+
+	while (next && *pbuf) {
+
+		next = strchr(pbuf, ';');
+		if (next)
+			(*next) = '\0';
+
+		ret = parse_parts(next_parts, pbuf);
+		if (ret)
+			goto fail;
+
+		if (next)
+			pbuf = ++next;
+
+		next_parts = &(*next_parts)->next_parts;
+	}
+
+	if (!(*parts)) {
+		pr_warn("cmdline partition has not valid partition.");
+		ret = -EFAULT;
+		goto fail;
+	}
+
+	ret = 0;
+done:
+	kfree(buf);
+	return ret;
+
+fail:
+	free_parts(parts);
+	goto done;
+}
+
+/*
+ * Purpose: allocate cmdline partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ */
+static int parse_partitions(struct parsed_partitions *state,
+			    struct cmdline_parts *parts)
+{
+	int slot;
+	uint64_t from = 0;
+	uint64_t disk_size;
+	char buf[BDEVNAME_SIZE];
+	struct cmdline_subpart *subpart;
+
+	bdevname(state->bdev, buf);
+
+	while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
+		parts = parts->next_parts;
+
+	if (!parts)
+		return 0;
+
+	disk_size = (uint64_t) get_capacity(state->bdev->bd_disk) << 9;
+
+	for (slot = 1, subpart = parts->subpart;
+	     subpart && slot < state->limit;
+	     subpart = subpart->next_subpart, slot++) {
+
+		unsigned label_max;
+		struct partition_meta_info *info;
+
+		if (subpart->from == OFFSET_CONTINUOUS)
+			subpart->from = from;
+		else
+			from = subpart->from;
+
+		if (from >= disk_size)
+			break;
+
+		if (subpart->size > (disk_size - from))
+			subpart->size = disk_size - from;
+
+		from += subpart->size;
+
+		put_partition(state, slot, le64_to_cpu(subpart->from >> 9),
+			      le64_to_cpu(subpart->size >> 9));
+
+		info = &state->parts[slot].info;
+
+		label_max = min(sizeof(info->volname) - 1,
+			sizeof(subpart->name));
+		strncpy(info->volname, subpart->name, label_max);
+		info->volname[label_max] = '\0';
+		state->parts[slot].has_info = true;
+	}
+
+	strlcat(state->pp_buf, "\n", PAGE_SIZE);
+
+	return 1;
+}
+
+static int set_cmdline_parts(char *str) {
+	strncpy(cmdline_string, str, sizeof(cmdline_string) - 1);
+	cmdline_string[sizeof(cmdline_string) - 1] = '\0';
+	return 1;
+}
+__setup("cmdlineparts=", set_cmdline_parts);
+
+void cmdline_parts_setup(char *str)
+{
+	mutex_lock(&cmdline_string_mutex);
+	set_cmdline_parts(str);
+	mutex_unlock(&cmdline_string_mutex);
+}
+EXPORT_SYMBOL(cmdline_parts_setup);
+
+/*
+ * Purpose: allocate cmdline partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ */
+int cmdline_partition(struct parsed_partitions *state) {
+	int ret;
+
+	mutex_lock(&cmdline_string_mutex);
+	if (cmdline_string[0]) {
+
+		if (cmdline_parts)
+			free_parts(&cmdline_parts);
+
+		if (parse_cmdline(&cmdline_parts, cmdline_string)) {
+			ret = 0;
+			goto fail;
+		}
+		cmdline_string[0] = '\0';
+	}
+	mutex_unlock(&cmdline_string_mutex);
+
+	if (!cmdline_parts)
+		return 0;
+
+	return parse_partitions(state, cmdline_parts);
+
+fail:
+	cmdline_string[0] = '\0';
+	mutex_unlock(&cmdline_string_mutex);
+	return ret;
+}
diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h new file mode 100644 index 0000000..26e0f8d
--- /dev/null
+++ b/block/partitions/cmdline.h
@@ -0,0 +1,2 @@
+
+int cmdline_partition(struct parsed_partitions *state);
--
1.8.1.5


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-07-27 13:56 [PATCH] block: support embedded device command line partition Caizhiyong
@ 2013-07-30 23:13 ` Andrew Morton
  2013-07-31 13:25 ` Karel Zak
  1 sibling, 0 replies; 15+ messages in thread
From: Andrew Morton @ 2013-07-30 23:13 UTC (permalink / raw)
  To: Caizhiyong; +Cc: linux-kernel, Wanglin (Albert), Quyaxin

On Sat, 27 Jul 2013 13:56:24 +0000 Caizhiyong <caizhiyong@huawei.com> wrote:

> From: Cai Zhiyong <caizhiyong@huawei.com>
> 
> Read block device partition table from command line. This partition used for fixed block device (eMMC) embedded device.
> It no MBR, can save storage space. Bootloader can be easily accessed by absolute address of data on the block device. It support partition name, provides partition interface.

That seems a reasonable thing to be able to do.

> This code reference MTD partition, source "./drivers/mtd/cmdlinepart.c"
> The format for the command line is just like mtdparts.
> 
> Examples: eMMC disk name is "mmcblk0"
> bootargs 'cmdlineparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'

We should document this user interface properly.  Is there
documentation under Documentation/ which can be referenced?  If not,
something new should be created.

>
> ...
>
> +struct cmdline_parts {
> +	char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
> +	struct cmdline_subpart *subpart;
> +	struct cmdline_parts *next_parts;
> +};
> +
> +static DEFINE_MUTEX(cmdline_string_mutex);
> +
> +static char cmdline_string[512] = { 0 }; static struct cmdline_parts 
> +*cmdline_parts;

That's messed up.

> +static int parse_subpart(struct cmdline_subpart **subpart, char
> +*cmdline) {

Please convert all the function definitions to standard kernel style:

static int parse_subpart(struct cmdline_subpart **subpart, char *cmdline)
{

> +	int ret = 0;
> +	struct cmdline_subpart *new_subpart;
> +
> +	(*subpart) = NULL;
> +
> +	new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
> +	if (!new_subpart)
> +		return -ENOMEM;
> +
> +	if ((*cmdline) == '-') {
> +		new_subpart->size = SIZE_REMAINING;
> +		cmdline++;
> +	} else {
> +		new_subpart->size = memparse(cmdline, &cmdline);
> +		if (new_subpart->size < PAGE_SIZE) {
> +			pr_warn("cmdline partition size is invalid.");
> +			ret = -EFAULT;

EFAULT is inappropriate here.  EINVAL would be suitable.

> +			goto fail;
> +		}
> +	}
> +
> +	if ((*cmdline) == '@') {
> +		cmdline++;
> +		new_subpart->from = memparse(cmdline, &cmdline);
> +	} else {
> +		new_subpart->from = OFFSET_CONTINUOUS;
> +	}
> +
> +	if ((*cmdline) == '(') {
> +

Remove this newline.

> +		int length;
> +		char *next = strchr(++cmdline, ')');
> +
> +		if (!next) {
> +			pr_warn("cmdline partition format is invalid.");
> +			ret = -EFAULT;

EINVAL

> +			goto fail;
> +		}
> +
> +		length = min((int)(next - cmdline),
> +			     (int)(sizeof(new_subpart->name) - 1));

OK, that's pretty ghastly.

Ideally, the types of the various variable should be compatible, so no
casting is needed.

If that is really truly not practical then use min_t rather than
open-coding the casts.

> +		strncpy(new_subpart->name, cmdline, length);
> +		new_subpart->name[length] = '\0';
> +
> +		cmdline = ++next;
> +	} else
> +		new_subpart->name[0] = '\0';
> +
> +	(*subpart) = new_subpart;
> +	return 0;
> +fail:
> +	kfree(new_subpart);
> +	return ret;
> +}
> +
> +static void free_subpart(struct cmdline_parts *parts) {
> +	struct cmdline_subpart *subpart;
> +
> +	while (parts->subpart) {
> +		subpart = parts->subpart;
> +		parts->subpart = subpart->next_subpart;
> +		kfree(subpart);
> +	}
> +}
> +
> +static void free_parts(struct cmdline_parts **parts) {
> +	struct cmdline_parts *next_parts;
> +
> +	while ((*parts)) {
> +		next_parts = (*parts)->next_parts;
> +		free_subpart((*parts));
> +		kfree((*parts));
> +		(*parts) = next_parts;
> +	}
> +}
> +
> +static int parse_parts(struct cmdline_parts **parts, const char
> +*cmdline) {
> +	int ret = -EFAULT;

EINVAL?

> +	char *next;
> +	int length;
> +	struct cmdline_subpart **next_subpart;
> +	struct cmdline_parts *newparts;
> +	char buf[BDEVNAME_SIZE + 32 + 4];
> +
> +	(*parts) = NULL;
> +
> +	newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
> +	if (!newparts)
> +		return -ENOMEM;
> +
> +	next = strchr(cmdline, ':');
> +	if (!next) {
> +		pr_warn("cmdline partition has not block device.");
> +		goto fail;
> +	}
> +
> +	length = min((int)(next - cmdline), (int)(sizeof(newparts->name) - 1));

Ditto.

> +	strncpy(newparts->name, cmdline, length);
> +	newparts->name[length] = '\0';
> +
> +	next_subpart = &newparts->subpart;
> +
> +	while (next && *(++next)) {
> +

Remove newline.

> +		cmdline = next;
> +		next = strchr(cmdline, ',');
> +
> +		length = (!next) ? (sizeof(buf) - 1) :
> +			min((int)(next - cmdline), (int)(sizeof(buf) - 1));

Sort the types out.

> +		strncpy(buf, cmdline, length);
> +		buf[length] = '\0';
> +
> +		ret = parse_subpart(next_subpart, buf);
> +		if (ret)
> +			goto fail;
> +
> +		next_subpart = &(*next_subpart)->next_subpart;
> +	}
> +
> +	if (!newparts->subpart) {
> +		pr_warn("cmdline partition has not valid partition.");
> +		goto fail;
> +	}
> +
> +	(*parts) = newparts;

The code adds these unneeded parentheses in several places.  They are
unneeded ;)

> +	return 0;
> +fail:
> +	free_subpart(newparts);
> +	kfree(newparts);
> +	return ret;
> +}
> +
> +static int parse_cmdline(struct cmdline_parts **parts, const char
> +*cmdline) {
> +	int ret;
> +	char *buf;
> +	char *pbuf;
> +	char *next;
> +	struct cmdline_parts **next_parts;
> +
> +	(*parts) = NULL;
> +
> +	next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	next_parts = parts;
> +
> +	while (next && *pbuf) {
> +

Remove newline.

> +		next = strchr(pbuf, ';');
> +		if (next)
> +			(*next) = '\0';
> +
> +		ret = parse_parts(next_parts, pbuf);
> +		if (ret)
> +			goto fail;
> +
> +		if (next)
> +			pbuf = ++next;
> +
> +		next_parts = &(*next_parts)->next_parts;
> +	}
> +
> +	if (!(*parts)) {
> +		pr_warn("cmdline partition has not valid partition.");
> +		ret = -EFAULT;
> +		goto fail;
> +	}
> +
> +	ret = 0;
> +done:
> +	kfree(buf);
> +	return ret;
> +
> +fail:
> +	free_parts(parts);
> +	goto done;
> +}
> +
> +/*
> + * Purpose: allocate cmdline partitions.
> + * Returns:
> + * -1 if unable to read the partition table
> + *  0 if this isn't our partition table
> + *  1 if successful
> + */
> +static int parse_partitions(struct parsed_partitions *state,
> +			    struct cmdline_parts *parts)
> +{
> +	int slot;
> +	uint64_t from = 0;
> +	uint64_t disk_size;
> +	char buf[BDEVNAME_SIZE];
> +	struct cmdline_subpart *subpart;
> +
> +	bdevname(state->bdev, buf);
> +
> +	while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
> +		parts = parts->next_parts;
> +
> +	if (!parts)
> +		return 0;
> +
> +	disk_size = (uint64_t) get_capacity(state->bdev->bd_disk) << 9;

Remove the space after the cast.

get_capacity() returns sector_t.  That is appropriate.  It would be
saner if all this code were to use sector_t as well.

Also, u64 is preferred over uint64_t in kernel code.

> +	for (slot = 1, subpart = parts->subpart;
> +	     subpart && slot < state->limit;
> +	     subpart = subpart->next_subpart, slot++) {
> +

Remove newline.

> +		unsigned label_max;
> +		struct partition_meta_info *info;
> +
> +		if (subpart->from == OFFSET_CONTINUOUS)
> +			subpart->from = from;
> +		else
> +			from = subpart->from;
> +
> +		if (from >= disk_size)
> +			break;
> +
> +		if (subpart->size > (disk_size - from))
> +			subpart->size = disk_size - from;
> +
> +		from += subpart->size;
> +
> +		put_partition(state, slot, le64_to_cpu(subpart->from >> 9),
> +			      le64_to_cpu(subpart->size >> 9));
> +
> +		info = &state->parts[slot].info;
> +
> +		label_max = min(sizeof(info->volname) - 1,
> +			sizeof(subpart->name));
> +		strncpy(info->volname, subpart->name, label_max);
> +		info->volname[label_max] = '\0';
> +		state->parts[slot].has_info = true;
> +	}
> +
> +	strlcat(state->pp_buf, "\n", PAGE_SIZE);
> +
> +	return 1;
> +}
> +
> +static int set_cmdline_parts(char *str) {
> +	strncpy(cmdline_string, str, sizeof(cmdline_string) - 1);
> +	cmdline_string[sizeof(cmdline_string) - 1] = '\0';
> +	return 1;
> +}
> +__setup("cmdlineparts=", set_cmdline_parts);
> +
> +void cmdline_parts_setup(char *str)
> +{
> +	mutex_lock(&cmdline_string_mutex);
> +	set_cmdline_parts(str);
> +	mutex_unlock(&cmdline_string_mutex);
> +}
> +EXPORT_SYMBOL(cmdline_parts_setup);

This export is unneed, I expect.

cmdline_parts_setup has no references and can simply be removed?

> +/*
> + * Purpose: allocate cmdline partitions.
> + * Returns:
> + * -1 if unable to read the partition table
> + *  0 if this isn't our partition table
> + *  1 if successful
> + */
> +int cmdline_partition(struct parsed_partitions *state) {
> +	int ret;
> +
> +	mutex_lock(&cmdline_string_mutex);
> +	if (cmdline_string[0]) {
> +
> +		if (cmdline_parts)
> +			free_parts(&cmdline_parts);
> +
> +		if (parse_cmdline(&cmdline_parts, cmdline_string)) {
> +			ret = 0;
> +			goto fail;
> +		}
> +		cmdline_string[0] = '\0';
> +	}
> +	mutex_unlock(&cmdline_string_mutex);
> +
> +	if (!cmdline_parts)
> +		return 0;
> +
> +	return parse_partitions(state, cmdline_parts);

But we dropped the mutex.  Nothing protects cmdline_parts during the
execution of parse_partitions().

> +fail:
> +	cmdline_string[0] = '\0';
> +	mutex_unlock(&cmdline_string_mutex);
> +	return ret;
> +}
> diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h new file mode 100644 index 0000000..26e0f8d
> --- /dev/null
> +++ b/block/partitions/cmdline.h
> @@ -0,0 +1,2 @@
> +
> +int cmdline_partition(struct parsed_partitions *state);
> --
> 1.8.1.5

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-07-27 13:56 [PATCH] block: support embedded device command line partition Caizhiyong
  2013-07-30 23:13 ` Andrew Morton
@ 2013-07-31 13:25 ` Karel Zak
  2013-08-01  1:46   ` Caizhiyong
  1 sibling, 1 reply; 15+ messages in thread
From: Karel Zak @ 2013-07-31 13:25 UTC (permalink / raw)
  To: Caizhiyong; +Cc: Andrew Morton, linux-kernel, Wanglin (Albert), Quyaxin

On Sat, Jul 27, 2013 at 01:56:24PM +0000, Caizhiyong wrote:
> +static int parse_partitions(struct parsed_partitions *state,
> +			    struct cmdline_parts *parts)
> +{
> +	int slot;
> +	uint64_t from = 0;
> +	uint64_t disk_size;
> +	char buf[BDEVNAME_SIZE];
> +	struct cmdline_subpart *subpart;
> +
> +	bdevname(state->bdev, buf);
> +
> +	while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
> +		parts = parts->next_parts;
> +
> +	if (!parts)
> +		return 0;
> +
> +	disk_size = (uint64_t) get_capacity(state->bdev->bd_disk) << 9;
> +
> +	for (slot = 1, subpart = parts->subpart;
> +	     subpart && slot < state->limit;
> +	     subpart = subpart->next_subpart, slot++) {
> +
> +		unsigned label_max;
> +		struct partition_meta_info *info;
> +
> +		if (subpart->from == OFFSET_CONTINUOUS)
> +			subpart->from = from;
> +		else
> +			from = subpart->from;
> +
> +		if (from >= disk_size)
> +			break;
> +
> +		if (subpart->size > (disk_size - from))
> +			subpart->size = disk_size - from;
> +
> +		from += subpart->size;
> +
> +		put_partition(state, slot, le64_to_cpu(subpart->from >> 9),
> +			      le64_to_cpu(subpart->size >> 9));

 Why le64_to_cpu()?
 
 I guess that memparse() does not return explicitly LE and it also
 seems that your code  on another places uses ->size and ->from
 without any extra care.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH] block: support embedded device command line partition
  2013-07-31 13:25 ` Karel Zak
@ 2013-08-01  1:46   ` Caizhiyong
  0 siblings, 0 replies; 15+ messages in thread
From: Caizhiyong @ 2013-08-01  1:46 UTC (permalink / raw)
  To: Karel Zak; +Cc: Andrew Morton, linux-kernel, Wanglin (Albert), Quyaxin

> From: Karel Zak [mailto:kzak@redhat.com]
> Sent: Wednesday, July 31, 2013 9:25 PM
> To: Caizhiyong
> Cc: Andrew Morton; linux-kernel@vger.kernel.org; Wanglin (Albert); Quyaxin
> Subject: Re: [PATCH] block: support embedded device command line partition
> 
> On Sat, Jul 27, 2013 at 01:56:24PM +0000, Caizhiyong wrote:
> > +static int parse_partitions(struct parsed_partitions *state,
> > +			    struct cmdline_parts *parts)
> > +{
> > +	int slot;
> > +	uint64_t from = 0;
> > +	uint64_t disk_size;
> > +	char buf[BDEVNAME_SIZE];
> > +	struct cmdline_subpart *subpart;
> > +
> > +	bdevname(state->bdev, buf);
> > +
> > +	while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
> > +		parts = parts->next_parts;
> > +
> > +	if (!parts)
> > +		return 0;
> > +
> > +	disk_size = (uint64_t) get_capacity(state->bdev->bd_disk) << 9;
> > +
> > +	for (slot = 1, subpart = parts->subpart;
> > +	     subpart && slot < state->limit;
> > +	     subpart = subpart->next_subpart, slot++) {
> > +
> > +		unsigned label_max;
> > +		struct partition_meta_info *info;
> > +
> > +		if (subpart->from == OFFSET_CONTINUOUS)
> > +			subpart->from = from;
> > +		else
> > +			from = subpart->from;
> > +
> > +		if (from >= disk_size)
> > +			break;
> > +
> > +		if (subpart->size > (disk_size - from))
> > +			subpart->size = disk_size - from;
> > +
> > +		from += subpart->size;
> > +
> > +		put_partition(state, slot, le64_to_cpu(subpart->from >> 9),
> > +			      le64_to_cpu(subpart->size >> 9));
> 
>  Why le64_to_cpu()?
> 
>  I guess that memparse() does not return explicitly LE and it also
>  seems that your code  on another places uses ->size and ->from
>  without any extra care.

Right. I will remove.

> 
>     Karel
> 
> --
>  Karel Zak  <kzak@redhat.com>
>  http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH] block: support embedded device command line partition
  2013-09-17 11:15 ` Linus Walleij
@ 2013-09-17 13:08   ` Caizhiyong
  0 siblings, 0 replies; 15+ messages in thread
From: Caizhiyong @ 2013-09-17 13:08 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert),
	Quyaxin, Ulf Hansson

 
> I saw this patch appear in kernel v3.12-rc1, and it's nice since it's exactly
> what we need. So needed that we proposed it in 2010:
> http://marc.info/?l=linux-kernel&m=127425650923757&w=2
> http://marc.info/?l=linux-kernel&m=127599718024364&w=2
> 
> Is this patch inspired by Ulfs patch? (I can see the code is different,
> but the cmdline argument is the same for example.) Some credit
> could have been proper in that case.

I have not searched other patch, English reading/writing is not an easy thing for me.

Thank Ulf Hansson. He was the first one who thought of this method.

> 
> Just asking: sometimes wheels do get reinvented.
> 
> Yours,
> Linus Walleij


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-03  9:57 Caizhiyong
  2013-08-05 22:22 ` Andrew Morton
  2013-08-15 15:52 ` Stephen Warren
@ 2013-09-17 11:15 ` Linus Walleij
  2013-09-17 13:08   ` Caizhiyong
  2 siblings, 1 reply; 15+ messages in thread
From: Linus Walleij @ 2013-09-17 11:15 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert),
	Quyaxin, Ulf Hansson

On Sat, Aug 3, 2013 at 11:57 AM, Caizhiyong <caizhiyong@huawei.com> wrote:

> From: Cai Zhiyong <caizhiyong@huawei.com>
>
> 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.
>
> This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
> About the partition verbose reference "Documentation/block/cmdline-partition.txt"
>
> Signed-off-by: Cai Zhiyong <caizhiyong@huawei.com>

I saw this patch appear in kernel v3.12-rc1, and it's nice since it's exactly
what we need. So needed that we proposed it in 2010:
http://marc.info/?l=linux-kernel&m=127425650923757&w=2
http://marc.info/?l=linux-kernel&m=127599718024364&w=2

Is this patch inspired by Ulfs patch? (I can see the code is different,
but the cmdline argument is the same for example.) Some credit
could have been proper in that case.

Just asking: sometimes wheels do get reinvented.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-19  8:36       ` Caizhiyong
@ 2013-08-19 16:05         ` Stephen Warren
  0 siblings, 0 replies; 15+ messages in thread
From: Stephen Warren @ 2013-08-19 16:05 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

On 08/19/2013 02:36 AM, Caizhiyong wrote:
>> On 08/15/2013 08:54 PM, Caizhiyong wrote:
>>>>> +blkdevparts=<blkdev-def>[;<blkdev-def>]
>>>>> +  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
>>>>> +    <partdef> := <size>[@<offset>](part-name)
>>>>> +
>>>>> +<blkdev-id>
>>>>> +    block device disk name, embedded device used fixed block device,
>>>>> +    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
>>>>
>>>> The device-name isn't always fixed.
>>>>
>>>> For example, what if there are multiple SDHCI controllers, one hosting a
>>>> fixed eMMC device and the other an SD card? It's quite typical for the
>>>> eMMC's device name (which is likely what should be affected by this
>>>> feature) to be mmcblk0 when no SD card is present, yet be mmcblk1 when
>>>> an SD card is present. Is there a more precise/stable way to define
>>>> which device the command-line option applies to?
>>>
>>> Yes. Fixed is for single controller.
>>> For multiple controllers, currently, there is not a simple way.
>>> I tend to do something in the eMMC driver, such as initialize order,
>>> but I have not tried.
>>
>> There have been proposals before to try and create a fixed naming for
>> the controllers (or rather the block devices they generate...) but
>> they've been rejected. I don't think we should rely on being able to do
>> that.
>>
>>>>> +
>>>>> +<offset>
>>>>> +    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.
>>>>
>>>> Do partitions usually have a PARTNAME attribute when probed through
>>>> normal mechanisms like MBR? If so, I guess this is fine.
>>>>
>>>> Perhaps we can just use , as the delimiter for all fields, rather than
>>>> special-casing part-name to use (), so:
>>>>
>>>> size,offset,partname,size,offset,partname,...
>>>>
>>>> The partname field could easily be empty if not needed.
>>>
>>> If no need partname, your bootargs are mmcblk0:1G,1G,1G,...
>>
>> Well, you always need the offset too. I don't think there's any harm in
>> forcing all fields to be specified in all cases; it makes the whole
>> system much more regular and less error-prone.
>>
>> Alternatively, use a different separator between fields for a given
>> partition, and between partitions, e.g.:
>>
>> size,offset,partname;size,offset,partname
>>
>> That way, you know that if you see a ; you're looking at a new
>> partition, and hence the partname field need not always be specified.
>> Although, if you want to specify a partname but not an offset you'd
>> still need empty fields, so just requiring all fields to always be
>> present still seems safest to me.
> 
> I just follow MTD cmdline partition format.(reference drivers/mtd/cmdlinepart.c)

Ah OK, consistency with an existing format used for similar purposes
probably does override any other concerns.

> There are many pitfalls in using this partition format, the designer is more
> consideration its ease of use, rather than safe.
> There is an other conversation: https://lkml.org/lkml/2013/8/3/16


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH] block: support embedded device command line partition
  2013-08-16 16:02     ` Stephen Warren
@ 2013-08-19  8:36       ` Caizhiyong
  2013-08-19 16:05         ` Stephen Warren
  0 siblings, 1 reply; 15+ messages in thread
From: Caizhiyong @ 2013-08-19  8:36 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

> On 08/15/2013 08:54 PM, Caizhiyong wrote:
> >>> +blkdevparts=<blkdev-def>[;<blkdev-def>]
> >>> +  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
> >>> +    <partdef> := <size>[@<offset>](part-name)
> >>> +
> >>> +<blkdev-id>
> >>> +    block device disk name, embedded device used fixed block device,
> >>> +    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
> >>
> >> The device-name isn't always fixed.
> >>
> >> For example, what if there are multiple SDHCI controllers, one hosting a
> >> fixed eMMC device and the other an SD card? It's quite typical for the
> >> eMMC's device name (which is likely what should be affected by this
> >> feature) to be mmcblk0 when no SD card is present, yet be mmcblk1 when
> >> an SD card is present. Is there a more precise/stable way to define
> >> which device the command-line option applies to?
> >
> > Yes. Fixed is for single controller.
> > For multiple controllers, currently, there is not a simple way.
> > I tend to do something in the eMMC driver, such as initialize order,
> > but I have not tried.
> 
> There have been proposals before to try and create a fixed naming for
> the controllers (or rather the block devices they generate...) but
> they've been rejected. I don't think we should rely on being able to do
> that.
> 
> >>> +
> >>> +<offset>
> >>> +    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.
> >>
> >> Do partitions usually have a PARTNAME attribute when probed through
> >> normal mechanisms like MBR? If so, I guess this is fine.
> >>
> >> Perhaps we can just use , as the delimiter for all fields, rather than
> >> special-casing part-name to use (), so:
> >>
> >> size,offset,partname,size,offset,partname,...
> >>
> >> The partname field could easily be empty if not needed.
> >
> > If no need partname, your bootargs are mmcblk0:1G,1G,1G,...
> 
> Well, you always need the offset too. I don't think there's any harm in
> forcing all fields to be specified in all cases; it makes the whole
> system much more regular and less error-prone.
> 
> Alternatively, use a different separator between fields for a given
> partition, and between partitions, e.g.:
> 
> size,offset,partname;size,offset,partname
> 
> That way, you know that if you see a ; you're looking at a new
> partition, and hence the partname field need not always be specified.
> Although, if you want to specify a partname but not an offset you'd
> still need empty fields, so just requiring all fields to always be
> present still seems safest to me.

I just follow MTD cmdline partition format.(reference drivers/mtd/cmdlinepart.c)
There are many pitfalls in using this partition format, the designer is more
consideration its ease of use, rather than safe.
There is an other conversation: https://lkml.org/lkml/2013/8/3/16


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-16  2:54   ` Caizhiyong
@ 2013-08-16 16:02     ` Stephen Warren
  2013-08-19  8:36       ` Caizhiyong
  0 siblings, 1 reply; 15+ messages in thread
From: Stephen Warren @ 2013-08-16 16:02 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

On 08/15/2013 08:54 PM, Caizhiyong wrote:
>>> +blkdevparts=<blkdev-def>[;<blkdev-def>]
>>> +  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
>>> +    <partdef> := <size>[@<offset>](part-name)
>>> +
>>> +<blkdev-id>
>>> +    block device disk name, embedded device used fixed block device,
>>> +    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
>>
>> The device-name isn't always fixed.
>>
>> For example, what if there are multiple SDHCI controllers, one hosting a
>> fixed eMMC device and the other an SD card? It's quite typical for the
>> eMMC's device name (which is likely what should be affected by this
>> feature) to be mmcblk0 when no SD card is present, yet be mmcblk1 when
>> an SD card is present. Is there a more precise/stable way to define
>> which device the command-line option applies to?
>   
> Yes. Fixed is for single controller.
> For multiple controllers, currently, there is not a simple way.
> I tend to do something in the eMMC driver, such as initialize order,
> but I have not tried.

There have been proposals before to try and create a fixed naming for
the controllers (or rather the block devices they generate...) but
they've been rejected. I don't think we should rely on being able to do
that.

>>> +
>>> +<offset>
>>> +    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.
>>
>> Do partitions usually have a PARTNAME attribute when probed through
>> normal mechanisms like MBR? If so, I guess this is fine.
>>
>> Perhaps we can just use , as the delimiter for all fields, rather than
>> special-casing part-name to use (), so:
>>
>> size,offset,partname,size,offset,partname,...
>>
>> The partname field could easily be empty if not needed.
> 
> If no need partname, your bootargs are mmcblk0:1G,1G,1G,...

Well, you always need the offset too. I don't think there's any harm in
forcing all fields to be specified in all cases; it makes the whole
system much more regular and less error-prone.

Alternatively, use a different separator between fields for a given
partition, and between partitions, e.g.:

size,offset,partname;size,offset,partname

That way, you know that if you see a ; you're looking at a new
partition, and hence the partname field need not always be specified.
Although, if you want to specify a partname but not an offset you'd
still need empty fields, so just requiring all fields to always be
present still seems safest to me.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH] block: support embedded device command line partition
  2013-08-15 15:52 ` Stephen Warren
@ 2013-08-16  2:54   ` Caizhiyong
  2013-08-16 16:02     ` Stephen Warren
  0 siblings, 1 reply; 15+ messages in thread
From: Caizhiyong @ 2013-08-16  2:54 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

> > +blkdevparts=<blkdev-def>[;<blkdev-def>]
> > +  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
> > +    <partdef> := <size>[@<offset>](part-name)
> > +
> > +<blkdev-id>
> > +    block device disk name, embedded device used fixed block device,
> > +    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
> 
> The device-name isn't always fixed.
> 
> For example, what if there are multiple SDHCI controllers, one hosting a
> fixed eMMC device and the other an SD card? It's quite typical for the
> eMMC's device name (which is likely what should be affected by this
> feature) to be mmcblk0 when no SD card is present, yet be mmcblk1 when
> an SD card is present. Is there a more precise/stable way to define
> which device the command-line option applies to?
  
Yes. Fixed is for single controller.
For multiple controllers, currently, there is not a simple way.
I tend to do something in the eMMC driver, such as initialize order,
but I have not tried.

> 
> For the root= command-line option, we use UUID= or PARTUUID= to work
> around this issue, but that won't work for naming the whole device.
> 
> What about using the MMIO address of the controller hosting the device,
> or something like that?
> 

  MMIO may be not a good idea, it is not intuitive. 

> > +<size>
> > +    partition size, in bytes, such as: 512, 1m, 1G.
> 
> s/m/M/?
> 
> I assume M/G are MiB/GiB?
> 
> Does it make sense to allow specifying the sizes in units of
> sectors/blocks? If so, which specific block/sector size in the case of
> things like NAND flash which IIRC have multiple types/levels of sectors;
> perhaps this is a bad idea. I guess we could easily add this feature
> later by introducing a new suffix, so no need to solve the issue now.
> 
> > +
> > +<offset>
> > +    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.
> 
> Do partitions usually have a PARTNAME attribute when probed through
> normal mechanisms like MBR? If so, I guess this is fine.
> 
> Perhaps we can just use , as the delimiter for all fields, rather than
> special-casing part-name to use (), so:
> 
> size,offset,partname,size,offset,partname,...
> 
> The partname field could easily be empty if not needed.
> 

If no need partname, your bootargs are mmcblk0:1G,1G,1G,...
 
> > +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)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-03  9:57 Caizhiyong
  2013-08-05 22:22 ` Andrew Morton
@ 2013-08-15 15:52 ` Stephen Warren
  2013-08-16  2:54   ` Caizhiyong
  2013-09-17 11:15 ` Linus Walleij
  2 siblings, 1 reply; 15+ messages in thread
From: Stephen Warren @ 2013-08-15 15:52 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Andrew Morton, Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

On 08/03/2013 03:57 AM, Caizhiyong wrote:
> From: Cai Zhiyong <caizhiyong@huawei.com>
> 
> 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.
> 
> This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
> About the partition verbose reference "Documentation/block/cmdline-partition.txt"

Interesting. NVIDIA Tegra devices running our downstream kernels have a
"tegrapt" (for "Tegra Partition Table") command-line option for
basically the same purpose. While I'd personally prefer we move our eMMC
layout towards standardized GPT, the feature implemented by this patch
may well provide an easy migration/co-existence path instead, so could
be quite useful.

> diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt

> +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=<blkdev-def>[;<blkdev-def>]
> +  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
> +    <partdef> := <size>[@<offset>](part-name)
> +
> +<blkdev-id>
> +    block device disk name, embedded device used fixed block device,
> +    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.

The device-name isn't always fixed.

For example, what if there are multiple SDHCI controllers, one hosting a
fixed eMMC device and the other an SD card? It's quite typical for the
eMMC's device name (which is likely what should be affected by this
feature) to be mmcblk0 when no SD card is present, yet be mmcblk1 when
an SD card is present. Is there a more precise/stable way to define
which device the command-line option applies to?

For the root= command-line option, we use UUID= or PARTUUID= to work
around this issue, but that won't work for naming the whole device.

What about using the MMIO address of the controller hosting the device,
or something like that?

> +<size>
> +    partition size, in bytes, such as: 512, 1m, 1G.

s/m/M/?

I assume M/G are MiB/GiB?

Does it make sense to allow specifying the sizes in units of
sectors/blocks? If so, which specific block/sector size in the case of
things like NAND flash which IIRC have multiple types/levels of sectors;
perhaps this is a bad idea. I guess we could easily add this feature
later by introducing a new suffix, so no need to solve the issue now.

> +
> +<offset>
> +    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.

Do partitions usually have a PARTNAME attribute when probed through
normal mechanisms like MBR? If so, I guess this is fine.

Perhaps we can just use , as the delimiter for all fields, rather than
special-casing part-name to use (), so:

size,offset,partname,size,offset,partname,...

The partname field could easily be empty if not needed.

> +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)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-06 10:53   ` Caizhiyong
@ 2013-08-07  0:10     ` Andrew Morton
  0 siblings, 0 replies; 15+ messages in thread
From: Andrew Morton @ 2013-08-07  0:10 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Karel Zak, linux-kernel, Wanglin (Albert),
	Quyaxin, Jens Axboe, David Woodhouse, Marius Groeger

On Tue, 6 Aug 2013 10:53:01 +0000 Caizhiyong <caizhiyong@huawei.com> wrote:

> > -----Original Message-----
> > From: Andrew Morton [mailto:akpm@linux-foundation.org]
> > Sent: Tuesday, August 06, 2013 6:22 AM
> > To: Caizhiyong
> > Cc: Karel Zak; linux-kernel@vger.kernel.org; Wanglin (Albert); Quyaxin; Jens Axboe;
> > David Woodhouse; Marius Groeger
> > Subject: Re: [PATCH] block: support embedded device command line partition
> > 
> > On Sat, 3 Aug 2013 09:57:04 +0000 Caizhiyong <caizhiyong@huawei.com> wrote:
> > 
> > > From: Cai Zhiyong <caizhiyong@huawei.com>
> > >
> > > 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.
> > >
> > > This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
> > > About the partition verbose reference
> > "Documentation/block/cmdline-partition.txt"
> > >
> > 
> > Seems OK to me.
> > 
> > The obvious question is: can we consolidate this with
> > drivers/mtd/cmdlinepart.c in some fashion so the kernel doesn't have
> > two parsers which do the same thing?
> 
> I will move the parser to "lib/cmdline.c".
> 

block/cmdline.c is an appropriate place for block-subsystem library
code.

But simply moving the file doesn't achieve anything.  To prove that the
code is indeed library-style code, we should actually *use* it in some
client code.  Such as MTD!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH] block: support embedded device command line partition
  2013-08-05 22:22 ` Andrew Morton
@ 2013-08-06 10:53   ` Caizhiyong
  2013-08-07  0:10     ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Caizhiyong @ 2013-08-06 10:53 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Karel Zak, linux-kernel, Wanglin (Albert),
	Quyaxin, Jens Axboe, David Woodhouse, Marius Groeger

> -----Original Message-----
> From: Andrew Morton [mailto:akpm@linux-foundation.org]
> Sent: Tuesday, August 06, 2013 6:22 AM
> To: Caizhiyong
> Cc: Karel Zak; linux-kernel@vger.kernel.org; Wanglin (Albert); Quyaxin; Jens Axboe;
> David Woodhouse; Marius Groeger
> Subject: Re: [PATCH] block: support embedded device command line partition
> 
> On Sat, 3 Aug 2013 09:57:04 +0000 Caizhiyong <caizhiyong@huawei.com> wrote:
> 
> > From: Cai Zhiyong <caizhiyong@huawei.com>
> >
> > 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.
> >
> > This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
> > About the partition verbose reference
> "Documentation/block/cmdline-partition.txt"
> >
> 
> Seems OK to me.
> 
> The obvious question is: can we consolidate this with
> drivers/mtd/cmdlinepart.c in some fashion so the kernel doesn't have
> two parsers which do the same thing?

I will move the parser to "lib/cmdline.c".

Looking forward to your feedback.
Best regards,
Cai Zhiyong.

http://www.huawei.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] block: support embedded device command line partition
  2013-08-03  9:57 Caizhiyong
@ 2013-08-05 22:22 ` Andrew Morton
  2013-08-06 10:53   ` Caizhiyong
  2013-08-15 15:52 ` Stephen Warren
  2013-09-17 11:15 ` Linus Walleij
  2 siblings, 1 reply; 15+ messages in thread
From: Andrew Morton @ 2013-08-05 22:22 UTC (permalink / raw)
  To: Caizhiyong
  Cc: Karel Zak, linux-kernel, Wanglin (Albert),
	Quyaxin, Jens Axboe, David Woodhouse, Marius Groeger

On Sat, 3 Aug 2013 09:57:04 +0000 Caizhiyong <caizhiyong@huawei.com> wrote:

> From: Cai Zhiyong <caizhiyong@huawei.com>
> 
> 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.
> 
> This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
> About the partition verbose reference "Documentation/block/cmdline-partition.txt"
> 

Seems OK to me.

The obvious question is: can we consolidate this with
drivers/mtd/cmdlinepart.c in some fashion so the kernel doesn't have
two parsers which do the same thing?


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] block: support embedded device command line partition
@ 2013-08-03  9:57 Caizhiyong
  2013-08-05 22:22 ` Andrew Morton
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Caizhiyong @ 2013-08-03  9:57 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Karel Zak, linux-kernel, Wanglin (Albert), Quyaxin

From: Cai Zhiyong <caizhiyong@huawei.com>

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.

This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
About the partition verbose reference "Documentation/block/cmdline-partition.txt"

Signed-off-by: Cai Zhiyong <caizhiyong@huawei.com>
---
 Documentation/block/cmdline-partition.txt |  40 ++++
 block/partitions/Kconfig                  |   6 +
 block/partitions/Makefile                 |   1 +
 block/partitions/check.c                  |   4 +
 block/partitions/cmdline.c                | 326 ++++++++++++++++++++++++++++++
 block/partitions/cmdline.h                |   2 +
 6 files changed, 379 insertions(+)
 create mode 100644 Documentation/block/cmdline-partition.txt
 create mode 100644 block/partitions/cmdline.c
 create mode 100644 block/partitions/cmdline.h

diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt
new file mode 100644
index 0000000..651863d
--- /dev/null
+++ b/Documentation/block/cmdline-partition.txt
@@ -0,0 +1,40 @@
+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=<blkdev-def>[;<blkdev-def>]
+  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
+    <partdef> := <size>[@<offset>](part-name)
+
+<blkdev-id>
+    block device disk name, embedded device used fixed block device,
+    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
+
+<size>
+    partition size, in bytes, such as: 512, 1m, 1G.
+
+<offset>
+    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:
+    '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/partitions/Kconfig b/block/partitions/Kconfig
index 4cebb2f..2ebf251 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -260,3 +260,9 @@ config SYSV68_PARTITION
 	  partition table format used by Motorola Delta machines (using
 	  sysv68).
 	  Otherwise, say N.
+
+config CMDLINE_PARTITION
+	bool "Command line partition support" if PARTITION_ADVANCED
+	help
+	  Say Y here if you would read the partitions table from bootargs.
+	  The format for the command line is just like mtdparts.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index 2be4d7b..4e9d584 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_KARMA_PARTITION) += karma.o
 obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
diff --git a/block/partitions/check.c b/block/partitions/check.c
index 19ba207..9ac1df7 100644
--- a/block/partitions/check.c
+++ b/block/partitions/check.c
@@ -34,6 +34,7 @@
 #include "efi.h"
 #include "karma.h"
 #include "sysv68.h"
+#include "cmdline.h"
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
@@ -65,6 +66,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
 	adfspart_check_ADFS,
 #endif
 
+#ifdef CONFIG_CMDLINE_PARTITION
+	cmdline_partition,
+#endif
 #ifdef CONFIG_EFI_PARTITION
 	efi_partition,		/* this must come before msdos */
 #endif
diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c
new file mode 100644
index 0000000..dc69483
--- /dev/null
+++ b/block/partitions/cmdline.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2013 HUAWEI
+ * Author: Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ * 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.
+ *
+ * This code reference MTD partition, source "drivers/mtd/cmdlinepart.c"
+ * The format for the command line is just like mtdparts.
+ *
+ * Verbose config please reference "Documentation/block/cmdline-partition.txt"
+ *
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+
+#include "check.h"
+#include "cmdline.h"
+
+struct cmdline_subpart {
+	char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
+	sector_t from;
+	sector_t size;
+	struct cmdline_subpart *next_subpart;
+};
+
+struct cmdline_parts {
+	char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
+	struct cmdline_subpart *subpart;
+	struct cmdline_parts *next_parts;
+};
+
+static char *cmdline_string;
+static struct cmdline_parts *cmdline_parts;
+
+static int parse_subpart(struct cmdline_subpart **subpart, char *cmdline)
+{
+	int ret = 0;
+	struct cmdline_subpart *new_subpart;
+
+	*subpart = NULL;
+
+	new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
+	if (!new_subpart)
+		return -ENOMEM;
+
+	if (*cmdline == '-') {
+		new_subpart->size = (sector_t)(~0ULL);
+		cmdline++;
+	} else {
+		new_subpart->size = (sector_t)memparse(cmdline, &cmdline);
+		if (new_subpart->size < (sector_t)PAGE_SIZE) {
+			pr_warn("cmdline partition size is invalid.");
+			ret = -EINVAL;
+			goto fail;
+		}
+	}
+
+	if (*cmdline == '@') {
+		cmdline++;
+		new_subpart->from = (sector_t)memparse(cmdline, &cmdline);
+	} else {
+		new_subpart->from = (sector_t)(~0ULL);
+	}
+
+	if (*cmdline == '(') {
+		int length;
+		char *next = strchr(++cmdline, ')');
+
+		if (!next) {
+			pr_warn("cmdline partition format is invalid.");
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		length = min_t(int, next - cmdline,
+			       sizeof(new_subpart->name) - 1);
+		strncpy(new_subpart->name, cmdline, length);
+		new_subpart->name[length] = '\0';
+
+		cmdline = ++next;
+	} else
+		new_subpart->name[0] = '\0';
+
+	*subpart = new_subpart;
+	return 0;
+fail:
+	kfree(new_subpart);
+	return ret;
+}
+
+static void free_subpart(struct cmdline_parts *parts)
+{
+	struct cmdline_subpart *subpart;
+
+	while (parts->subpart) {
+		subpart = parts->subpart;
+		parts->subpart = subpart->next_subpart;
+		kfree(subpart);
+	}
+}
+
+static void free_parts(struct cmdline_parts **parts)
+{
+	struct cmdline_parts *next_parts;
+
+	while (*parts) {
+		next_parts = (*parts)->next_parts;
+		free_subpart(*parts);
+		kfree(*parts);
+		*parts = next_parts;
+	}
+}
+
+static int parse_parts(struct cmdline_parts **parts, const char *cmdline)
+{
+	int ret = -EINVAL;
+	char *next;
+	int length;
+	struct cmdline_subpart **next_subpart;
+	struct cmdline_parts *newparts;
+	char buf[BDEVNAME_SIZE + 32 + 4];
+
+	*parts = NULL;
+
+	newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
+	if (!newparts)
+		return -ENOMEM;
+
+	next = strchr(cmdline, ':');
+	if (!next) {
+		pr_warn("cmdline partition has not block device.");
+		goto fail;
+	}
+
+	length = min_t(int, next - cmdline, sizeof(newparts->name) - 1);
+	strncpy(newparts->name, cmdline, length);
+	newparts->name[length] = '\0';
+
+	next_subpart = &newparts->subpart;
+
+	while (next && *(++next)) {
+		cmdline = next;
+		next = strchr(cmdline, ',');
+
+		length = (!next) ? (sizeof(buf) - 1) :
+			min_t(int, next - cmdline, sizeof(buf) - 1);
+
+		strncpy(buf, cmdline, length);
+		buf[length] = '\0';
+
+		ret = parse_subpart(next_subpart, buf);
+		if (ret)
+			goto fail;
+
+		next_subpart = &(*next_subpart)->next_subpart;
+	}
+
+	if (!newparts->subpart) {
+		pr_warn("cmdline partition has not valid partition.");
+		goto fail;
+	}
+
+	*parts = newparts;
+
+	return 0;
+fail:
+	free_subpart(newparts);
+	kfree(newparts);
+	return ret;
+}
+
+static int parse_cmdline(struct cmdline_parts **parts, const char *cmdline)
+{
+	int ret;
+	char *buf;
+	char *pbuf;
+	char *next;
+	struct cmdline_parts **next_parts;
+
+	*parts = NULL;
+
+	next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	next_parts = parts;
+
+	while (next && *pbuf) {
+		next = strchr(pbuf, ';');
+		if (next)
+			*next = '\0';
+
+		ret = parse_parts(next_parts, pbuf);
+		if (ret)
+			goto fail;
+
+		if (next)
+			pbuf = ++next;
+
+		next_parts = &(*next_parts)->next_parts;
+	}
+
+	if (!*parts) {
+		pr_warn("cmdline partition has not valid partition.");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = 0;
+done:
+	kfree(buf);
+	return ret;
+
+fail:
+	free_parts(parts);
+	goto done;
+}
+
+/*
+ * Purpose: allocate cmdline partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ */
+static int parse_partitions(struct parsed_partitions *state,
+			    struct cmdline_parts *parts)
+{
+	int slot;
+	sector_t from = 0;
+	sector_t disk_size;
+	char buf[BDEVNAME_SIZE];
+	struct cmdline_subpart *subpart;
+
+	bdevname(state->bdev, buf);
+
+	while (parts && strncmp(buf, parts->name, BDEVNAME_SIZE))
+		parts = parts->next_parts;
+
+	if (!parts)
+		return 0;
+
+	disk_size = get_capacity(state->bdev->bd_disk) << 9;
+
+	for (slot = 1, subpart = parts->subpart;
+	     subpart && slot < state->limit;
+	     subpart = subpart->next_subpart, slot++) {
+		int label_min;
+		struct partition_meta_info *info;
+		char tmp[sizeof(info->volname) + 4];
+
+		if (subpart->from == (sector_t)(~0ULL))
+			subpart->from = from;
+		else
+			from = subpart->from;
+
+		if (from >= disk_size)
+			break;
+
+		if (subpart->size > (disk_size - from))
+			subpart->size = disk_size - from;
+
+		from += subpart->size;
+
+		put_partition(state, slot, subpart->from >> 9,
+			      subpart->size >> 9);
+
+		info = &state->parts[slot].info;
+
+		label_min = min_t(int, sizeof(info->volname) - 1,
+				  sizeof(subpart->name));
+		strncpy(info->volname, subpart->name, label_min);
+		info->volname[label_min] = '\0';
+
+		snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
+		strlcat(state->pp_buf, tmp, PAGE_SIZE);
+
+		state->parts[slot].has_info = true;
+	}
+
+	strlcat(state->pp_buf, "\n", PAGE_SIZE);
+
+	return 1;
+}
+
+static int __init cmdline_parts_setup(char *s)
+{
+	cmdline_string = s;
+	return 1;
+}
+__setup("blkdevparts=", cmdline_parts_setup);
+
+/*
+ * Purpose: allocate cmdline partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ */
+int cmdline_partition(struct parsed_partitions *state)
+{
+	if (cmdline_string) {
+		if (cmdline_parts)
+			free_parts(&cmdline_parts);
+
+		if (parse_cmdline(&cmdline_parts, cmdline_string))
+			goto fail;
+
+		cmdline_string = NULL;
+	}
+
+	if (!cmdline_parts)
+		return 0;
+
+	return parse_partitions(state, cmdline_parts);
+
+fail:
+	cmdline_string = NULL;
+	return -1;
+}
diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h
new file mode 100644
index 0000000..26e0f8d
--- /dev/null
+++ b/block/partitions/cmdline.h
@@ -0,0 +1,2 @@
+
+int cmdline_partition(struct parsed_partitions *state);
-- 
1.8.1.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2013-09-17 13:08 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-27 13:56 [PATCH] block: support embedded device command line partition Caizhiyong
2013-07-30 23:13 ` Andrew Morton
2013-07-31 13:25 ` Karel Zak
2013-08-01  1:46   ` Caizhiyong
2013-08-03  9:57 Caizhiyong
2013-08-05 22:22 ` Andrew Morton
2013-08-06 10:53   ` Caizhiyong
2013-08-07  0:10     ` Andrew Morton
2013-08-15 15:52 ` Stephen Warren
2013-08-16  2:54   ` Caizhiyong
2013-08-16 16:02     ` Stephen Warren
2013-08-19  8:36       ` Caizhiyong
2013-08-19 16:05         ` Stephen Warren
2013-09-17 11:15 ` Linus Walleij
2013-09-17 13:08   ` Caizhiyong

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.