diff mbox

qcow2: Handle EAGAIN returned from update_refcount

Message ID 1435122325-13478-1-git-send-email-makovick@gmail.com
State New
Headers show

Commit Message

Jindřich Makovička June 24, 2015, 5:05 a.m. UTC
Fixes a crash during image compression

Signed-off-by: Jindřich Makovička <makovick@gmail.com>
---
 block/qcow2-refcount.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

Comments

Cole Robinson June 24, 2015, 2:15 p.m. UTC | #1
On 06/24/2015 01:05 AM, Jindřich Makovička wrote:
> Fixes a crash during image compression
> 
> Signed-off-by: Jindřich Makovička <makovick@gmail.com>
> ---
>  block/qcow2-refcount.c | 22 ++++++++++++----------
>  1 file changed, 12 insertions(+), 10 deletions(-)
> 

Rich Jones already confirmed that this patch fixes a bug he can reliably
reproduce:

https://bugzilla.redhat.com/show_bug.cgi?id=1214855

- Cole

> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index 0632fc3..b0ee42d 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -940,19 +940,21 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
>      }
>  
>      free_in_cluster = s->cluster_size - offset_into_cluster(s, offset);
> -    if (!offset || free_in_cluster < size) {
> -        int64_t new_cluster = alloc_clusters_noref(bs, s->cluster_size);
> -        if (new_cluster < 0) {
> -            return new_cluster;
> -        }
> +    do {
> +        if (!offset || free_in_cluster < size) {
> +            int64_t new_cluster = alloc_clusters_noref(bs, s->cluster_size);
> +            if (new_cluster < 0) {
> +                return new_cluster;
> +            }
>  
> -        if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
> -            offset = new_cluster;
> +            if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
> +                offset = new_cluster;
> +            }
>          }
> -    }
>  
> -    assert(offset);
> -    ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
> +        assert(offset);
> +        ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
> +    } while (ret == -EAGAIN);
>      if (ret < 0) {
>          return ret;
>      }
>
Richard W.M. Jones June 24, 2015, 2:22 p.m. UTC | #2
On Wed, Jun 24, 2015 at 10:15:21AM -0400, Cole Robinson wrote:
> On 06/24/2015 01:05 AM, Jindřich Makovička wrote:
> > Fixes a crash during image compression
> > 
> > Signed-off-by: Jindřich Makovička <makovick@gmail.com>
> > ---
> >  block/qcow2-refcount.c | 22 ++++++++++++----------
> >  1 file changed, 12 insertions(+), 10 deletions(-)
> > 
> 
> Rich Jones already confirmed that this patch fixes a bug he can reliably
> reproduce:
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=1214855

Confirmed.  You can add

  Tested-by: Richard W.M. Jones <rjones@redhat.com>

to this patch.

Also note that if you view the patch without whitespace changes
(eg. git diff -b) then it's actually quite simple.

Rich.
Max Reitz June 24, 2015, 3:26 p.m. UTC | #3
On 24.06.2015 07:05, Jindřich Makovička wrote:
> Fixes a crash during image compression
>
> Signed-off-by: Jindřich Makovička <makovick@gmail.com>
> ---
>   block/qcow2-refcount.c | 22 ++++++++++++----------
>   1 file changed, 12 insertions(+), 10 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>
diff mbox

Patch

diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 0632fc3..b0ee42d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -940,19 +940,21 @@  int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
     }
 
     free_in_cluster = s->cluster_size - offset_into_cluster(s, offset);
-    if (!offset || free_in_cluster < size) {
-        int64_t new_cluster = alloc_clusters_noref(bs, s->cluster_size);
-        if (new_cluster < 0) {
-            return new_cluster;
-        }
+    do {
+        if (!offset || free_in_cluster < size) {
+            int64_t new_cluster = alloc_clusters_noref(bs, s->cluster_size);
+            if (new_cluster < 0) {
+                return new_cluster;
+            }
 
-        if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
-            offset = new_cluster;
+            if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
+                offset = new_cluster;
+            }
         }
-    }
 
-    assert(offset);
-    ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
+        assert(offset);
+        ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
+    } while (ret == -EAGAIN);
     if (ret < 0) {
         return ret;
     }