public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH] cmd: add clone command
@ 2020-06-27  3:15 John Chau
  2020-06-29 15:54 ` Tom Rini
  0 siblings, 1 reply; 5+ messages in thread
From: John Chau @ 2020-06-27  3:15 UTC (permalink / raw)
  To: u-boot

From: John Chau <john@harmon.hk>

This patch adds a feature for block device cloning similar to dd
command, this should be useful for boot-strapping a device where
usb gadget or networking is not available. For instance one can
clone a factory image into a blank emmc from an external sd card.

Signed-off-by: John Chau <john@harmon.hk>
---
 cmd/Kconfig  |   9 +++++
 cmd/Makefile |   1 +
 cmd/clone.c  | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 cmd/clone.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6403bc45a5..44f96dedcd 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1067,6 +1067,15 @@ config CMD_MMC_SWRITE
 	  Enable support for the "mmc swrite" command to write Android sparse
 	  images to eMMC.
 
+config CMD_CLONE
+	bool "clone"
+	depends on BLK
+	select CLONE
+	help
+	  Enable storage cloning over block devices, useful for 
+	  initial flashing by external block device without network
+	  or usb gadget support.
+	  
 config CMD_MTD
 	bool "mtd"
 	depends on MTD
diff --git a/cmd/Makefile b/cmd/Makefile
index f1dd513a4b..02663a1c73 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_MP) += mp.o
 obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
+obj-$(CONFIG_CMD_CLONE) += clone.o
 ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
 obj-y += legacy-mtd-utils.o
 endif
diff --git a/cmd/clone.c b/cmd/clone.c
new file mode 100644
index 0000000000..ee36c7698c
--- /dev/null
+++ b/cmd/clone.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 John Chau <john@harmon.hk>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <blk.h>
+#include <vsprintf.h>
+
+//FIXME: we assume blk size of both devices can be divided by 1M, which should be normal
+#define BUFSIZE (1 * 1024 * 1024)
+static int do_clone(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
+	int srcdev, destdev;
+	struct blk_desc *srcdesc, *destdesc;
+	int srcbz, destbz, ret;
+	char *unit, *buf;
+	unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
+	unsigned long timer;
+	
+	if (argc < 6) {
+		return CMD_RET_USAGE;
+	}
+	printf("\n");
+	srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
+	destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
+	if (srcdev < 0) {
+		printf("Unable to open source device\n");
+		return 1;
+	} else if (destdev < 0) {
+		printf("Unable to open destination device\n");
+		return 1;
+	}
+	requested = simple_strtoul(argv[5], &unit, 10);
+	srcbz = srcdesc->blksz;
+	destbz = destdesc->blksz;
+	if (requested == 0) {
+		unsigned long a = srcdesc->lba * srcdesc->blksz;
+		unsigned long b = destdesc->lba * destdesc->blksz;
+		if (a > b) requested = a;
+		else requested = b;
+	} else {
+		switch (unit[0]) {
+		case 'g':
+		case 'G':
+			requested *= 1024;
+		case 'm':
+		case 'M':
+			requested *= 1024;
+		case 'k':
+		case 'K':
+			requested *= 1024;
+			break;	
+		}
+	}
+	wrcnt = 0;
+	rdcnt = 0;
+	buf = (char*)malloc(BUFSIZE);
+	srcblk = 0;
+	destblk = 0;
+	timer = get_timer(0);
+	while (wrcnt < requested) {
+		unsigned long toRead = BUFSIZE / srcbz;
+		unsigned long offset = 0;
+read:
+		ret = blk_dread(srcdesc, srcblk, toRead, buf + offset);
+		if (ret < 0) {
+			printf("Src read error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		rdcnt += ret * srcbz;
+		srcblk += ret;
+		if (ret < toRead) {
+			toRead -= ret;
+			offset += ret * srcbz;
+			goto read;
+		}
+		unsigned long toWrite = BUFSIZE / destbz;
+		offset = 0;
+write:
+		ret = blk_dwrite(destdesc, destblk, toWrite, buf + offset);
+		if (ret < 0) {
+			printf("Dest write error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		wrcnt += ret * destbz;
+		destblk += ret;
+		if (ret < toWrite) {
+			toWrite -= ret;
+			offset += ret * destbz;
+			goto write;
+		}
+	}
+	
+exit:
+	timer = get_timer(timer);
+	timer = 1000 * timer / CONFIG_SYS_HZ;
+	printf("%ld read \n", rdcnt);
+	printf("%ld written\n", wrcnt);
+	printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
+	free(buf);
+	return 0;
+}
+
+U_BOOT_CMD(
+	clone, 6, 1, do_clone,
+	"simple storage cloning",
+	"<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
+	"clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
+);
-- 
2.25.1

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

* [PATCH] cmd: add clone command
  2020-06-27  3:15 [PATCH] cmd: add clone command John Chau
@ 2020-06-29 15:54 ` Tom Rini
  2020-07-02  3:38   ` [PATCH v2] " John Chau
  2020-07-02  4:01   ` [PATCH v3] " John Chau
  0 siblings, 2 replies; 5+ messages in thread
