diff mbox

[RFC,2/7] qcow2: introduce dirty bit

Message ID 1340377726-5896-3-git-send-email-stefanha@linux.vnet.ibm.com
State New
Headers show

Commit Message

Stefan Hajnoczi June 22, 2012, 3:08 p.m. UTC
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.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 block/qcow2.c |   44 ++++++++++++++++++++++++++++++++++++++++++--
 block/qcow2.h |    3 +++
 2 files changed, 45 insertions(+), 2 deletions(-)

Comments

Kevin Wolf June 25, 2012, 2:18 p.m. UTC | #1
Am 22.06.2012 17:08, schrieb Stefan Hajnoczi:
> 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.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> ---
>  block/qcow2.c |   44 ++++++++++++++++++++++++++++++++++++++++++--
>  block/qcow2.h |    3 +++
>  2 files changed, 45 insertions(+), 2 deletions(-)

> diff --git a/block/qcow2.h b/block/qcow2.h
> index 455b6d7..5c7cfb6 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -108,6 +108,9 @@ enum {
>      QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
>      QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
>      QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
> +
> +    QCOW2_INCOMPATIBLE_FEAT_DIRTY   = 0x1,
> +    QCOW2_INCOMPATIBLE_FEAT_MASK    = QCOW2_INCOMPATIBLE_FEAT_DIRTY,
>  };

I would use a separate enum for each of the three flag categories.

Also, you should add a feature table entry for the dirty bit so that
older qemu versions can display a useful error message.

Kevin
Stefan Hajnoczi June 25, 2012, 3:51 p.m. UTC | #2
On Mon, Jun 25, 2012 at 3:18 PM, Kevin Wolf <kwolf@redhat.com> wrote:
> Am 22.06.2012 17:08, schrieb Stefan Hajnoczi:
>> 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.
>>
>> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
>> ---
>>  block/qcow2.c |   44 ++++++++++++++++++++++++++++++++++++++++++--
>>  block/qcow2.h |    3 +++
>>  2 files changed, 45 insertions(+), 2 deletions(-)
>
>> diff --git a/block/qcow2.h b/block/qcow2.h
>> index 455b6d7..5c7cfb6 100644
>> --- a/block/qcow2.h
>> +++ b/block/qcow2.h
>> @@ -108,6 +108,9 @@ enum {
>>      QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
>>      QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
>>      QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
>> +
>> +    QCOW2_INCOMPATIBLE_FEAT_DIRTY   = 0x1,
>> +    QCOW2_INCOMPATIBLE_FEAT_MASK    = QCOW2_INCOMPATIBLE_FEAT_DIRTY,
>>  };
>
> I would use a separate enum for each of the three flag categories.
>
> Also, you should add a feature table entry for the dirty bit so that
> older qemu versions can display a useful error message.

Good point, I forgot to do this.

Stefan
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index 2c1cd0a..cc30784 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -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_INCOMPATIBLE_FEAT_DIRTY) {
+        int ret = bdrv_flush(bs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        s->incompatible_features &= ~QCOW2_INCOMPATIBLE_FEAT_DIRTY;
+        return qcow2_update_header(bs);
+    }
+    return 0;
+}
+
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
@@ -287,12 +308,13 @@  static int qcow2_open(BlockDriverState *bs, int flags)
     s->compatible_features      = header.compatible_features;
     s->autoclear_features       = header.autoclear_features;
 
-    if (s->incompatible_features != 0) {
+    if (s->incompatible_features & ~QCOW2_INCOMPATIBLE_FEAT_MASK) {
         void *feature_table = NULL;
         qcow2_read_extensions(bs, header.header_length, ext_end,
                               &feature_table);
         report_unsupported_feature(bs, feature_table,
-                                   s->incompatible_features);
+                                   s->incompatible_features &
+                                   ~QCOW2_INCOMPATIBLE_FEAT_MASK);
         ret = -ENOTSUP;
         goto fail;
     }
@@ -412,6 +434,22 @@  static int qcow2_open(BlockDriverState *bs, int flags)
     /* Initialise locks */
     qemu_co_mutex_init(&s->lock);
 
+    /* Repair image if dirty */
+    if ((s->incompatible_features & QCOW2_INCOMPATIBLE_FEAT_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
     {
         BdrvCheckResult result = {0};
@@ -788,6 +826,8 @@  static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_flush(bs, s->l2_table_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->refcount_block_cache);
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 455b6d7..5c7cfb6 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -108,6 +108,9 @@  enum {
     QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
     QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
     QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
+
+    QCOW2_INCOMPATIBLE_FEAT_DIRTY   = 0x1,
+    QCOW2_INCOMPATIBLE_FEAT_MASK    = QCOW2_INCOMPATIBLE_FEAT_DIRTY,
 };
 
 typedef struct Qcow2Feature {