[PULL 41/56] block/copy-before-write: make public block driver

Maintainers: Eduardo Habkost <ehabkost@redhat.com>, Wainer dos Santos Moschetta <wainersm@redhat.com>, Thomas Huth <thuth@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Markus Armbruster <armbru@redhat.com>, Kevin Wolf <kwolf@redhat.com>, Eric Blake <eblake@redhat.com>, Cleber Rosa <crosa@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Stefan Weil <sw@weilnetz.de>, John Snow <jsnow@redhat.com>, "Alex Bennée" <alex.bennee@linaro.org>, Willian Rampazzo <willianr@redhat.com>, Hanna Reitz <hreitz@redhat.com>, "Philippe Mathieu-Daudé" <f4bug@amsat.org>, Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
There is a newer version of this series
[PULL 41/56] block/copy-before-write: make public block driver
Posted by Hanna Reitz 3 years, 7 months ago
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

Finally, copy-before-write gets own .bdrv_open and .bdrv_close
handlers, block_init() call and becomes available through bdrv_open().

To achieve this:

 - cbw_init gets unused flags argument and becomes cbw_open
 - block_copy_state_free() call moved to new cbw_close()
 - in bdrv_cbw_append:
   - options are completed with driver and node-name, and we can simply
     use bdrv_insert_node() to do both open and drained replacing
 - in bdrv_cbw_drop:
   - cbw_close() is now responsible for freeing s->bcs, so don't do it
     here

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-Id: <20210824083856.17408-22-vsementsov@virtuozzo.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
 block/copy-before-write.c | 60 ++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/block/copy-before-write.c b/block/copy-before-write.c
index 2efe098aae..2cd68b480a 100644
--- a/block/copy-before-write.c
+++ b/block/copy-before-write.c
@@ -144,7 +144,8 @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
     }
 }
 
-static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp)
+static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
+                    Error **errp)
 {
     BDRVCopyBeforeWriteState *s = bs->opaque;
     BdrvDirtyBitmap *copy_bitmap;
@@ -181,10 +182,21 @@ static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp)
     return 0;
 }
 
+static void cbw_close(BlockDriverState *bs)
+{
+    BDRVCopyBeforeWriteState *s = bs->opaque;
+
+    block_copy_state_free(s->bcs);
+    s->bcs = NULL;
+}
+
 BlockDriver bdrv_cbw_filter = {
     .format_name = "copy-before-write",
     .instance_size = sizeof(BDRVCopyBeforeWriteState),
 
+    .bdrv_open                  = cbw_open,
+    .bdrv_close                 = cbw_close,
+
     .bdrv_co_preadv             = cbw_co_preadv,
     .bdrv_co_pwritev            = cbw_co_pwritev,
     .bdrv_co_pwrite_zeroes      = cbw_co_pwrite_zeroes,
@@ -205,56 +217,40 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
                                   Error **errp)
 {
     ERRP_GUARD();
-    int ret;
     BDRVCopyBeforeWriteState *state;
     BlockDriverState *top;
     QDict *opts;
 
     assert(source->total_sectors == target->total_sectors);
 
-    top = bdrv_new_open_driver(&bdrv_cbw_filter, filter_node_name,
-                               BDRV_O_RDWR, errp);
-    if (!top) {
-        error_prepend(errp, "Cannot open driver: ");
-        return NULL;
-    }
-    state = top->opaque;
-
     opts = qdict_new();
+    qdict_put_str(opts, "driver", "copy-before-write");
+    if (filter_node_name) {
+        qdict_put_str(opts, "node-name", filter_node_name);
+    }
     qdict_put_str(opts, "file", bdrv_get_node_name(source));
     qdict_put_str(opts, "target", bdrv_get_node_name(target));
 
-    ret = cbw_init(top, opts, errp);
-    qobject_unref(opts);
-    if (ret < 0) {
-        goto fail;
-    }
-
-    bdrv_drained_begin(source);
-    ret = bdrv_replace_node(source, top, errp);
-    bdrv_drained_end(source);
-    if (ret < 0) {
-        error_prepend(errp, "Cannot append copy-before-write filter: ");
-        goto fail;
+    top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp);
+    if (!top) {
+        return NULL;
     }
 
+    state = top->opaque;
     *bcs = state->bcs;
 
     return top;
-
-fail:
-    block_copy_state_free(state->bcs);
-    bdrv_unref(top);
-    return NULL;
 }
 
 void bdrv_cbw_drop(BlockDriverState *bs)
 {
-    BDRVCopyBeforeWriteState *s = bs->opaque;
-
     bdrv_drop_filter(bs, &error_abort);
-
-    block_copy_state_free(s->bcs);
-
     bdrv_unref(bs);
 }
