@@ -307,6 +307,8 @@ int qcow2_mark_corrupt(BlockDriverState *bs)
BDRVQcow2State *s = bs->opaque;
s->incompatible_features |= QCOW2_INCOMPAT_CORRUPT;
+ s->compatible_features &= ~QCOW2_COMPAT_IN_USE;
+
return qcow2_update_header(bs);
}
@@ -472,6 +474,11 @@ static QemuOptsList qcow2_runtime_opts = {
.type = QEMU_OPT_NUMBER,
.help = "Clean unused cache entries after this time (in seconds)",
},
+ {
+ .name = BDRV_OPT_OVERRIDE_LOCK,
+ .type = QEMU_OPT_BOOL,
+ .help = "Open the image read-write even if it is locked",
+ },
{ /* end of list */ }
},
};
@@ -593,6 +600,7 @@ typedef struct Qcow2ReopenState {
Qcow2Cache *l2_table_cache;
Qcow2Cache *refcount_block_cache;
bool use_lazy_refcounts;
+ bool override_lock;
int overlap_check;
bool discard_passthrough[QCOW2_DISCARD_MAX];
uint64_t cache_clean_interval;
@@ -754,6 +762,9 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
r->discard_passthrough[QCOW2_DISCARD_OTHER] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
+ r->override_lock = qemu_opt_get_bool(opts, BDRV_OPT_OVERRIDE_LOCK,
+ s->override_lock);
+
ret = 0;
fail:
qemu_opts_del(opts);
@@ -788,6 +799,8 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
s->cache_clean_interval = r->cache_clean_interval;
cache_clean_timer_init(bs, bdrv_get_aio_context(bs));
}
+
+ s->override_lock = r->override_lock;
}
static void qcow2_update_options_abort(BlockDriverState *bs,
@@ -1080,6 +1093,22 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
+ /* Protect against opening the image r/w twice at the same time */
+ if (!bs->read_only && (s->compatible_features & QCOW2_COMPAT_IN_USE)) {
+ /* Shared storage is expected during migration */
+ bool migrating = (flags & BDRV_O_INCOMING);
+
+ if (!migrating && !s->override_lock) {
+ error_set(errp, ERROR_CLASS_IMAGE_FILE_LOCKED,
+ "Image is already in use");
+ error_append_hint(errp, "This check can be disabled "
+ "with override-lock=on. Caution: Opening an "
+ "image twice can cause corruption!");
+ ret = -EBUSY;
+ goto fail;
+ }
+ }
+
s->cluster_cache = g_malloc(s->cluster_size);
/* one more sector for decompressed data alignment */
s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS
@@ -1164,6 +1193,17 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
}
}
+ /* Set advisory lock in the header (do this as the final step so that
+ * failure doesn't leave a locked image around) */
+ if (!bs->read_only && !(flags & BDRV_O_INCOMING) && s->qcow_version >= 3) {
+ s->compatible_features |= QCOW2_COMPAT_IN_USE;
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not update qcow2 header");
+ goto fail;
+ }
+ }
+
#ifdef DEBUG_ALLOC
{
BdrvCheckResult result = {0};
@@ -1260,6 +1300,15 @@ static int qcow2_reopen_prepare(BDRVReopenState *state,
if (ret < 0) {
goto fail;
}
+
+ if (!state->bs->read_only) {
+ BDRVQcow2State *s = state->bs->opaque;
+ s->compatible_features &= ~QCOW2_COMPAT_IN_USE;
+ ret = qcow2_update_header(state->bs);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
}
return 0;
@@ -1272,12 +1321,32 @@ fail:
static void qcow2_reopen_commit(BDRVReopenState *state)
{
+ /* We can't fail the commit, so if the header update fails, we may end up
+ * not protecting the image even though it is writable now. This is okay,
+ * the lock is a best-effort service to protect the user from shooting
+ * themselves into the foot. */
+ if (state->bs->read_only && (state->flags & BDRV_O_RDWR)) {
+ BDRVQcow2State *s = state->bs->opaque;
+ s->compatible_features |= QCOW2_COMPAT_IN_USE;
+ (void) qcow2_update_header(state->bs);
+ }
+
qcow2_update_options_commit(state->bs, state->opaque);
g_free(state->opaque);
}
static void qcow2_reopen_abort(BDRVReopenState *state)
{
+ /* We can't fail the abort, so if the header update fails, we may end up
+ * not protecting the image any more. This is okay, the lock is a
+ * best-effort service to protect the user from shooting themselves into
+ * the foot. */
+ if (!state->bs->read_only && !(state->flags & BDRV_O_RDWR)) {
+ BDRVQcow2State *s = state->bs->opaque;
+ s->compatible_features |= QCOW2_COMPAT_IN_USE;
+ (void) qcow2_update_header(state->bs);
+ }
+
qcow2_update_options_abort(state->bs, state->opaque);
g_free(state->opaque);
}
@@ -1708,6 +1777,16 @@ static int qcow2_inactivate(BlockDriverState *bs)
qcow2_mark_clean(bs);
}
+ if (!bs->read_only) {
+ s->flags |= BDRV_O_INCOMING;
+ s->compatible_features &= ~QCOW2_COMPAT_IN_USE;
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ result = ret;
+ error_report("Could not update qcow2 header: %s", strerror(-ret));
+ }
+ }
+
return result;
}
@@ -1926,6 +2005,11 @@ int qcow2_update_header(BlockDriverState *bs)
.bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
.name = "lazy refcounts",
},
+ {
+ .type = QCOW2_FEAT_TYPE_COMPATIBLE,
+ .bit = QCOW2_COMPAT_IN_USE_BITNR,
+ .name = "image is in use (locked)",
+ },
};
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
@@ -190,9 +190,12 @@ enum {
/* Compatible feature bits */
enum {
QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR = 0,
+ QCOW2_COMPAT_IN_USE_BITNR = 1,
QCOW2_COMPAT_LAZY_REFCOUNTS = 1 << QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
+ QCOW2_COMPAT_IN_USE = 1 << QCOW2_COMPAT_IN_USE_BITNR,
- QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS,
+ QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS
+ | QCOW2_COMPAT_IN_USE,
};
enum qcow2_discard_type {
@@ -293,6 +296,8 @@ typedef struct BDRVQcow2State {
* override) */
char *image_backing_file;
char *image_backing_format;
+
+ bool override_lock;
} BDRVQcow2State;
typedef struct Qcow2COWRegion {
@@ -96,7 +96,12 @@ in the description of a field.
marking the image file dirty and postponing
refcount metadata updates.
- Bits 1-63: Reserved (set to 0)
+ Bit 1: Locking bit. If this bit is set, then the
+ image is supposedly in use by some process and
+ shouldn't be opened read-write by another
+ process.
+
+ Bits 2-63: Reserved (set to 0)
88 - 95: autoclear_features
Bitmask of auto-clear features. An implementation may only
@@ -107,7 +107,7 @@ $QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io
# Reads are another path to trigger l2_load, so do a read, too
if [ "$event" == "l2_load" ]; then
$QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io
- $QEMU_IO -c "read $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io
+ $QEMU_IO -r -c "read $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io
fi
_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
@@ -16,6 +16,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
1 leaked clusters were found on the image.
@@ -25,6 +26,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
1 leaked clusters were found on the image.
@@ -44,6 +46,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
1 leaked clusters were found on the image.
@@ -53,6 +56,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
1 leaked clusters were found on the image.
@@ -80,9 +84,8 @@ wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
-Failed to flush the L2 table cache: Input/output error
-Failed to flush the refcount block cache: Input/output error
read failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -92,9 +95,8 @@ wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
-Failed to flush the L2 table cache: Input/output error
-Failed to flush the refcount block cache: Input/output error
read failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -120,9 +122,8 @@ wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
-Failed to flush the L2 table cache: No space left on device
-Failed to flush the refcount block cache: No space left on device
read failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -132,9 +133,8 @@ wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
-Failed to flush the L2 table cache: No space left on device
-Failed to flush the refcount block cache: No space left on device
read failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -152,6 +152,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
127 leaked clusters were found on the image.
@@ -161,6 +162,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
127 leaked clusters were found on the image.
@@ -180,6 +182,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
127 leaked clusters were found on the image.
@@ -189,6 +192,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
127 leaked clusters were found on the image.
@@ -208,6 +212,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc_write; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -215,6 +220,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
1 leaked clusters were found on the image.
@@ -234,6 +240,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc_write; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -241,6 +248,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
1 leaked clusters were found on the image.
@@ -260,6 +268,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -267,6 +276,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -284,6 +294,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -291,6 +302,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -308,6 +320,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -315,6 +328,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -332,6 +346,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -339,6 +354,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -356,6 +372,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -363,6 +380,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -380,6 +398,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -387,6 +406,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -404,6 +424,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -411,6 +432,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -428,6 +450,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -435,6 +458,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -452,6 +476,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -459,6 +484,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -476,6 +502,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -483,6 +510,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
@@ -503,6 +531,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
55 leaked clusters were found on the image.
@@ -512,6 +541,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
251 leaked clusters were found on the image.
@@ -531,6 +561,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -538,6 +569,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -555,6 +587,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
11 leaked clusters were found on the image.
@@ -564,6 +597,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
23 leaked clusters were found on the image.
@@ -583,6 +617,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
11 leaked clusters were found on the image.
@@ -592,6 +627,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
23 leaked clusters were found on the image.
@@ -611,6 +647,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
11 leaked clusters were found on the image.
@@ -620,6 +657,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
23 leaked clusters were found on the image.
@@ -637,6 +675,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_alloc_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -649,6 +688,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_alloc_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -661,6 +701,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_write_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -673,6 +714,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_write_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -685,6 +727,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_activate_table; errno: 5; imm: off; once: off
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
write failed: Input/output error
96 leaked clusters were found on the image.
@@ -699,6 +742,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow_activate_table; errno: 28; imm: off; once: off
Failed to flush the L2 table cache: No space left on device
Failed to flush the refcount block cache: No space left on device
+Could not update qcow2 header: No space left on device
write failed: No space left on device
96 leaked clusters were found on the image.
@@ -117,7 +117,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
Header extension:
@@ -150,7 +150,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
Header extension:
@@ -164,7 +164,7 @@ No errors were found on the image.
magic 0x514649fb
version 3
-backing_file_offset 0x148
+backing_file_offset 0x178
backing_file_size 0x17
cluster_bits 16
size 67108864
@@ -188,7 +188,7 @@ data 'host_device'
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
Header extension:
@@ -58,7 +58,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
@@ -86,7 +86,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
*** done
@@ -86,7 +86,7 @@ $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
echo
echo "== Repairing the image file must succeed =="
-_check_test_img -r all
+_check_test_img -r all --force
# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -109,7 +109,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" \
# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
-$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "open -o override-lock=on $TEST_IMG" -c "write 0 512" | _filter_qemu_io
# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -61,6 +61,7 @@ IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IMG force-unlock "$TEST_IMG"
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
@@ -95,6 +96,7 @@ IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IMG force-unlock "$TEST_IMG"
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
@@ -26,7 +26,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
magic 0x514649fb
@@ -76,14 +76,14 @@ refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
incompatible_features 0x1
-compatible_features 0x1
+compatible_features 0x3
autoclear_features 0x0
refcount_order 4
header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
ERROR cluster 5 refcount=0 reference=1
@@ -138,7 +138,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
magic 0x514649fb
@@ -207,7 +207,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
read 65536/65536 bytes at offset 44040192
@@ -238,14 +238,14 @@ refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
incompatible_features 0x1
-compatible_features 0x1
+compatible_features 0x3
autoclear_features 0x0
refcount_order 4
header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
ERROR cluster 5 refcount=0 reference=1
@@ -274,7 +274,7 @@ header_length 104
Header extension:
magic 0x6803f857
-length 144
+length 192
data <binary>
read 131072/131072 bytes at offset 0
@@ -85,6 +85,7 @@ $QEMU_IO -c 'write -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \
-c 'read -P 42 0 512' | _filter_qemu_io
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkdebug through filename ==="
@@ -92,6 +93,7 @@ echo
$QEMU_IO -c "open -o file.driver=blkdebug,file.inject-error.event=l2_load $TEST_IMG" \
-c 'read -P 42 0x38000 512'
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkdebug through file blockref ==="
@@ -99,6 +101,7 @@ echo
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.inject-error.event=l2_load,file.image.filename=$TEST_IMG" \
-c 'read -P 42 0x38000 512'
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkdebug on existing block device ==="
@@ -137,6 +140,7 @@ run_qemu <<EOF
}
{ "execute": "quit" }
EOF
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkverify on existing block device ==="
@@ -176,6 +180,7 @@ run_qemu <<EOF
}
{ "execute": "quit" }
EOF
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkverify on existing raw block device ==="
@@ -215,6 +220,7 @@ run_qemu <<EOF
}
{ "execute": "quit" }
EOF
+$QEMU_IMG force-unlock "$TEST_IMG"
echo
echo "=== Testing blkdebug's set-state through QMP ==="
@@ -268,6 +274,7 @@ run_qemu <<EOF
}
{ "execute": "quit" }
EOF
+$QEMU_IMG force-unlock "$TEST_IMG"
# success, all done
echo "*** done"
@@ -32,12 +32,14 @@ blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
read failed: Input/output error
=== Testing blkdebug through file blockref ===
Failed to flush the L2 table cache: Input/output error
Failed to flush the refcount block cache: Input/output error
+Could not update qcow2 header: Input/output error
read failed: Input/output error
=== Testing blkdebug on existing block device ===
@@ -53,6 +55,7 @@ read failed: Input/output error
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
+QEMU_PROG: Could not update qcow2 header: Input/output error
=== Testing blkverify on existing block device ===
@@ -94,5 +97,6 @@ read failed: Input/output error
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
+QEMU_PROG: Could not update qcow2 header: Input/output error
*** done
@@ -94,7 +94,7 @@ $QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
# the same (which they should).
-$QEMU_IO_PROG --cache $CACHEMODE \
+$QEMU_IO_PROG -r --cache $CACHEMODE \
-c 'read -P 42 0x38000 512' "json:{
\"driver\": \"$IMGFMT\",
\"file\": {
@@ -24,8 +24,6 @@ read 512/512 bytes at offset 0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Failed to flush the L2 table cache: Input/output error
-Failed to flush the refcount block cache: Input/output error
read failed: Input/output error
=== Testing qemu-img info output ===
@@ -97,7 +97,7 @@ _send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)"
_send_qemu_cmd $h2 'quit' ""
echo "Check image pattern"
-${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
+${QEMU_IO} -r -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
echo "Running 'qemu-img check -r all \$TEST_IMG'"
"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu
@@ -67,7 +67,7 @@ $QEMU_IMG commit "blkdebug:$TEST_DIR/blkdebug.conf:$TEST_IMG" 2>&1 \
| _filter_testdir | _filter_imgfmt
# There may be errors, but they should be fixed by opening the image
-$QEMU_IO -c close "$TEST_IMG"
+$QEMU_IO -c "open -o override-lock=on $TEST_IMG" -c close
_check_test_img
People have been keeping destroying their qcow2 images by using 'qemu-img snapshot' on images that were in use by a VM. This patch adds some image locking that protects them against this mistake. In order to achieve this, a new compatible header flag is introduced that tells that the image is currently in use. It is (almost) always set when qcow2 considers the image to be active and in a read-write mode. During live migration, the source considers the image active until the VM stops on migration completion. The destination considers it active as soon as it starts running the VM. In cases where qemu wasn't shut down cleanly, images may incorrectly refuse to open. An option override-lock=on is provided to force opening the image (this is the option that qemu-img uses for 'force-unlock' and 'check --force'). A few test cases have to be adjusted, either to update error messages, to use read-only mode to avoid the check, or to override the lock where necessary. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/qcow2.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.h | 7 +++- docs/specs/qcow2.txt | 7 +++- tests/qemu-iotests/026 | 2 +- tests/qemu-iotests/026.out | 60 ++++++++++++++++++++++++++++----- tests/qemu-iotests/031.out | 8 ++--- tests/qemu-iotests/036.out | 4 +-- tests/qemu-iotests/039 | 4 +-- tests/qemu-iotests/061 | 2 ++ tests/qemu-iotests/061.out | 16 ++++----- tests/qemu-iotests/071 | 7 ++++ tests/qemu-iotests/071.out | 4 +++ tests/qemu-iotests/089 | 2 +- tests/qemu-iotests/089.out | 2 -- tests/qemu-iotests/091 | 2 +- tests/qemu-iotests/098 | 2 +- 16 files changed, 181 insertions(+), 32 deletions(-)