]> git.proxmox.com Git - pve-qemu.git/commitdiff
add qemu-img dd stdin/stdout pipe patch
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 23 Jun 2017 10:12:36 +0000 (12:12 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 23 Jun 2017 10:12:36 +0000 (12:12 +0200)
debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch [new file with mode: 0644]
debian/patches/series

diff --git a/debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch b/debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
new file mode 100644 (file)
index 0000000..2c137f7
--- /dev/null
@@ -0,0 +1,287 @@
+From 70bc584282901ee2a8954559393f305377016249 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 23 Jun 2017 12:01:43 +0200
+Subject: [PATCH 50/50] qemu-img dd: add osize and read from/to stdin/stdout
+
+Neither convert nor dd were previously able to write to or
+read from a pipe. Particularly serializing an image file
+into a raw stream or vice versa can be useful, but using
+`qemu-img convert -f qcow2 -O raw foo.qcow2 /dev/stdout` in
+a pipe will fail trying to seek.
+
+While dd and convert have overlapping use cases, `dd` is a
+simple read/write loop while convert is much more
+sophisticated and has ways to dealing with holes and blocks
+of zeroes.
+Since these typically can't be detected in pipes via
+SEEK_DATA/HOLE or skipped while writing, dd seems to be the
+better choice for implementing stdin/stdout streams.
+
+This patch causes "if" and "of" to default to stdin and
+stdout respectively, allowing only the "raw" format to be
+used in these cases.
+Since the input can now be a pipe we have no way of
+detecting the size of the output image to create. Since we
+also want to support images with a size not matching the
+dd command's "bs" parameter (which, together with "count"
+could be used to calculate the desired size, and is already
+used to limit it), the "osize" option is added to explicitly
+override the output file's size.
+
+Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
+---
+ qemu-img.c | 176 +++++++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 113 insertions(+), 63 deletions(-)
+
+diff --git a/qemu-img.c b/qemu-img.c
+index 4f7f458dd2..b9d1ef7bb8 100644
+--- a/qemu-img.c
++++ b/qemu-img.c
+@@ -4035,10 +4035,12 @@ out:
+ #define C_IF      04
+ #define C_OF      010
+ #define C_SKIP    020
++#define C_OSIZE   040
+ struct DdInfo {
+     unsigned int flags;
+     int64_t count;
++    int64_t osize;
+ };
+ struct DdIo {
+@@ -4117,6 +4119,20 @@ static int img_dd_skip(const char *arg,
+     return 0;
+ }
++static int img_dd_osize(const char *arg,
++                        struct DdIo *in, struct DdIo *out,
++                        struct DdInfo *dd)
++{
++    dd->osize = cvtnum(arg);
++
++    if (dd->osize < 0) {
++        error_report("invalid number: '%s'", arg);
++        return 1;
++    }
++
++    return 0;
++}
++
+ static int img_dd(int argc, char **argv)
+ {
+     int ret = 0;
+@@ -4156,6 +4172,7 @@ static int img_dd(int argc, char **argv)
+         { "if", img_dd_if, C_IF },
+         { "of", img_dd_of, C_OF },
+         { "skip", img_dd_skip, C_SKIP },
++        { "osize", img_dd_osize, C_OSIZE },
+         { NULL, NULL, 0 }
+     };
+     const struct option long_options[] = {
+@@ -4223,84 +4240,106 @@ static int img_dd(int argc, char **argv)
+         arg = NULL;
+     }
+-    if (!(dd.flags & C_IF && dd.flags & C_OF)) {
+-        error_report("Must specify both input and output files");
++    if (!(dd.flags & C_IF) && (!fmt || strcmp(fmt, "raw") != 0)) {
++        error_report("Input format must be raw when readin from stdin");
+         ret = -1;
+         goto out;
+     }
+-    blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
+-
+-    if (!blk1) {
++    if (!(dd.flags & C_OF) && strcmp(out_fmt, "raw") != 0) {
++        error_report("Output format must be raw when writing to stdout");
+         ret = -1;
+         goto out;
+     }
++    if (dd.flags & C_IF) {
++        blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
+-    drv = bdrv_find_format(out_fmt);
+-    if (!drv) {
+-        error_report("Unknown file format");
+-        ret = -1;
+-        goto out;
+-    }
+-    proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
+-
+-    if (!proto_drv) {
+-        error_report_err(local_err);
+-        ret = -1;
+-        goto out;
+-    }
+-    if (!drv->create_opts) {
+-        error_report("Format driver '%s' does not support image creation",
+-                     drv->format_name);
+-        ret = -1;
+-        goto out;
+-    }
+-    if (!proto_drv->create_opts) {
+-        error_report("Protocol driver '%s' does not support image creation",
+-                     proto_drv->format_name);
+-        ret = -1;
+-        goto out;
++        if (!blk1) {
++            ret = -1;
++            goto out;
++        }
+     }
+-    create_opts = qemu_opts_append(create_opts, drv->create_opts);
+-    create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+-
+-    opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+-    size = blk_getlength(blk1);
+-    if (size < 0) {
+-        error_report("Failed to get size for '%s'", in.filename);
++    if (dd.flags & C_OSIZE) {
++        size = dd.osize;
++    } else if (dd.flags & C_IF) {
++        size = blk_getlength(blk1);
++        if (size < 0) {
++            error_report("Failed to get size for '%s'", in.filename);
++            ret = -1;
++            goto out;
++        }
++    } else if (dd.flags & C_COUNT) {
++        size = dd.count * in.bsz;
++    } else {
++        error_report("Output size must be known when reading from stdin");
+         ret = -1;
+         goto out;
+     }
+-    if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
++    if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
+         dd.count * in.bsz < size) {
+         size = dd.count * in.bsz;
+     }
+-    /* Overflow means the specified offset is beyond input image's size */
+-    if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
+-                              size < in.bsz * in.offset)) {
+-        qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
+-    } else {
+-        qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
+-                            size - in.bsz * in.offset, &error_abort);
+-    }
+-    ret = bdrv_create(drv, out.filename, opts, &local_err);
+-    if (ret < 0) {
+-        error_reportf_err(local_err,
+-                          "%s: error while creating output image: ",
+-                          out.filename);
+-        ret = -1;
+-        goto out;
+-    }
++    if (dd.flags & C_OF) {
++        drv = bdrv_find_format(out_fmt);
++        if (!drv) {
++            error_report("Unknown file format");
++            ret = -1;
++            goto out;
++        }
++        proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
++
++        if (!proto_drv) {
++            error_report_err(local_err);
++            ret = -1;
++            goto out;
++        }
++        if (!drv->create_opts) {
++            error_report("Format driver '%s' does not support image creation",
++                         drv->format_name);
++            ret = -1;
++            goto out;
++        }
++        if (!proto_drv->create_opts) {
++            error_report("Protocol driver '%s' does not support image creation",
++                         proto_drv->format_name);
++            ret = -1;
++            goto out;
++        }
++        create_opts = qemu_opts_append(create_opts, drv->create_opts);
++        create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+-    blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
+-                    false, false);
++        opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+-    if (!blk2) {
+-        ret = -1;
+-        goto out;
++        /* Overflow means the specified offset is beyond input image's size */
++        if (dd.flags & C_OSIZE) {
++            qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
++        } else if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
++                                         size < in.bsz * in.offset)) {
++            qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
++        } else {
++            qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
++                                size - in.bsz * in.offset, &error_abort);
++        }
++
++        ret = bdrv_create(drv, out.filename, opts, &local_err);
++        if (ret < 0) {
++            error_reportf_err(local_err,
++                              "%s: error while creating output image: ",
++                              out.filename);
++            ret = -1;
++            goto out;
++        }
++
++        blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
++                        false, false);
++
++        if (!blk2) {
++            ret = -1;
++            goto out;
++        }
+     }
+     if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
+@@ -4318,11 +4357,18 @@ static int img_dd(int argc, char **argv)
+     for (out_pos = 0; in_pos < size; block_count++) {
+         int in_ret, out_ret;
++        size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
+-        if (in_pos + in.bsz > size) {
+-            in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos);
++        if (blk1) {
++            in_ret = blk_pread(blk1, in_pos, in.buf, in_bsz);
+         } else {
+-            in_ret = blk_pread(blk1, in_pos, in.buf, in.bsz);
++            in_ret = read(STDIN_FILENO, in.buf, in_bsz);
++            if (in_ret == 0) {
++                /* early EOF is considered an error */
++                error_report("Input ended unexpectedly");
++                ret = -1;
++                goto out;
++            }
+         }
+         if (in_ret < 0) {
+             error_report("error while reading from input image file: %s",
+@@ -4332,9 +4378,13 @@ static int img_dd(int argc, char **argv)
+         }
+         in_pos += in_ret;
+-        out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0);
++        if (blk2) {
++            out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0);
++        } else {
++            out_ret = write(STDOUT_FILENO, in.buf, in_ret);
++        }
+-        if (out_ret < 0) {
++        if (out_ret != in_ret) {
+             error_report("error while writing to output image file: %s",
+                          strerror(-out_ret));
+             ret = -1;
+-- 
+2.11.0
+
index 07b852e901c34fe41ffbb8b0f9541fd40cc8c19a..0b7f343e4db2712a32909609e339297d6ac8adf4 100644 (file)
@@ -47,6 +47,7 @@ pve/0046-convert-savevm-async-to-threads.patch
 pve/0047-glusterfs-allow-partial-reads.patch
 pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch
 pve/0049-block-zeroinit-request-child-permissions.patch
+pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
 extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
 extra/0002-qemu-img-wait-for-convert-coroutines-to-complete.patch
 extra/0003-block-Do-not-unref-bs-file-on-error-in-BD-s-open.patch