From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55971) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z5VSM-0004qk-Gj for qemu-devel@nongnu.org; Thu, 18 Jun 2015 04:45:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z5VSK-00049n-Jk for qemu-devel@nongnu.org; Thu, 18 Jun 2015 04:45:54 -0400 From: Wen Congyang Date: Thu, 18 Jun 2015 16:49:09 +0800 Message-ID: <1434617361-17778-5-git-send-email-wency@cn.fujitsu.com> In-Reply-To: <1434617361-17778-1-git-send-email-wency@cn.fujitsu.com> References: <1434617361-17778-1-git-send-email-wency@cn.fujitsu.com> MIME-Version: 1.0 Content-Type: text/plain Subject: [Qemu-devel] [PATCH COLO-Block v6 04/16] block: Parse "backing_reference" option to reference existing BDS List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu devel , Fam Zheng , Max Reitz , Paolo Bonzini Cc: Kevin Wolf , qemu block , Lai Jiangshan , Jiang Yunhong , Dong Eddie , "Dr. David Alan Gilbert" , Gonglei , Stefan Hajnoczi , Yang Hongyang , zhanghailiang Usage: -drive file=xxx,id=Y, \ -drive file=xxxx,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. Active disk X, hidden disk, and Y are all on the same AioContext. Signed-off-by: Wen Congyang Signed-off-by: zhanghailiang Signed-off-by: Gonglei --- block.c | 154 ++++++++++++++++++++++++++++++++++++++++++++- 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, 179 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index df4cbce..d1ed227 100644 --- a/block.c +++ b/block.c @@ -1245,6 +1245,119 @@ 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; + AioContext *aio_context; + 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_setg(errp, "Device '%s' 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); + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + bdrv_set_aio_context(backing_hd, aio_context); + backup_start(backing_hd, hidden_disk, 0, MIRROR_SYNC_MODE_NONE, NULL, + BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, + backing_reference_completed, hidden_disk, &local_err); + aio_context_release(aio_context); + 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; +} + /* * Opens a disk image whose options are given as BlockdevRef in another block * device's options. @@ -1527,13 +1640,37 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, /* If there is a backing file, use it */ if ((flags & BDRV_O_NO_BACKING) == 0) { - QDict *backing_options; + QDict *backing_options, *backing_reference_options; + qdict_extract_subqdict(options, &backing_reference_options, + "backing_reference."); qdict_extract_subqdict(options, &backing_options, "backing."); - ret = bdrv_open_backing_file(bs, backing_options, &local_err); - if (ret < 0) { + + if (qdict_size(backing_reference_options) && + qdict_size(backing_options)) { + error_setg(&local_err, + "Option \"backing_reference.*\" and \"backing.*\"" + " cannot be used together"); + ret = -EINVAL; + QDECREF(backing_reference_options); + QDECREF(backing_options); goto close_and_fail; } + if (qdict_size(backing_reference_options)) { + QDECREF(backing_options); + ret = bdrv_open_backing_reference_file(bs, + backing_reference_options, + &local_err); + if (ret) { + goto close_and_fail; + } + } else { + QDECREF(backing_reference_options); + ret = bdrv_open_backing_file(bs, backing_options, &local_err); + if (ret < 0) { + goto close_and_fail; + } + } } bdrv_refresh_filename(bs); @@ -1895,6 +2032,14 @@ void bdrv_close(BlockDriverState *bs) if (bs->backing_hd) { BlockDriverState *backing_hd = bs->backing_hd; + if (bs->backing_reference) { + assert(backing_hd->backing_hd); + if (backing_hd->backing_hd->job) { + block_job_cancel(backing_hd->backing_hd->job); + } + bdrv_set_backing_hd(backing_hd, NULL); + bdrv_unref(backing_hd->backing_hd); + } bdrv_set_backing_hd(bs, NULL); bdrv_unref(backing_hd); } @@ -3934,6 +4079,9 @@ void bdrv_attach_aio_context(BlockDriverState *bs, bs->aio_context = new_context; + if (bs->backing_reference) { + bdrv_attach_aio_context(bs->backing_hd->backing_hd, new_context); + } if (bs->backing_hd) { bdrv_attach_aio_context(bs->backing_hd, new_context); } diff --git a/include/block/block.h b/include/block/block.h index 07bb724..7cdb569 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -168,6 +168,7 @@ typedef enum BlockOpType { BLOCK_OP_TYPE_RESIZE, BLOCK_OP_TYPE_STREAM, BLOCK_OP_TYPE_REPLACE, + BLOCK_OP_TYPE_BACKING_REFERENCE, BLOCK_OP_TYPE_MAX, } BlockOpType; diff --git a/include/block/block_int.h b/include/block/block_int.h index 888ec09..87fe89a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -380,6 +380,7 @@ struct BlockDriverState { QDict *full_open_options; char exact_filename[PATH_MAX]; + bool backing_reference; BlockDriverState *backing_hd; BlockDriverState *file; diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 4a8055b..2aa3060 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -116,6 +116,19 @@ run_qemu -drive file="$TEST_IMG",file.backing.driver=file,file.backing.filename= run_qemu -drive file="$TEST_IMG",file.backing.driver=qcow2,file.backing.file.filename="$TEST_IMG.orig" echo +echo === Backing file reference === +echo + +run_qemu -drive file="$TEST_IMG",if=none,id=drive0 \ + -drive file="$TEST_IMG",driver=qcow2,backing_reference.drive_id=drive0,backing_reference.hidden-disk.filename="$TEST_IMG.hidden" + +run_qemu -drive file="$TEST_IMG",if=none,id=drive0 \ + -drive file="$TEST_IMG",driver=qcow2,backing_reference.drive_id=drive0,backing_reference.hidden-disk.filename="$TEST_IMG.hidden",backing.file.filename="$TEST_IMG.orig" + +run_qemu -drive file="$TEST_IMG",if=none,id=drive0 \ + -drive file="$TEST_IMG",driver=qcow2,file.backing_reference.drive_id=drive0,file.backing_reference.hidden-disk.filename="$TEST_IMG.hidden",file.backing.file.filename="$TEST_IMG.orig" + +echo echo === Enable and disable lazy refcounting on the command line, plus some invalid values === echo diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 652dd63..a33d102 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -75,6 +75,19 @@ Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.fil QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files +=== Backing file reference === + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing_reference.drive_id=drive0,backing_reference.hidden-disk.filename=TEST_DIR/t.qcow2.hidden +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing_reference.drive_id=drive0,backing_reference.hidden-disk.filename=TEST_DIR/t.qcow2.hidden,backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing=drive0,backing.file.filename=TEST_DIR/t.qcow2.orig: Option "backing_reference.*" and "backing.*" cannot be used together + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -drive file=TEST_DIR/t.qcow2,driver=qcow2,file.backing_reference.drive_id=drive0,file.backing_reference.hidden-disk.filename=TEST_DIR/t.qcow2.hidden,file.backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,file.backing=drive0,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Option "backing_reference.*" and "backing.*" cannot be used together + + === Enable and disable lazy refcounting on the command line, plus some invalid values === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on -- 2.4.3