Re: [Qemu-block] [RFC PATCH COLO v2 09/13] block: Parse "backing_reference" option to reference existing BDS

2015-03-26 Thread Fam Zheng
On Wed, 03/25 17:36, Wen Congyang wrote:
> Usage:
> -drive file=xxx,id=Y, \
> -drive 
> file=,id=X,backing_reference.drive_id=Y,backing_reference.hidden-disk.*
> 
> It will create such backing chain:
>{virtio-blk dev 'Y'}  
> {virtio-blk dev 'X'}
>  |
>   |
>  |
>   |
>  v
>   v
> 
> [base] <- [mid] <- ( Y )  <- (hidden target) 
> <--- ( X )
> 
>  v  ^
>  v  ^
>  v  ^
>  v  ^
>   drive-backup sync=none 
> 
> X's backing file is hidden-disk, and hidden-disk's backing file is Y.
> Disk Y may be opened or reopened in read-write mode, so A block backup
> job is automatically created: source is Y and target is hidden-disk.
> 
> Signed-off-by: Wen Congyang 
> Signed-off-by: zhanghailiang 
> Signed-off-by: Gonglei 
> ---
>  block.c| 145 
> -
>  include/block/block.h  |   1 +
>  include/block/block_int.h  |   1 +
>  tests/qemu-iotests/051 |  13 
>  tests/qemu-iotests/051.out |  13 
>  5 files changed, 170 insertions(+), 3 deletions(-)
> 
> diff --git a/block.c b/block.c
> index b4d629e..bd7fa9c 100644
> --- a/block.c
> +++ b/block.c
> @@ -1351,6 +1351,113 @@ free_exit:
>  return ret;
>  }
>  
> +static void backing_reference_completed(void *opaque, int ret)
> +{
> +BlockDriverState *hidden_disk = opaque;
> +
> +assert(!hidden_disk->backing_reference);
> +}
> +
> +static int bdrv_open_backing_reference_file(BlockDriverState *bs,
> +QDict *options, Error **errp)
> +{
> +const char *backing_name;
> +QDict *hidden_disk_options = NULL;
> +BlockDriverState *backing_hd, *hidden_disk;
> +BlockBackend *backing_blk;
> +Error *local_err = NULL;
> +int ret = 0;
> +
> +backing_name = qdict_get_try_str(options, "drive_id");
> +if (!backing_name) {
> +error_setg(errp, "Backing reference needs option drive_id");
> +ret = -EINVAL;
> +goto free_exit;
> +}
> +qdict_del(options, "drive_id");
> +
> +qdict_extract_subqdict(options, &hidden_disk_options, "hidden-disk.");
> +if (!qdict_size(hidden_disk_options)) {
> +error_setg(errp, "Backing reference needs option hidden-disk.*");
> +ret = -EINVAL;
> +goto free_exit;
> +}
> +
> +if (qdict_size(options)) {
> +const QDictEntry *entry = qdict_first(options);
> +error_setg(errp, "Backing reference used by '%s' doesn't support "
> +   "the option '%s'", bdrv_get_device_name(bs), entry->key);
> +ret = -EINVAL;
> +goto free_exit;
> +}
> +
> +backing_blk = blk_by_name(backing_name);
> +if (!backing_blk) {
> +error_set(errp, QERR_DEVICE_NOT_FOUND, backing_name);
> +ret = -ENOENT;
> +goto free_exit;
> +}
> +
> +backing_hd = blk_bs(backing_blk);
> +/* Backing reference itself? */
> +if (backing_hd == bs || bdrv_find_overlay(backing_hd, bs)) {
> +error_setg(errp, "Backing reference itself");
> +ret = -EINVAL;
> +goto free_exit;
> +}
> +
> +if (bdrv_op_is_blocked(backing_hd, BLOCK_OP_TYPE_BACKING_REFERENCE,
> +   errp)) {
> +ret = -EBUSY;
> +goto free_exit;
> +}
> +
> +/* hidden-disk is bs's backing file */
> +ret = bdrv_open_backing_file(bs, hidden_disk_options, errp);
> +hidden_disk_options = NULL;
> +if (ret < 0) {
> +goto free_exit;
> +}
> +
> +hidden_disk = bs->backing_hd;
> +if (!hidden_disk->drv || !hidden_disk->drv->supports_backing) {
> +ret = -EINVAL;
> +error_setg(errp, "Hidden disk's driver doesn't support backing 
> files");
> +goto free_exit;
> +}
> +
> +bdrv_set_backing_hd(hidden_disk, backing_hd);
> +bdrv_ref(backing_hd);
> +
> +/*
> + * backing hd may be opened or reopened in read-write mode, so we
> + * should backup backing hd to hidden disk
> + */
> +bdrv_op_unblock(hidden_disk, BLOCK_OP_TYPE_BACKUP_TARGET,
> +bs->backing_blocker);
> +bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
> +hidden_disk->backing_blocker);
> +
> +bdrv_ref(hidden_disk);
> +backup_start(backing_hd, hidden_disk, 0, MIRROR_SYNC_MODE_NONE,
> + BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
> + backing_reference_completed, hidden_disk, &local_err);

We need t

[Qemu-block] [RFC PATCH COLO v2 09/13] block: Parse "backing_reference" option to reference existing BDS

2015-03-25 Thread Wen Congyang
Usage:
-drive file=xxx,id=Y, \
-drive 
file=,id=X,backing_reference.drive_id=Y,backing_reference.hidden-disk.*

It will create such backing chain:
   {virtio-blk dev 'Y'}  
{virtio-blk dev 'X'}
 |  
|
 |  
|
 v  
v

[base] <- [mid] <- ( Y )  <- (hidden target) 
<--- ( X )

 v  ^
 v  ^
 v  ^
 v  ^
  drive-backup sync=none 

X's backing file is hidden-disk, and hidden-disk's backing file is Y.
Disk Y may be opened or reopened in read-write mode, so A block backup
job is automatically created: source is Y and target is hidden-disk.

Signed-off-by: Wen Congyang 
Signed-off-by: zhanghailiang 
Signed-off-by: Gonglei 
---
 block.c| 145 -
 include/block/block.h  |   1 +
 include/block/block_int.h  |   1 +
 tests/qemu-iotests/051 |  13 
 tests/qemu-iotests/051.out |  13 
 5 files changed, 170 insertions(+), 3 deletions(-)

diff --git a/block.c b/block.c
index b4d629e..bd7fa9c 100644
--- a/block.c
+++ b/block.c
@@ -1351,6 +1351,113 @@ free_exit:
 return ret;
 }
 
