uboot/cmd/clone.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2020 John Chau <john@harmon.hk>
   4 *
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <malloc.h>
  10#include <part.h>
  11#include <blk.h>
  12#include <vsprintf.h>
  13
  14#define BUFSIZE (1 * 1024 * 1024)
  15static int do_clone(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
  16{
  17        int srcdev, destdev;
  18        struct blk_desc *srcdesc, *destdesc;
  19        int srcbz, destbz, ret;
  20        char *unit, *buf;
  21        unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
  22        unsigned long timer;
  23        const unsigned long buffersize = 1024 * 1024;
  24
  25        if (argc < 6)
  26                return CMD_RET_USAGE;
  27
  28        srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
  29        destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
  30        if (srcdev < 0) {
  31                printf("Unable to open source device\n");
  32                return 1;
  33        } else if (destdev < 0) {
  34                printf("Unable to open destination device\n");
  35                return 1;
  36        }
  37        requested = dectoul(argv[5], &unit);
  38        srcbz = srcdesc->blksz;
  39        destbz = destdesc->blksz;
  40
  41        if ((srcbz * (buffersize / srcbz) != buffersize) ||
  42            (destbz * (buffersize / destbz) != buffersize)) {
  43                printf("failed: cannot match device block sizes\n");
  44                return 1;
  45        }
  46        if (requested == 0) {
  47                unsigned long a = srcdesc->lba * srcdesc->blksz;
  48                unsigned long b = destdesc->lba * destdesc->blksz;
  49
  50                if (a > b)
  51                        requested = a;
  52                else
  53                        requested = b;
  54        } else {
  55                switch (unit[0]) {
  56                case 'g':
  57                case 'G':
  58                        requested *= 1024 * 1024 * 1024;
  59                        break;
  60                case 'm':
  61                case 'M':
  62                        requested *= 1024 * 1024;
  63                        break;
  64                case 'k':
  65                case 'K':
  66                        requested *= 1024;
  67                        break;
  68                }
  69        }
  70        printf("Copying %ld bytes from %s:%s to %s:%s\n",
  71               requested, argv[1], argv[2], argv[3], argv[4]);
  72        wrcnt = 0;
  73        rdcnt = 0;
  74        buf = (char *)malloc(BUFSIZE);
  75        srcblk = 0;
  76        destblk = 0;
  77        timer = get_timer(0);
  78        while (wrcnt < requested) {
  79                unsigned long toread = BUFSIZE / srcbz;
  80                unsigned long towrite = BUFSIZE / destbz;
  81                unsigned long offset = 0;
  82
  83read:
  84                ret = blk_dread(srcdesc, srcblk, toread, buf + offset);
  85                if (ret < 0) {
  86                        printf("Src read error @blk %ld\n", srcblk);
  87                        goto exit;
  88                }
  89                rdcnt += ret * srcbz;
  90                srcblk += ret;
  91                if (ret < toread) {
  92                        toread -= ret;
  93                        offset += ret * srcbz;
  94                        goto read;
  95                }
  96                offset = 0;
  97write:
  98                ret = blk_dwrite(destdesc, destblk, towrite, buf + offset);
  99                if (ret < 0) {
 100                        printf("Dest write error @blk %ld\n", srcblk);
 101                        goto exit;
 102                }
 103                wrcnt += ret * destbz;
 104                destblk += ret;
 105                if (ret < towrite) {
 106                        towrite -= ret;
 107                        offset += ret * destbz;
 108                        goto write;
 109                }
 110        }
 111
 112exit:
 113        timer = get_timer(timer);
 114        timer = 1000 * timer / CONFIG_SYS_HZ;
 115        printf("%ld read\n", rdcnt);
 116        printf("%ld written\n", wrcnt);
 117        printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
 118        free(buf);
 119
 120        return 0;
 121}
 122
 123U_BOOT_CMD(
 124        clone, 6, 1, do_clone,
 125        "simple storage cloning",
 126        "<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
 127        "clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
 128);
 129