From: Tom Rini @ 2020-06-29 15:54 UTC (permalink / raw)
  To: u-boot

On Sat, Jun 27, 2020 at 11:15:49AM +0800, John Chau wrote:

> From: John Chau <john@harmon.hk>
> 
> This patch adds a feature for block device cloning similar to dd
> command, this should be useful for boot-strapping a device where
> usb gadget or networking is not available. For instance one can
> clone a factory image into a blank emmc from an external sd card.
> 
> Signed-off-by: John Chau <john@harmon.hk>

In general, checkpatch.pl complains a lot and those need to be fixed.

[snip]
> +config CMD_CLONE
> +	bool "clone"
> +	depends on BLK
> +	select CLONE

There's no "config CLONE" so we don't need this line.

[snip]
> +//FIXME: we assume blk size of both devices can be divided by 1M, which should be normal
> +#define BUFSIZE (1 * 1024 * 1024)

Can we do some run-time checks of the block sizes of each device and
confirm this assumption and fail if it's not true?

Finally, we should also enable this on sandbox so that it's build-tested
and put through coverity.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200629/febaeda1/attachment.sig>

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

* [PATCH v2] cmd: add clone command
  2020-06-29 15:54 ` Tom Rini
@ 2020-07-02  3:38   ` John Chau
  2020-07-02  4:01   ` [PATCH v3] " John Chau
  1 sibling, 0 replies; 5+ messages in thread
From: John Chau @ 2020-07-02  3:38 UTC (permalink / raw)
  To: u-boot

From: John Chau <john@harmon.hk>

This patch adds a feature for block device cloning similar to dd
command, this should be useful for boot-strapping a device where
usb gadget or networking is not available. For instance one can
clone a factory image into a blank emmc from an external sd card.

Signed-off-by: John Chau <john@harmon.hk>
---
Changes for v2:
	- Coding styles cleanup
	- removed useless "select CLONE" line from cmd/Kconfig
	- added buffer size check against block size of both devices
	- enabled this by default on sandbox in arch/Kconfig
	 
 arch/Kconfig |   1 +
 cmd/Kconfig  |   8 ++++
 cmd/Makefile |   1 +
 cmd/clone.c  | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 135 insertions(+)
 create mode 100644 cmd/clone.c

diff --git a/arch/Kconfig b/arch/Kconfig
index ae9c93ed7b..4d7415d426 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -136,6 +136,7 @@ config SANDBOX
 	imply ACPI_PMC
 	imply ACPI_PMC_SANDBOX
 	imply CMD_PMC
+	imply CMD_CLONE
 
 config SH
 	bool "SuperH architecture"
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6403bc45a5..1e95de249f 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1067,6 +1067,14 @@ config CMD_MMC_SWRITE
 	  Enable support for the "mmc swrite" command to write Android sparse
 	  images to eMMC.
 
+config CMD_CLONE
+	bool "clone"
+	depends on BLK
+	help
+	  Enable storage cloning over block devices, useful for
+	  initial flashing by external block device without network
+	  or usb support.
+
 config CMD_MTD
 	bool "mtd"
 	depends on MTD
diff --git a/cmd/Makefile b/cmd/Makefile
index f1dd513a4b..02663a1c73 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_MP) += mp.o
 obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
+obj-$(CONFIG_CMD_CLONE) += clone.o
 ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
 obj-y += legacy-mtd-utils.o
 endif
diff --git a/cmd/clone.c b/cmd/clone.c
new file mode 100644
index 0000000000..e3aba1b796
--- /dev/null
+++ b/cmd/clone.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 John Chau <john@harmon.hk>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <blk.h>
+#include <vsprintf.h>
+
+#define BUFSIZE (1 * 1024 * 1024)
+static int do_clone(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int srcdev, destdev;
+	const struct blk_desc *srcdesc, *destdesc;
+	int srcbz, destbz, ret;
+	char *unit, *buf;
+	unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
+	unsigned long timer;
+	const unsigned long buffersize = 1024 * 1024;
+
+	if (argc < 6)
+		return CMD_RET_USAGE;
+
+	srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
+	destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
+	if (srcdev < 0) {
+		printf("Unable to open source device\n");
+		return 1;
+	} else if (destdev < 0) {
+		printf("Unable to open destination device\n");
+		return 1;
+	}
+	requested = simple_strtoul(argv[5], &unit, 10);
+	srcbz = srcdesc->blksz;
+	destbz = destdesc->blksz;
+
+	if ((srcbz * (buffersize / srcbz) == buffersize) &&
+	    (destbz * (buffersize / destbz) == buffersize)) {
+		printf("failed: cannot match device block sizes\n");
+		return 1;
+	}
+	if (requested == 0) {
+		unsigned long a = srcdesc->lba * srcdesc->blksz;
+		unsigned long b = destdesc->lba * destdesc->blksz;
+
+		if (a > b)
+			requested = a;
+		else
+			requested = b;
+	} else {
+		switch (unit[0]) {
+		case 'g':
+		case 'G':
+			requested *= 1024;
+		case 'm':
+		case 'M':
+			requested *= 1024;
+		case 'k':
+		case 'K':
+			requested *= 1024;
+			break;
+		}
+	}
+	printf("Copying %ld bytes from %s:%s to %s:%s\n",
+	       requested, argv[1], argv[2], argv[3], argv[4]);
+	wrcnt = 0;
+	rdcnt = 0;
+	buf = (char *)malloc(BUFSIZE);
+	srcblk = 0;
+	destblk = 0;
+	timer = get_timer(0);
+	while (wrcnt < requested) {
+		unsigned long toread = BUFSIZE / srcbz;
+		unsigned long towrite = BUFSIZE / destbz;
+		unsigned long offset = 0;
+
+read:
+		ret = blk_dread(srcdesc, srcblk, toread, buf + offset);
+		if (ret < 0) {
+			printf("Src read error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		rdcnt += ret * srcbz;
+		srcblk += ret;
+		if (ret < toread) {
+			toread -= ret;
+			offset += ret * srcbz;
+			goto read;
+		}
+		offset = 0;
+write:
+		ret = blk_dwrite(destdesc, destblk, towrite, buf + offset);
+		if (ret < 0) {
+			printf("Dest write error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		wrcnt += ret * destbz;
+		destblk += ret;
+		if (ret < towrite) {
+			towrite -= ret;
+			offset += ret * destbz;
+			goto write;
+		}
+	}
+
+exit:
+	timer = get_timer(timer);
+	timer = 1000 * timer / CONFIG_SYS_HZ;
+	printf("%ld read\n", rdcnt);
+	printf("%ld written\n", wrcnt);
+	printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
+	free(buf);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	clone, 6, 1, do_clone,
+	"simple storage cloning",
+	"<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
+	"clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
+);
-- 
2.25.1

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

* [PATCH v3] cmd: add clone command
  2020-06-29 15:54 ` Tom Rini
  2020-07-02  3:38   ` [PATCH v2] " John Chau
@ 2020-07-02  4:01   ` John Chau
  2020-08-05 20:27     ` Tom Rini
  1 sibling, 1 reply; 5+ messages in thread
From: John Chau @ 2020-07-02  4:01 UTC (permalink / raw)
  To: u-boot

From: John Chau <john@harmon.hk>

This patch adds a feature for block device cloning similar to dd
command, this should be useful for boot-strapping a device where
usb gadget or networking is not available. For instance one can
clone a factory image into a blank emmc from an external sd card.

Signed-off-by: John Chau <john@harmon.hk>
---
Changes for v2:
	- Coding styles cleanup
	- removed useless "select CLONE" line from cmd/Kconfig
	- added buffer size check against block size of both devices
	- enabled this by default on sandbox in arch/Kconfig
Changes for v3:
	- fixed buffer size check (condition inverted)

 arch/Kconfig |   1 +
 cmd/Kconfig  |   8 ++++
 cmd/Makefile |   1 +
 cmd/clone.c  | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 135 insertions(+)
 create mode 100644 cmd/clone.c

diff --git a/arch/Kconfig b/arch/Kconfig
index ae9c93ed7b..4d7415d426 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -136,6 +136,7 @@ config SANDBOX
 	imply ACPI_PMC
 	imply ACPI_PMC_SANDBOX
 	imply CMD_PMC
+	imply CMD_CLONE
 
 config SH
 	bool "SuperH architecture"
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6403bc45a5..1e95de249f 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1067,6 +1067,14 @@ config CMD_MMC_SWRITE
 	  Enable support for the "mmc swrite" command to write Android sparse
 	  images to eMMC.
 
+config CMD_CLONE
+	bool "clone"
+	depends on BLK
+	help
+	  Enable storage cloning over block devices, useful for
+	  initial flashing by external block device without network
+	  or usb support.
+
 config CMD_MTD
 	bool "mtd"
 	depends on MTD
diff --git a/cmd/Makefile b/cmd/Makefile
index f1dd513a4b..02663a1c73 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_MP) += mp.o
 obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
+obj-$(CONFIG_CMD_CLONE) += clone.o
 ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
 obj-y += legacy-mtd-utils.o
 endif
diff --git a/cmd/clone.c b/cmd/clone.c
new file mode 100644
index 0000000000..9ece465537
--- /dev/null
+++ b/cmd/clone.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 John Chau <john@harmon.hk>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <blk.h>
+#include <vsprintf.h>
+
+#define BUFSIZE (1 * 1024 * 1024)
+static int do_clone(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int srcdev, destdev;
+	struct blk_desc *srcdesc, *destdesc;
+	int srcbz, destbz, ret;
+	char *unit, *buf;
+	unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
+	unsigned long timer;
+	const unsigned long buffersize = 1024 * 1024;
+
+	if (argc < 6)
+		return CMD_RET_USAGE;
+
+	srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
+	destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
+	if (srcdev < 0) {
+		printf("Unable to open source device\n");
+		return 1;
+	} else if (destdev < 0) {
+		printf("Unable to open destination device\n");
+		return 1;
+	}
+	requested = simple_strtoul(argv[5], &unit, 10);
+	srcbz = srcdesc->blksz;
+	destbz = destdesc->blksz;
+
+	if ((srcbz * (buffersize / srcbz) != buffersize) &&
+	    (destbz * (buffersize / destbz) != buffersize)) {
+		printf("failed: cannot match device block sizes\n");
+		return 1;
+	}
+	if (requested == 0) {
+		unsigned long a = srcdesc->lba * srcdesc->blksz;
+		unsigned long b = destdesc->lba * destdesc->blksz;
+
+		if (a > b)
+			requested = a;
+		else
+			requested = b;
+	} else {
+		switch (unit[0]) {
+		case 'g':
+		case 'G':
+			requested *= 1024;
+		case 'm':
+		case 'M':
+			requested *= 1024;
+		case 'k':
+		case 'K':
+			requested *= 1024;
+			break;
+		}
+	}
+	printf("Copying %ld bytes from %s:%s to %s:%s\n",
+	       requested, argv[1], argv[2], argv[3], argv[4]);
+	wrcnt = 0;
+	rdcnt = 0;
+	buf = (char *)malloc(BUFSIZE);
+	srcblk = 0;
+	destblk = 0;
+	timer = get_timer(0);
+	while (wrcnt < requested) {
+		unsigned long toread = BUFSIZE / srcbz;
+		unsigned long towrite = BUFSIZE / destbz;
+		unsigned long offset = 0;
+
+read:
+		ret = blk_dread(srcdesc, srcblk, toread, buf + offset);
+		if (ret < 0) {
+			printf("Src read error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		rdcnt += ret * srcbz;
+		srcblk += ret;
+		if (ret < toread) {
+			toread -= ret;
+			offset += ret * srcbz;
+			goto read;
+		}
+		offset = 0;
+write:
+		ret = blk_dwrite(destdesc, destblk, towrite, buf + offset);
+		if (ret < 0) {
+			printf("Dest write error @blk %ld\n", srcblk);
+			goto exit;
+		}
+		wrcnt += ret * destbz;
+		destblk += ret;
+		if (ret < towrite) {
+			towrite -= ret;
+			offset += ret * destbz;
+			goto write;
+		}
+	}
+
+exit:
+	timer = get_timer(timer);
+	timer = 1000 * timer / CONFIG_SYS_HZ;
+	printf("%ld read\n", rdcnt);
+	printf("%ld written\n", wrcnt);
+	printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
+	free(buf);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	clone, 6, 1, do_clone,
+	"simple storage cloning",
+	"<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
+	"clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
+);
-- 
2.25.1

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

* [PATCH v3] cmd: add clone command
  2020-07-02  4:01   ` [PATCH v3] " John Chau
@ 2020-08-05 20:27     ` Tom Rini
  0 siblings, 0 replies; 5+ messages in thread
From: Tom Rini @ 2020-08-05 20:27 UTC (permalink / raw)
  To: u-boot

On Thu, Jul 02, 2020 at 12:01:21PM +0800, John Chau wrote:

> From: John Chau <john@harmon.hk>
> 
> This patch adds a feature for block device cloning similar to dd
> command, this should be useful for boot-strapping a device where
> usb gadget or networking is not available. For instance one can
> clone a factory image into a blank emmc from an external sd card.
> 
> Signed-off-by: John Chau <john@harmon.hk>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: not available
URL: <https://lists.denx.de/pipermail/u-boot/attachments/20200805/290587e6/attachment.sig>

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

end of thread, other threads:[~2020-08-05 20:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-27  3:15 [PATCH] cmd: add clone command John Chau
2020-06-29 15:54 ` Tom Rini
2020-07-02  3:38   ` [PATCH v2] " John Chau
2020-07-02  4:01   ` [PATCH v3] " John Chau
2020-08-05 20:27     ` Tom Rini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox