qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qemu-img: add skip option to dd

This adds the skip option which allows qemu-img dd to skip a number of blocks
before copying the input.

A test case was added to test the skip option.

Signed-off-by: Reda Sallahi <fullmanet@gmail.com>
Message-id: 20160810141609.32727-1-fullmanet@gmail.com
Signed-off-by: Max Reitz <mreitz@redhat.com>

authored by

Reda Sallahi and committed by
Max Reitz
f7c15533 86ce1f6e

+174 -8
+2 -2
qemu-img-cmds.hx
··· 46 46 ETEXI 47 47 48 48 DEF("dd", img_dd, 49 - "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] if=input of=output") 49 + "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output") 50 50 STEXI 51 - @item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} 51 + @item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} 52 52 ETEXI 53 53 54 54 DEF("info", img_info,
+45 -5
qemu-img.c
··· 173 173 "(default: 512)\n" 174 174 " 'count=N' copy only N input blocks\n" 175 175 " 'if=FILE' read from FILE\n" 176 - " 'of=FILE' write to FILE\n"; 176 + " 'of=FILE' write to FILE\n" 177 + " 'skip=N' skip N bs-sized blocks at the start of input\n"; 177 178 178 179 printf("%s\nSupported formats:", help_msg); 179 180 bdrv_iterate_format(format_print, NULL); ··· 3807 3808 #define C_COUNT 02 3808 3809 #define C_IF 04 3809 3810 #define C_OF 010 3811 + #define C_SKIP 020 3810 3812 3811 3813 struct DdInfo { 3812 3814 unsigned int flags; ··· 3817 3819 int bsz; /* Block size */ 3818 3820 char *filename; 3819 3821 uint8_t *buf; 3822 + int64_t offset; 3820 3823 }; 3821 3824 3822 3825 struct DdOpts { ··· 3877 3880 return 0; 3878 3881 } 3879 3882 3883 + static int img_dd_skip(const char *arg, 3884 + struct DdIo *in, struct DdIo *out, 3885 + struct DdInfo *dd) 3886 + { 3887 + char *end; 3888 + 3889 + in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); 3890 + 3891 + if (in->offset < 0 || *end) { 3892 + error_report("invalid number: '%s'", arg); 3893 + return 1; 3894 + } 3895 + 3896 + return 0; 3897 + } 3898 + 3880 3899 static int img_dd(int argc, char **argv) 3881 3900 { 3882 3901 int ret = 0; ··· 3900 3919 struct DdIo in = { 3901 3920 .bsz = 512, /* Block size is by default 512 bytes */ 3902 3921 .filename = NULL, 3903 - .buf = NULL 3922 + .buf = NULL, 3923 + .offset = 0 3904 3924 }; 3905 3925 struct DdIo out = { 3906 3926 .bsz = 512, 3907 3927 .filename = NULL, 3908 - .buf = NULL 3928 + .buf = NULL, 3929 + .offset = 0 3909 3930 }; 3910 3931 3911 3932 const struct DdOpts options[] = { ··· 3913 3934 { "count", img_dd_count, C_COUNT }, 3914 3935 { "if", img_dd_if, C_IF }, 3915 3936 { "of", img_dd_of, C_OF }, 3937 + { "skip", img_dd_skip, C_SKIP }, 3916 3938 { NULL, NULL, 0 } 3917 3939 }; 3918 3940 const struct option long_options[] = { ··· 4032 4054 size = dd.count * in.bsz; 4033 4055 } 4034 4056 4035 - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort); 4057 + /* Overflow means the specified offset is beyond input image's size */ 4058 + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || 4059 + size < in.bsz * in.offset)) { 4060 + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort); 4061 + } else { 4062 + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 4063 + size - in.bsz * in.offset, &error_abort); 4064 + } 4036 4065 4037 4066 ret = bdrv_create(drv, out.filename, opts, &local_err); 4038 4067 if (ret < 0) { ··· 4051 4080 goto out; 4052 4081 } 4053 4082 4083 + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || 4084 + size < in.offset * in.bsz)) { 4085 + /* We give a warning if the skip option is bigger than the input 4086 + * size and create an empty output disk image (i.e. like dd(1)). 4087 + */ 4088 + error_report("%s: cannot skip to specified offset", in.filename); 4089 + in_pos = size; 4090 + } else { 4091 + in_pos = in.offset * in.bsz; 4092 + } 4093 + 4054 4094 in.buf = g_new(uint8_t, in.bsz); 4055 4095 4056 - for (in_pos = 0, out_pos = 0; in_pos < size; block_count++) { 4096 + for (out_pos = 0; in_pos < size; block_count++) { 4057 4097 int in_ret, out_ret; 4058 4098 4059 4099 if (in_pos + in.bsz > size) {
+3 -1
qemu-img.texi
··· 151 151 sets the input file 152 152 @item of=@var{output} 153 153 sets the output file 154 + @item skip=@var{blocks} 155 + sets the number of input blocks to skip 154 156 @end table 155 157 156 158 Command description: ··· 324 326 volume has already been created with site specific options that cannot 325 327 be supplied through qemu-img. 326 328 327 - @item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} 329 + @item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} 328 330 329 331 Dd copies from @var{input} file to @var{output} file converting it from 330 332 @var{fmt} format to @var{output_fmt} format.
+72
tests/qemu-iotests/160
··· 1 + #! /bin/bash 2 + # 3 + # qemu-img dd test for the skip option 4 + # 5 + # Copyright (C) 2016 Reda Sallahi 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # This program is distributed in the hope that it will be useful, 13 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + # GNU General Public License for more details. 16 + # 17 + # You should have received a copy of the GNU General Public License 18 + # along with this program. If not, see <http://www.gnu.org/licenses/>. 19 + # 20 + 21 + owner=fullmanet@gmail.com 22 + 23 + seq="$(basename $0)" 24 + echo "QA output created by $seq" 25 + 26 + here="$PWD" 27 + status=1 28 + 29 + _cleanup() 30 + { 31 + _cleanup_test_img 32 + rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd" 33 + } 34 + trap "_cleanup; exit \$status" 0 1 2 3 15 35 + 36 + . ./common.rc 37 + . ./common.filter 38 + . ./common.pattern 39 + 40 + _supported_fmt raw 41 + _supported_proto file 42 + _supported_os Linux 43 + 44 + TEST_SKIP_BLOCKS="1 2 30 30K" 45 + 46 + for skip in $TEST_SKIP_BLOCKS; do 47 + echo 48 + echo "== Creating image ==" 49 + 50 + size=1M 51 + _make_test_img $size 52 + _check_test_img 53 + $QEMU_IO -c "write -P 0xa 24 512k" "$TEST_IMG" | _filter_qemu_io 54 + 55 + echo 56 + echo "== Converting the image with dd with skip=$skip ==" 57 + 58 + $QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" -O "$IMGFMT" \ 59 + 2> /dev/null 60 + TEST_IMG="$TEST_IMG.out" _check_test_img 61 + dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" status=none 62 + 63 + echo 64 + echo "== Compare the images with qemu-img compare ==" 65 + 66 + $QEMU_IMG compare "$TEST_IMG.out.dd" "$TEST_IMG.out" 67 + done 68 + 69 + echo 70 + echo "*** done" 71 + rm -f "$seq.full" 72 + status=0
+51
tests/qemu-iotests/160.out
··· 1 + QA output created by 160 2 + 3 + == Creating image == 4 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 5 + No errors were found on the image. 6 + wrote 524288/524288 bytes at offset 24 7 + 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 + 9 + == Converting the image with dd with skip=1 == 10 + No errors were found on the image. 11 + 12 + == Compare the images with qemu-img compare == 13 + Images are identical. 14 + 15 + == Creating image == 16 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 17 + No errors were found on the image. 18 + wrote 524288/524288 bytes at offset 24 19 + 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 20 + 21 + == Converting the image with dd with skip=2 == 22 + No errors were found on the image. 23 + 24 + == Compare the images with qemu-img compare == 25 + Images are identical. 26 + 27 + == Creating image == 28 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 29 + No errors were found on the image. 30 + wrote 524288/524288 bytes at offset 24 31 + 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 32 + 33 + == Converting the image with dd with skip=30 == 34 + No errors were found on the image. 35 + 36 + == Compare the images with qemu-img compare == 37 + Images are identical. 38 + 39 + == Creating image == 40 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 41 + No errors were found on the image. 42 + wrote 524288/524288 bytes at offset 24 43 + 512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 44 + 45 + == Converting the image with dd with skip=30K == 46 + No errors were found on the image. 47 + 48 + == Compare the images with qemu-img compare == 49 + Images are identical. 50 + 51 + *** done
+1
tests/qemu-iotests/group
··· 158 158 156 rw auto quick 159 159 157 auto 160 160 159 rw auto quick 161 + 160 rw auto quick 161 162 162 auto quick 162 163 170 rw auto quick