+
+static void cbw_init(void)
+{
+    bdrv_register(&bdrv_cbw_filter);
+}
+
+block_init(cbw_init);
-- 
2.31.1


Re: [PULL 41/56] block/copy-before-write: make public block driver
Posted by Kevin Wolf 3 years, 6 months ago
Am 01.09.2021 um 17:16 hat Hanna Reitz geschrieben:
> From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> 
> Finally, copy-before-write gets own .bdrv_open and .bdrv_close
> handlers, block_init() call and becomes available through bdrv_open().
> 
> To achieve this:
> 
>  - cbw_init gets unused flags argument and becomes cbw_open
>  - block_copy_state_free() call moved to new cbw_close()
>  - in bdrv_cbw_append:
>    - options are completed with driver and node-name, and we can simply
>      use bdrv_insert_node() to do both open and drained replacing
>  - in bdrv_cbw_drop:
>    - cbw_close() is now responsible for freeing s->bcs, so don't do it
>      here
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> Message-Id: <20210824083856.17408-22-vsementsov@virtuozzo.com>
> Signed-off-by: Hanna Reitz <hreitz@redhat.com>

This patch results in a change in behaviour that I assume was not
intentional: Previously, creating a backup block job would succeed to
insert the filter node independently of whether the filter driver was
whitelisted or not. After this patch, it becomes an error if the filter
driver isn't explicitly whitelisted:

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

