diff mbox

[2/3] qcow2: Always execute preallocate() in a coroutine

Message ID 20171009215533.12530-3-mreitz@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Max Reitz Oct. 9, 2017, 9:55 p.m. UTC
Some qcow2 functions (at least perform_cow()) expect s->lock to be
taken.  Therefore, if we want to make use of them, we should execute
preallocate() (as "preallocate_co") in a coroutine so that we can use
the qemu_co_mutex_* functions.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

Comments

Max Reitz Oct. 9, 2017, 9:57 p.m. UTC | #1
On 2017-10-09 23:55, Max Reitz wrote:
> Some qcow2 functions (at least perform_cow()) expect s->lock to be
> taken.  Therefore, if we want to make use of them, we should execute
> preallocate() (as "preallocate_co") in a coroutine so that we can use
> the qemu_co_mutex_* functions.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
>  1 file changed, 34 insertions(+), 7 deletions(-)

Cc: qemu-stable@nongnu.org
Eric Blake Oct. 9, 2017, 10:28 p.m. UTC | #2
On 10/09/2017 04:55 PM, Max Reitz wrote:
> Some qcow2 functions (at least perform_cow()) expect s->lock to be
> taken.  Therefore, if we want to make use of them, we should execute
> preallocate() (as "preallocate_co") in a coroutine so that we can use
> the qemu_co_mutex_* functions.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
>  1 file changed, 34 insertions(+), 7 deletions(-)
> 

> +++ b/block/qcow2.c
> @@ -2460,6 +2460,14 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
>  }
>  
>  
> +typedef struct PreallocCo {
> +    BlockDriverState *bs;
> +    uint64_t offset;
> +    uint64_t new_length;
> +
> +    int ret;
> +} PreallocCo;

Because you create a typedef here...