+static void backing_reference_completed(void *opaque, int ret)
+{
+BlockDriverState *hidden_disk = opaque;
+
+assert(!hidden_disk->backing_reference);
+}
+
+static int bdrv_open_backing_reference_file(BlockDriverState *bs,
+QDict *options, Error **errp)
+{
+const char *backing_name;
+QDict *hidden_disk_options = NULL;
+BlockDriverState *backing_hd, *hidden_disk;
+BlockBackend *backing_blk;
+Error *local_err = NULL;
+int ret = 0;
+
+backing_name = qdict_get_try_str(options, "drive_id");
+if (!backing_name) {
+error_setg(errp, "Backing reference needs option drive_id");
+ret = -EINVAL;
+goto free_exit;
+}
+qdict_del(options, "drive_id");
+
+qdict_extract_subqdict(options, &hidden_disk_options, "hidden-disk.");
+if (!qdict_size(hidden_disk_options)) {
+error_setg(errp, "Backing reference needs option hidden-disk.*");
+ret = -EINVAL;
+goto free_exit;
+}
+
+if (qdict_size(options)) {
+const QDictEntry *entry = qdict_first(options);
+error_setg(errp, "Backing reference used by '%s' doesn't support "
+   "the option '%s'", bdrv_get_device_name(bs), entry->key);
+ret = -EINVAL;
+goto free_exit;
+}
+
+backing_blk = blk_by_name(backing_name);
+if (!backing_blk) {
+error_set(errp, QERR_DEVICE_NOT_FOUND, backing_name);
+ret = -ENOENT;
+goto free_exit;
+}
+
+backing_hd = blk_bs(backing_blk);
+/* Backing reference itself? */
+if (backing_hd == bs || bdrv_find_overlay(backing_hd, bs)) {
+error_setg(errp, "Backing reference itself");
+ret = -EINVAL;
+goto free_exit;
+}
+
+if (bdrv_op_is_blocked(backing_hd, BLOCK_OP_TYPE_BACKING_REFERENCE,
+   errp)) {
+ret = -EBUSY;
+goto free_exit;
+}
+
+/* hidden-disk is bs's backing file */
+ret = bdrv_open_backing_file(bs, hidden_disk_options, errp);
+hidden_disk_options = NULL;
+if (ret < 0) {
+goto free_exit;
+}
+
+hidden_disk = bs->backing_hd;
+if (!hidden_disk->drv || !hidden_disk->drv->supports_backing) {
+ret = -EINVAL;
+error_setg(errp, "Hidden disk's driver doesn't support backing files");
+goto free_exit;
+}
+
+bdrv_set_backing_hd(hidden_disk, backing_hd);
+bdrv_ref(backing_hd);
+
+/*
+ * backing hd may be opened or reopened in read-write mode, so we
+ * should backup backing hd to hidden disk
+ */
+bdrv_op_unblock(hidden_disk, BLOCK_OP_TYPE_BACKUP_TARGET,
+bs->backing_blocker);
+bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
+hidden_disk->backing_blocker);
+
+bdrv_ref(hidden_disk);
+backup_start(backing_hd, hidden_disk, 0, MIRROR_SYNC_MODE_NONE,
+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
+ backing_reference_completed, hidden_disk, &local_err);
+if (local_err) {
+error_propagate(errp, local_err);
+bdrv_unref(hidden_disk);
+/* FIXME, use which errno? */
+ret = -EIO;
+goto free_exit;
+}
+
+bs->backing_reference = true;
+
+free_exit:
+QDECREF(hidden_disk_options);
+QDECREF(options);
+return ret;
+}
+
 /*
  * Ope