>  block/copy-before-write.c | 60 ++++++++++++++++++---------------------
>  1 file changed, 28 insertions(+), 32 deletions(-)
> 
> diff --git a/block/copy-before-write.c b/block/copy-before-write.c
> index 2efe098aae..2cd68b480a 100644
> --- a/block/copy-before-write.c
> +++ b/block/copy-before-write.c
> @@ -144,7 +144,8 @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
>      }
>  }
>  
> -static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp)
> +static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
> +                    Error **errp)
>  {
>      BDRVCopyBeforeWriteState *s = bs->opaque;
>      BdrvDirtyBitmap *copy_bitmap;
> @@ -181,10 +182,21 @@ static int cbw_init(BlockDriverState *bs, QDict *options, Error **errp)
>      return 0;
>  }
>  
> +static void cbw_close(BlockDriverState *bs)
> +{
> +    BDRVCopyBeforeWriteState *s = bs->opaque;
> +
> +    block_copy_state_free(s->bcs);
> +    s->bcs = NULL;
> +}
> +
>  BlockDriver bdrv_cbw_filter = {
>      .format_name = "copy-before-write",
>      .instance_size = sizeof(BDRVCopyBeforeWriteState),
>  
> +    .bdrv_open                  = cbw_open,
> +    .bdrv_close                 = cbw_close,
> +
>      .bdrv_co_preadv             = cbw_co_preadv,
>      .bdrv_co_pwritev            = cbw_co_pwritev,
>      .bdrv_co_pwrite_zeroes      = cbw_co_pwrite_zeroes,
> @@ -205,56 +217,40 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
>                                    Error **errp)
>  {
>      ERRP_GUARD();
> -    int ret;
>      BDRVCopyBeforeWriteState *state;
>      BlockDriverState *top;
>      QDict *opts;
>  
>      assert(source->total_sectors == target->total_sectors);
>  
> -    top = bdrv_new_open_driver(&bdrv_cbw_filter, filter_node_name,
> -                               BDRV_O_RDWR, errp);

bdrv_new_open_driver() is a relatively short and straightforward code
path that just directly opens a driver for internal use.

> -    if (!top) {
> -        error_prepend(errp, "Cannot open driver: ");
> -        return NULL;
> -    }
> -    state = top->opaque;
> -
>      opts = qdict_new();
> +    qdict_put_str(opts, "driver", "copy-before-write");
> +    if (filter_node_name) {
> +        qdict_put_str(opts, "node-name", filter_node_name);
> +    }
>      qdict_put_str(opts, "file", bdrv_get_node_name(source));
>      qdict_put_str(opts, "target", bdrv_get_node_name(target));
>  
> -    ret = cbw_init(top, opts, errp);
> -    qobject_unref(opts);
> -    if (ret < 0) {
> -        goto fail;
> -    }
> -
> -    bdrv_drained_begin(source);
> -    ret = bdrv_replace_node(source, top, errp);
> -    bdrv_drained_end(source);
> -    if (ret < 0) {
> -        error_prepend(errp, "Cannot append copy-before-write filter: ");
> -        goto fail;
> +    top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp);

On the other hand, bdrv_insert_node() uses bdrv_open() internally, which
is a really long and messy code path that basically has to handle all of
the craziness that compatibility code for -drive needs to have.

Do we really need bdrv_open() here?

Or is all you really need just a version of bdrv_new_open_driver() that
accepts an options QDict instead of just flags?

Kevin


Re: [PULL 41/56] block/copy-before-write: make public block driver
Posted by Vladimir Sementsov-Ogievskiy 3 years, 6 months ago
20.09.2021 12:41, Kevin Wolf wrote:
> Am 01.09.2021 um 17:16 hat Hanna Reitz geschrieben:
>> From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>
>> Finally, copy-before-write gets own .bdrv_open and .bdrv_close
>> handlers, block_init() call and becomes available through bdrv_open().
>>
>> To achieve this:
>>
>>   - cbw_init gets unused flags argument and becomes cbw_open
>>   - block_copy_state_free() call moved to new cbw_close()
>>   - in bdrv_cbw_append:
>>     - options are completed with driver and node-name, and we can simply
>>       use bdrv_insert_node() to do both open and drained replacing
>>   - in bdrv_cbw_drop:
>>     - cbw_close() is now responsible for freeing s->bcs, so don't do it
>>       here
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>> Message-Id: <20210824083856.17408-22-vsementsov@virtuozzo.com>
>> Signed-off-by: Hanna Reitz <hreitz@redhat.com>
> 
> This patch results in a change in behaviour that I assume was not
> intentional: Previously, creating a backup block job would succeed to
> insert the filter node independently of whether the filter driver was
> whitelisted or not. After this patch, it becomes an error if the filter
> driver isn't explicitly whitelisted:
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=2004812

I'm sorry :( Will try to fix that today.

[..]

>> -    ret = bdrv_replace_node(source, top, errp);
>> -    bdrv_drained_end(source);
>> -    if (ret < 0) {
>> -        error_prepend(errp, "Cannot append copy-before-write filter: ");
>> -        goto fail;
>> +    top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp);
> 
> On the other hand, bdrv_insert_node() uses bdrv_open() internally, which
> is a really long and messy code path that basically has to handle all of
> the craziness that compatibility code for -drive needs to have.
> 
> Do we really need bdrv_open() here?
> 
> Or is all you really need just a version of bdrv_new_open_driver() that
> accepts an options QDict instead of just flags?
> 

Yes something like this, to always go through same interface.


-- 
Best regards,
Vladimir