qcow2: introduce dirty bit
This patch adds an incompatible feature bit to mark images that have not been closed cleanly. When a dirty image file is opened a consistency check and repair is performed. Update qemu-iotests 031 and 036 since the extension header size changes when we add feature bit table entries. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
0f6d767aa8
commit
c61d0004bc
@ -214,6 +214,27 @@ static void report_unsupported_feature(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clears the dirty bit and flushes before if necessary. Only call this
|
||||||
|
* function when there are no pending requests, it does not guard against
|
||||||
|
* concurrent requests dirtying the image.
|
||||||
|
*/
|
||||||
|
static int qcow2_mark_clean(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
|
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
||||||
|
int ret = bdrv_flush(bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
||||||
|
return qcow2_update_header(bs);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int qcow2_open(BlockDriverState *bs, int flags)
|
static int qcow2_open(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@ -287,12 +308,13 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
|||||||
s->compatible_features = header.compatible_features;
|
s->compatible_features = header.compatible_features;
|
||||||
s->autoclear_features = header.autoclear_features;
|
s->autoclear_features = header.autoclear_features;
|
||||||
|
|
||||||
if (s->incompatible_features != 0) {
|
if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) {
|
||||||
void *feature_table = NULL;
|
void *feature_table = NULL;
|
||||||
qcow2_read_extensions(bs, header.header_length, ext_end,
|
qcow2_read_extensions(bs, header.header_length, ext_end,
|
||||||
&feature_table);
|
&feature_table);
|
||||||
report_unsupported_feature(bs, feature_table,
|
report_unsupported_feature(bs, feature_table,
|
||||||
s->incompatible_features);
|
s->incompatible_features &
|
||||||
|
~QCOW2_INCOMPAT_MASK);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -412,6 +434,22 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
|||||||
/* Initialise locks */
|
/* Initialise locks */
|
||||||
qemu_co_mutex_init(&s->lock);
|
qemu_co_mutex_init(&s->lock);
|
||||||
|
|
||||||
|
/* Repair image if dirty */
|
||||||
|
if ((s->incompatible_features & QCOW2_INCOMPAT_DIRTY) &&
|
||||||
|
!bs->read_only) {
|
||||||
|
BdrvCheckResult result = {0};
|
||||||
|
|
||||||
|
ret = qcow2_check_refcounts(bs, &result, BDRV_FIX_ERRORS);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcow2_mark_clean(bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
#ifdef DEBUG_ALLOC
|
||||||
{
|
{
|
||||||
BdrvCheckResult result = {0};
|
BdrvCheckResult result = {0};
|
||||||
@ -785,6 +823,8 @@ static void qcow2_close(BlockDriverState *bs)
|
|||||||
qcow2_cache_flush(bs, s->l2_table_cache);
|
qcow2_cache_flush(bs, s->l2_table_cache);
|
||||||
qcow2_cache_flush(bs, s->refcount_block_cache);
|
qcow2_cache_flush(bs, s->refcount_block_cache);
|
||||||
|
|
||||||
|
qcow2_mark_clean(bs);
|
||||||
|
|
||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||||
|
|
||||||
@ -949,7 +989,11 @@ int qcow2_update_header(BlockDriverState *bs)
|
|||||||
|
|
||||||
/* Feature table */
|
/* Feature table */
|
||||||
Qcow2Feature features[] = {
|
Qcow2Feature features[] = {
|
||||||
/* no feature defined yet */
|
{
|
||||||
|
.type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
|
||||||
|
.bit = QCOW2_INCOMPAT_DIRTY_BITNR,
|
||||||
|
.name = "dirty bit",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
|
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
|
||||||
|
@ -110,6 +110,14 @@ enum {
|
|||||||
QCOW2_FEAT_TYPE_AUTOCLEAR = 2,
|
QCOW2_FEAT_TYPE_AUTOCLEAR = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Incompatible feature bits */
|
||||||
|
enum {
|
||||||
|
QCOW2_INCOMPAT_DIRTY_BITNR = 0,
|
||||||
|
QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
|
||||||
|
|
||||||
|
QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Qcow2Feature {
|
typedef struct Qcow2Feature {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t bit;
|
uint8_t bit;
|
||||||
|
@ -54,8 +54,8 @@ header_length 72
|
|||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x6803f857
|
magic 0x6803f857
|
||||||
length 0
|
length 48
|
||||||
data ''
|
data <binary>
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
@ -68,7 +68,7 @@ No errors were found on the image.
|
|||||||
|
|
||||||
magic 0x514649fb
|
magic 0x514649fb
|
||||||
version 2
|
version 2
|
||||||
backing_file_offset 0x98
|
backing_file_offset 0xc8
|
||||||
backing_file_size 0x17
|
backing_file_size 0x17
|
||||||
cluster_bits 16
|
cluster_bits 16
|
||||||
size 67108864
|
size 67108864
|
||||||
@ -92,8 +92,8 @@ data 'host_device'
|
|||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x6803f857
|
magic 0x6803f857
|
||||||
length 0
|
length 48
|
||||||
data ''
|
data <binary>
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
@ -155,8 +155,8 @@ header_length 104
|
|||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x6803f857
|
magic 0x6803f857
|
||||||
length 0
|
length 48
|
||||||
data ''
|
data <binary>
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
@ -169,7 +169,7 @@ No errors were found on the image.
|
|||||||
|
|
||||||
magic 0x514649fb
|
magic 0x514649fb
|
||||||
version 3
|
version 3
|
||||||
backing_file_offset 0xb8
|
backing_file_offset 0xe8
|
||||||
backing_file_size 0x17
|
backing_file_size 0x17
|
||||||
cluster_bits 16
|
cluster_bits 16
|
||||||
size 67108864
|
size 67108864
|
||||||
@ -193,8 +193,8 @@ data 'host_device'
|
|||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x6803f857
|
magic 0x6803f857
|
||||||
length 0
|
length 48
|
||||||
data ''
|
data <binary>
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
|
@ -46,7 +46,7 @@ header_length 104
|
|||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x6803f857
|
magic 0x6803f857
|
||||||
length 0
|
length 48
|
||||||
data ''
|
data <binary>
|
||||||
|
|
||||||
*** done
|
*** done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user