> +static void coroutine_fn preallocate_co(void *opaque)
>  {
> +    struct PreallocCo *params = opaque;

you could drop 'struct' here, the way you already dropped it...

> +static int preallocate(BlockDriverState *bs,
> +                       uint64_t offset, uint64_t new_length)
> +{
> +    PreallocCo params = {
> +        .bs         = bs,
> +        .offset     = offset,
> +        .new_length = new_length,
> +        .ret        = -EINPROGRESS,
> +    };

...here.  But that doesn't change semantics, so either way,

Reviewed-by: Eric Blake <eblake@redhat.com>
Jeff Cody Oct. 9, 2017, 11:30 p.m. UTC | #3
On Mon, Oct 09, 2017 at 11:55:32PM +0200, Max Reitz wrote:
> Some qcow2 functions (at least perform_cow()) expect s->lock to be
> taken.  Therefore, if we want to make use of them, we should execute
> preallocate() (as "preallocate_co") in a coroutine so that we can use
> the qemu_co_mutex_* functions.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>

Reviewed-by: Jeff Cody <jcody@redhat.com>

> ---
>  block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
>  1 file changed, 34 insertions(+), 7 deletions(-)
> 
> diff --git a/block/qcow2.c b/block/qcow2.c
> index c3b312cdef..cc75a5167f 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -2460,6 +2460,14 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
>  }
>  
>  
> +typedef struct PreallocCo {
> +    BlockDriverState *bs;
> +    uint64_t offset;
> +    uint64_t new_length;
> +
> +    int ret;
> +} PreallocCo;
> +
>  /**
>   * Preallocates metadata structures for data clusters between @offset (in the
>   * guest disk) and @new_length (which is thus generally the new guest disk
> @@ -2467,9 +2475,12 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
>   *
>   * Returns: 0 on success, -errno on failure.
>   */
> -static int preallocate(BlockDriverState *bs,
> -                       uint64_t offset, uint64_t new_length)
> +static void coroutine_fn preallocate_co(void *opaque)
>  {
> +    struct PreallocCo *params = opaque;
> +    BlockDriverState *bs = params->bs;
> +    uint64_t offset = params->offset;
> +    uint64_t new_length = params->new_length;
>      BDRVQcow2State *s = bs->opaque;
>      uint64_t bytes;
>      uint64_t host_offset = 0;
> @@ -2477,9 +2488,7 @@ static int preallocate(BlockDriverState *bs,
>      int ret;
>      QCowL2Meta *meta;
>  
> -    if (qemu_in_coroutine()) {
> -        qemu_co_mutex_lock(&s->lock);
> -    }
> +    qemu_co_mutex_lock(&s->lock);
>  
>      assert(offset <= new_length);
>      bytes = new_length - offset;
> @@ -2533,10 +2542,28 @@ static int preallocate(BlockDriverState *bs,
>      ret = 0;
>  
>  done:
> +    qemu_co_mutex_unlock(&s->lock);
> +    params->ret = ret;
> +}
> +
> +static int preallocate(BlockDriverState *bs,
> +                       uint64_t offset, uint64_t new_length)
> +{
> +    PreallocCo params = {
> +        .bs         = bs,
> +        .offset     = offset,
> +        .new_length = new_length,
> +        .ret        = -EINPROGRESS,
> +    };
> +
>      if (qemu_in_coroutine()) {
> -        qemu_co_mutex_unlock(&s->lock);
> +        preallocate_co(&params);
> +    } else {
> +        Coroutine *co = qemu_coroutine_create(preallocate_co, &params);
> +        bdrv_coroutine_enter(bs, co);
> +        BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS);
>      }
> -    return ret;
> +    return params.ret;
>  }
>  
>  /* qcow2_refcount_metadata_size:
> -- 
> 2.13.6
> 
>
Max Reitz Oct. 11, 2017, 11:31 a.m. UTC | #4
On 2017-10-10 00:28, Eric Blake wrote:
> On 10/09/2017 04:55 PM, Max Reitz wrote:
>> Some qcow2 functions (at least perform_cow()) expect s->lock to be
>> taken.  Therefore, if we want to make use of them, we should execute
>> preallocate() (as "preallocate_co") in a coroutine so that we can use
>> the qemu_co_mutex_* functions.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>  block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++-------
>>  1 file changed, 34 insertions(+), 7 deletions(-)
>>
> 
>> +++ b/block/qcow2.c
>> @@ -2460,6 +2460,14 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
>>  }
>>  
>>  
>> +typedef struct PreallocCo {
>> +    BlockDriverState *bs;
>> +    uint64_t offset;
>> +    uint64_t new_length;
>> +
>> +    int ret;
>> +} PreallocCo;
> 
> Because you create a typedef here...
> 
> 
>> +static void coroutine_fn preallocate_co(void *opaque)
>>  {
>> +    struct PreallocCo *params = opaque;
> 
> you could drop 'struct' here, the way you already dropped it...

Ah, yes, that was from before I added the typedef...  Will fix.

Max

> 
>> +static int preallocate(BlockDriverState *bs,
>> +                       uint64_t offset, uint64_t new_length)
>> +{
>> +    PreallocCo params = {
>> +        .bs         = bs,
>> +        .offset     = offset,
>> +        .new_length = new_length,
>> +        .ret        = -EINPROGRESS,
>> +    };
> 
> ...here.  But that doesn't change semantics, so either way,
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index c3b312cdef..cc75a5167f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2460,6 +2460,14 @@  static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
 }
 
 
+typedef struct PreallocCo {
+    BlockDriverState *bs;
+    uint64_t offset;
+    uint64_t new_length;
+
+    int ret;
+} PreallocCo;
+
 /**
  * Preallocates metadata structures for data clusters between @offset (in the
  * guest disk) and @new_length (which is thus generally the new guest disk
@@ -2467,9 +2475,12 @@  static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
  *
  * Returns: 0 on success, -errno on failure.
  */
-static int preallocate(BlockDriverState *bs,
-                       uint64_t offset, uint64_t new_length)
+static void coroutine_fn preallocate_co(void *opaque)
 {
+    struct PreallocCo *params = opaque;
+    BlockDriverState *bs = params->bs;
+    uint64_t offset = params->offset;
+    uint64_t new_length = params->new_length;
     BDRVQcow2State *s = bs->opaque;
     uint64_t bytes;
     uint64_t host_offset = 0;
@@ -2477,9 +2488,7 @@  static int preallocate(BlockDriverState *bs,
     int ret;
     QCowL2Meta *meta;
 
-    if (qemu_in_coroutine()) {
-        qemu_co_mutex_lock(&s->lock);
-    }
+    qemu_co_mutex_lock(&s->lock);
 
     assert(offset <= new_length);
     bytes = new_length - offset;
@@ -2533,10 +2542,28 @@  static int preallocate(BlockDriverState *bs,
     ret = 0;
 
 done:
+    qemu_co_mutex_unlock(&s->lock);
+    params->ret = ret;
+}
+
+static int preallocate(BlockDriverState *bs,
+                       uint64_t offset, uint64_t new_length)
+{
+    PreallocCo params = {
+        .bs         = bs,
+        .offset     = offset,
+        .new_length = new_length,
+        .ret        = -EINPROGRESS,
+    };
+
     if (qemu_in_coroutine()) {
-        qemu_co_mutex_unlock(&s->lock);
+        preallocate_co(&params);
+    } else {
+        Coroutine *co = qemu_coroutine_create(preallocate_co, &params);
+        bdrv_coroutine_enter(bs, co);
+        BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS);
     }
-    return ret;
+    return params.ret;
 }
 
 /* qcow2_refcount_metadata_size: