[PATCH v2 3/3] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
The point of 'qemu-img convert --bitmaps' is to be a convenience for actions that are already possible through a string of smaller 'qemu-img bitmap' sub-commands. One situation not accounted for already is that if a source image contains an inconsistent bitmap (for example, because a qemu process died abruptly before flushing bitmap state), the user MUST delete those inconsistent bitmaps before anything else useful can be done with the image. We don't want to delete inconsistent bitmaps by default: although a corrupt bitmap is only a loss of optimization rather than a corruption of user-visible data, it is still nice to require the user to opt in to the fact that they are aware of the loss of the bitmap. Still, requiring the user to check 'qemu-img info' to see whether bitmaps are consistent, then use 'qemu-img bitmap --remove' to remove offenders, all before using 'qemu-img convert', is a lot more work than just adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which opts in to skipping the broken bitmaps. After testing the new option, also demonstrate the way to manually fix things (either deleting bad bitmaps, or re-creating them as empty) so that it is possible to convert without the option. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084 Signed-off-by: Eric Blake --- docs/tools/qemu-img.rst | 8 - qemu-img.c| 26 +--- tests/qemu-iotests/tests/qemu-img-bitmaps | 10 ++ tests/qemu-iotests/tests/qemu-img-bitmaps.out | 31 +++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index cfe11478791f..4d407b180450 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -414,7 +414,7 @@ Command description: 4 Error on reading data -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can @@ -456,6 +456,12 @@ Command description: *NUM_COROUTINES* specifies how many coroutines work in parallel during the convert process (defaults to 8). + Use of ``--bitmaps`` requests that any persistent bitmaps present in + the original are also copied to the destination. If any bitmap is + inconsistent in the source, the conversion will fail unless + ``--skip-broken-bitmaps`` is also specified to copy only the + consistent bitmaps. + .. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE] Create the new disk image *FILENAME* of size *SIZE* and format diff --git a/qemu-img.c b/qemu-img.c index e84b3c530155..661538edd785 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -82,6 +82,7 @@ enum { OPTION_MERGE = 274, OPTION_BITMAPS = 275, OPTION_FORCE = 276, +OPTION_SKIP_BROKEN = 277, }; typedef enum OutputFormat { @@ -2102,7 +2103,7 @@ static int convert_do_copy(ImgConvertState *s) } /* Check that bitmaps can be copied, or output an error */ -static int convert_check_bitmaps(BlockDriverState *src) +static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken) { BdrvDirtyBitmap *bm; @@ -2117,7 +2118,7 @@ static int convert_check_bitmaps(BlockDriverState *src) continue; } name = bdrv_dirty_bitmap_name(bm); -if (bdrv_dirty_bitmap_inconsistent(bm)) { +if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { error_report("Cannot copy inconsistent bitmap '%s'", name); return -1; } @@ -2125,7 +2126,8 @@ static int convert_check_bitmaps(BlockDriverState *src) return 0; } -static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) +static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst, +bool skip_broken) { BdrvDirtyBitmap *bm; Error *err = NULL; @@ -2137,6 +2139,10 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst) continue; } name = bdrv_dirty_bitmap_name(bm); +if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { +warn_report("Skipping inconsistent bitmap %s", name); +
Re: [PATCH v2 3/3] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
On 7/9/21 6:39 PM, Eric Blake wrote: The point of 'qemu-img convert --bitmaps' is to be a convenience for actions that are already possible through a string of smaller 'qemu-img bitmap' sub-commands. One situation not accounted for already is that if a source image contains an inconsistent bitmap (for example, because a qemu process died abruptly before flushing bitmap state), the user MUST delete those inconsistent bitmaps before anything else useful can be done with the image. The only thing affected by inconsistent bitmap is creating incremental backup, and taking some space on storage. Anything else should not be affected by having such bitmap so the user does not need to remove it. In oVirt we don't check or repair images after unclean guest shutdown. Maybe this is a good idea for future version. Inconsistent bitmaps are removed only when the user ask to remove the related checkpoint. We don't want to delete inconsistent bitmaps by default: although a corrupt bitmap is only a loss of optimization rather than a corruption of user-visible data, it is still nice to require the user to opt in to the fact that they are aware of the loss of the bitmap. Still, requiring the user to check 'qemu-img info' to see whether bitmaps are consistent, then use 'qemu-img bitmap --remove' to remove offenders, all before using 'qemu-img convert', is a lot more work than just adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which opts in to skipping the broken bitmaps. I think this is more than convenience. During live storage migration in oVirt, we mirror the top layer to the destination using libvirt blockCopy, and copy the rest of the chain using qemu-img convert with the --bitmaps option. If we have to remove inconsistent bitmaps at this point we need to modify images opened for reading by qemu, which is likely not possible and even if it is possible, sounds like a bad idea. After testing the new option, also demonstrate the way to manually fix things (either deleting bad bitmaps, or re-creating them as empty) so that it is possible to convert without the option. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084 Signed-off-by: Eric Blake --- docs/tools/qemu-img.rst | 8 - qemu-img.c| 26 +--- tests/qemu-iotests/tests/qemu-img-bitmaps | 10 ++ tests/qemu-iotests/tests/qemu-img-bitmaps.out | 31 +++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index cfe11478791f..4d407b180450 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -414,7 +414,7 @@ Command description: 4 Error on reading data -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME I liked --skip-broken more, but Vladimir is right that this is not really a sub-option. Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can @@ -456,6 +456,12 @@ Command description: *NUM_COROUTINES* specifies how many coroutines work in parallel during the convert process (defaults to 8). + Use of ``--bitmaps`` requests that any persistent bitmaps present in + the original are also copied to the destination. If any bitmap is + inconsistent in the source, the conversion will fail unless + ``--skip-broken-bitmaps`` is also specified to copy only the + consistent bitmaps. + .. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE] Create the new disk image *FILENAME* of size *SIZE* and format diff --git a/qemu-img.c b/qemu-img.c index e84b3c530155..661538edd785 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -82,6 +82,7 @@ enum { OPTION_MERGE = 274, OPTION_BITMAPS = 275, OPTION_FORCE = 276, +OPTION_SKIP_BROKEN = 277, }; typedef enum OutputFormat { @@ -2102,7 +2103,7 @@ static int convert_do_copy(ImgConvertState *s) } /* Check that bitmaps can be copied, or output an error */ -static int convert_check_bitmaps(BlockDriverState *src) +static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken) { BdrvDirtyBitmap *bm; @@ -2117,7 +2118,7 @@ static int convert_che
Re: [PATCH v2 3/3] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
On Sat, Jul 10, 2021 at 09:37:35PM +0300, Nir Soffer wrote: > > We don't want to delete inconsistent bitmaps by default: although a > > corrupt bitmap is only a loss of optimization rather than a corruption > > of user-visible data, it is still nice to require the user to opt in > > to the fact that they are aware of the loss of the bitmap. Still, > > requiring the user to check 'qemu-img info' to see whether bitmaps are > > consistent, then use 'qemu-img bitmap --remove' to remove offenders, > > all before using 'qemu-img convert', is a lot more work than just > > adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which > > opts in to skipping the broken bitmaps. > > I think this is more than convenience. During live storage migration in > oVirt, we mirror the top layer to the destination using libvirt blockCopy, > and copy the rest of the chain using qemu-img convert with the --bitmaps > option. Still, this feels like enough of a feature that I'd really like R-b in time to prepare a pull request for inclusion in soft freeze; the justification for it being a bug fix is a tough sell. > > +.. option:: convert [--object OBJECTDEF] [--image-opts] > > [--target-image-opts] [--target-is-zero] [--bitmaps > > [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] > > [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l > > SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] > > FILENAME [FILENAME2 [...]] OUTPUT_FILENAME > > I liked --skip-broken more, but Vladimir is right that this is not really a > sub-option. getopt_long() lets you abbreviate; '--sk' and '--skip-broken' are both unambiguous prefixes of '--skip-broken-bitmaps'. > > @@ -2117,7 +2118,7 @@ static int convert_check_bitmaps(BlockDriverState > > *src) > > continue; > > } > > name = bdrv_dirty_bitmap_name(bm); > > -if (bdrv_dirty_bitmap_inconsistent(bm)) { > > +if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { > > error_report("Cannot copy inconsistent bitmap '%s'", name); > > We can add another hint: > > Try --skip-brocken-bitmaps to skip this bitmap or "qemu-img bitmap > --remove" to delete it from disk. Sure, I can see about adding that. > > > return -1; > > } > > @@ -2125,7 +2126,8 @@ static int convert_check_bitmaps(BlockDriverState > > *src) > > return 0; > > } > > > > -static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState > > *dst) > > +static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState > > *dst, > > +bool skip_broken) > > { > > BdrvDirtyBitmap *bm; > > Error *err = NULL; > > @@ -2137,6 +2139,10 @@ static int convert_copy_bitmaps(BlockDriverState > > *src, BlockDriverState *dst) > > continue; > > } > > name = bdrv_dirty_bitmap_name(bm); > > +if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { > > +warn_report("Skipping inconsistent bitmap %s", name); > > In other logs we quote the bitmap name:'%s' Yes, will fix. > > +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps > > @@ -143,6 +143,16 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" > > "$TEST_IMG.copy" && > > echo "unexpected success" > > TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ > > | _filter_irrelevant_img_info > > A new title here will make the test output much more clear. Or even just a bare 'echo' to separate things with blank lines. Will improve. > > +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out > > @@ -145,4 +145,35 @@ Format specific information: > > corrupt: false > > qemu-img: Cannot copy inconsistent bitmap 'b0' > > qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open > > 'TEST_DIR/t.IMGFMT.copy': No such file or directory > > Why to we get this error? I guess it is part of the first copy that should > fail? Yes - proof that we no longer leave a broken file around, but instead failed fast (in fact, that's part of the previous patch). > > > +qemu-img: warning: Skipping inconsistent bitmap b0 > > +qemu-img: warning: Skipping inconsistent bitmap b2 > > Looks useful, I need to check that we log such warnings. > Anything else I should improve before sending a v2? -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Re: [PATCH v2 3/3] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
On Tue, Jul 13, 2021 at 8:53 PM Eric Blake wrote: > > On Sat, Jul 10, 2021 at 09:37:35PM +0300, Nir Soffer wrote: > > > We don't want to delete inconsistent bitmaps by default: although a > > > corrupt bitmap is only a loss of optimization rather than a corruption > > > of user-visible data, it is still nice to require the user to opt in > > > to the fact that they are aware of the loss of the bitmap. Still, > > > requiring the user to check 'qemu-img info' to see whether bitmaps are > > > consistent, then use 'qemu-img bitmap --remove' to remove offenders, > > > all before using 'qemu-img convert', is a lot more work than just > > > adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which > > > opts in to skipping the broken bitmaps. > > > > I think this is more than convenience. During live storage migration in > > oVirt, we mirror the top layer to the destination using libvirt blockCopy, > > and copy the rest of the chain using qemu-img convert with the --bitmaps > > option. > > Still, this feels like enough of a feature that I'd really like R-b in > time to prepare a pull request for inclusion in soft freeze; the > justification for it being a bug fix is a tough sell. This is not a bug in the current code, more like missing handling of important use case. Without this we cannot copy images in some cases, or we must require downtime to check and repair images before copying disks. > > > +.. option:: convert [--object OBJECTDEF] [--image-opts] > > > [--target-image-opts] [--target-is-zero] [--bitmaps > > > [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t > > > CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l > > > SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] > > > FILENAME [FILENAME2 [...]] OUTPUT_FILENAME > > > > I liked --skip-broken more, but Vladimir is right that this is not really a > > sub-option. > > getopt_long() lets you abbreviate; '--sk' and '--skip-broken' are both > unambiguous prefixes of '--skip-broken-bitmaps'. Nice to learn that > > > @@ -2117,7 +2118,7 @@ static int convert_check_bitmaps(BlockDriverState > > > *src) > > > continue; > > > } > > > name = bdrv_dirty_bitmap_name(bm); > > > -if (bdrv_dirty_bitmap_inconsistent(bm)) { > > > +if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { > > > error_report("Cannot copy inconsistent bitmap '%s'", name); > > > > We can add another hint: > > > > Try --skip-brocken-bitmaps to skip this bitmap or "qemu-img bitmap > > --remove" to delete it from disk. > > Sure, I can see about adding that. > > > > > > > return -1; > > > } > > > @@ -2125,7 +2126,8 @@ static int convert_check_bitmaps(BlockDriverState > > > *src) > > > return 0; > > > } > > > > > > -static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState > > > *dst) > > > +static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState > > > *dst, > > > +bool skip_broken) > > > { > > > BdrvDirtyBitmap *bm; > > > Error *err = NULL; > > > @@ -2137,6 +2139,10 @@ static int convert_copy_bitmaps(BlockDriverState > > > *src, BlockDriverState *dst) > > > continue; > > > } > > > name = bdrv_dirty_bitmap_name(bm); > > > +if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) { > > > +warn_report("Skipping inconsistent bitmap %s", name); > > > > In other logs we quote the bitmap name:'%s' > > Yes, will fix. > > > > +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps > > > @@ -143,6 +143,16 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" > > > "$TEST_IMG.copy" && > > > echo "unexpected success" > > > TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ > > > | _filter_irrelevant_img_info > > > > A new title here will make the test output much more clear. > > Or even just a bare 'echo' to separate things with blank lines. Will > improve. > > > > +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out > > > @@ -145,4 +145,35 @@ Format specific information: > > > corrupt: false > > > qemu-img: Cannot copy inconsistent bitmap 'b0' > > > qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open > > > 'TEST_DIR/t.IMGFMT.copy': No such file or directory > > > > Why to we get this error? I guess it is part of the first copy that should > > fail? > > Yes - proof that we no longer leave a broken file around, but instead > failed fast (in fact, that's part of the previous patch). > > > > > > +qemu-img: warning: Skipping inconsistent bitmap b0 > > > +qemu-img: warning: Skipping inconsistent bitmap b2 > > > > Looks useful, I need to check that we log such warnings. > > > > Anything else I should improve before sending a v2? I think we covered everything, but Vladimir may want to comment.
Re: [PATCH v2 3/3] qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
09.07.2021 18:39, Eric Blake wrote: The point of 'qemu-img convert --bitmaps' is to be a convenience for actions that are already possible through a string of smaller 'qemu-img bitmap' sub-commands. One situation not accounted for already is that if a source image contains an inconsistent bitmap (for example, because a qemu process died abruptly before flushing bitmap state), the user MUST delete those inconsistent bitmaps before anything else useful can be done with the image. We don't want to delete inconsistent bitmaps by default: although a corrupt bitmap is only a loss of optimization rather than a corruption of user-visible data, it is still nice to require the user to opt in to the fact that they are aware of the loss of the bitmap. Still, requiring the user to check 'qemu-img info' to see whether bitmaps are consistent, then use 'qemu-img bitmap --remove' to remove offenders, all before using 'qemu-img convert', is a lot more work than just adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which opts in to skipping the broken bitmaps. After testing the new option, also demonstrate the way to manually fix things (either deleting bad bitmaps, or re-creating them as empty) so that it is possible to convert without the option. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084 Signed-off-by: Eric Blake [..] --- a/tests/qemu-iotests/tests/qemu-img-bitmaps +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps @@ -143,6 +143,16 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" && echo "unexpected success" TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ | _filter_irrelevant_img_info +$QEMU_IMG convert --bitmaps --skip-broken-bitmaps \ +-O qcow2 "$TEST_IMG" "$TEST_IMG.copy" Nitpicking: sometimes you quote filename variables, sometimes not.. +TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ +| _filter_irrelevant_img_info +_rm_test_img "$TEST_IMG.copy" +$QEMU_IMG bitmap --remove "$TEST_IMG" b0 +$QEMU_IMG bitmap --remove --add "$TEST_IMG" b2 +$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" +TEST_IMG=$TEST_IMG.copy _img_info --format-specific \ +| _filter_irrelevant_img_info With or without adjustments you discussed: Reviewed-by: Vladimir Sementsov-Ogievskiy -- Best regards, Vladimir