* [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD
@ 2013-11-26 4:05 Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum Fam Zheng
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
This series adds for point-in-time snapshot NBD exporting based on
blockdev-backup (variant of drive-backup with existing device as target).
We get a thin point-in-time snapshot by COW mechanism of drive-backup, and
export it through built in NBD server. The steps are as below:
1. (SHELL) qemu-img create -f qcow2 BACKUP.qcow2 <source size here>
(Alternatively we can use -o backing_file=RUNNING-VM.img to omit explicitly
providing the size by ourselves, but it's risky because RUNNING-VM.qcow2 is
used r/w by guest. Whether or not setting backing file in the image file
doesn't matter, as we are going to override the backing hd in the next
step)
2. (QMP) blockdev-add backing=source-drive file.driver=file file.filename=BACKUP.qcow2 id=target0 if=none driver=qcow2
(where ide0-hd0 is the running BlockDriverState name for
RUNNING-VM.img. This patch implements "backing=" option to override
backing_hd for added drive)
3. (QMP) blockdev-backup device=source-drive sync=none target=target0
(this is the QMP command introduced by this series, which use a named
device as target of drive-backup)
4. (QMP) nbd-server-add device=target0
When image fleecing done:
1. (QMP) block-job-complete device=ide0-hd0
2. (HMP) drive_del target0
3. (SHELL) rm BACKUP.qcow2
v5: Address reviewer comments:
[01/07] qapi: Add BlockOperationType enum
Add comments for types. (Eric)
Remove "nbd-server-add", "passwd" and "set-io-throttle".
[02/07] block: Introduce op_blockers to BlockDriverState
Fix wording of commit message. (Kevin)
Fix spacing and compiler error for assertion. (Kevin)
Allow NULL errp in bdrv_op_is_blocked. (Stefan)
[03/07] block: Replace in_use with operation blocker
Separate "source" and "target" for backup operation check. (Kevin)
[04/07] block: Add checks of blocker in block operations
Removed checks for nbd, passwd and throttle. (Paolo)
[05/07] block: Parse "backing" option to reference existing BDS
Moved backing reference code to bdrv_open_backing_file. (Kevin)
Unblock and free blocker in bdrv_close unconditionally. (Kevin)
[06/07] qmp: add command 'blockdev-backup'
Check op blocker before creating target in qmp_drive_backup.
Fix "." in EOL. (Eric)
Fix (Since 1.8). (Eric)
Fix comment indent, remove "mode" in hmp-commands.hx. (Kevin)
[07/07] block: Allow backup on referenced named BlockDriverState
Only allow "source" on backing referenced BDS. (Kevin)
Experimental for reviewers: the side by side diff against previous series:
http://goo.gl/x6s2cI
v4: Dropping RFC, this series tries to address the crashing cases with an added
safety mechanics.
In the first half of series, replace the in_use flag with an operation
blocker list, and block all operations on named backing hd:
[01/07] qapi: Add BlockOperationType enum
[02/07] block: Introduce op_blockers to BlockDriverState
[03/07] block: Replace in_use with operation blocker
[04/07] block: Add checks of blocker in block operations
The second half enables point in time snapshot over NBD, with fixes from
last revision:
[05/07] block: Parse "backing" option to reference existing BDS
Fix NULL dereference if device not found.
[06/07] qmp: add command 'blockdev-backup'
Moved some checks into backup_run. (Paolo)
[07/07] block: Allow backup on referenced named BlockDriverState
New. Removes one specific blocker on backing referenced BDS, so we
can start a backup job on it.
Fam Zheng (7):
qapi: Add BlockOperationType enum
block: Introduce op_blockers to BlockDriverState
block: Replace in_use with operation blocker
block: Add checks of blocker in block operations
block: Parse "backing" option to reference existing BDS
qmp: add command 'blockdev-backup'
block: Allow backup on referenced named BlockDriverState
block-migration.c | 8 ++-
block.c | 120 +++++++++++++++++++++++++++++++++++-----
block/backup.c | 21 +++++++
block/mirror.c | 2 +-
blockdev.c | 93 +++++++++++++++++++++++++++----
blockjob.c | 12 ++--
hw/block/dataplane/virtio-blk.c | 16 ++++--
include/block/block.h | 11 +++-
include/block/block_int.h | 9 ++-
include/block/blockjob.h | 3 +
qapi-schema.json | 98 ++++++++++++++++++++++++++++++++
qmp-commands.hx | 44 +++++++++++++++
12 files changed, 395 insertions(+), 42 deletions(-)
--
1.8.4.2
^ permalink raw reply [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 16:21 ` Paolo Bonzini
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 2/7] block: Introduce op_blockers to BlockDriverState Fam Zheng
` (5 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
This adds the enum of all the operations that can be taken on a block
device.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
qapi-schema.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/qapi-schema.json b/qapi-schema.json
index 83fa485..c9e513c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1440,6 +1440,55 @@
'data': ['commit', 'stream', 'mirror', 'backup'] }
##
+# @BlockOperationType
+# Type of a block operation. (since 1.8)
+#
+# @backup-source: As a backup source. See the 'drive-backup' command.
+#
+# @backup-target: As a backup target. See the 'drive-backup' command.
+#
+# @change: See the 'change' command.
+#
+# @commit: See the 'block-commi' command.
+#
+# @dataplane: The virtio-blk dataplane feature.
+#
+# @drive-del: See the 'drive_del' HMP command.
+#
+# @eject: See the 'eject' command.
+#
+# @external-snapshot: See the 'blockdev-snapshot-sync' command.
+#
+# @internal-snapshot: See the 'blockdev-snapshot-internal-sync' command.
+#
+# @internal-snapshot-delete: See the 'blockdev-snapshot-delete-internal-sync' command.
+#
+# @mirror: See the 'drive-mirror' command.
+#
+# @resize: See the 'block-resize' command.
+#
+# @stream: See the 'block-stream' command.
+#
+# Since: 1.8
+##
+{ 'enum': 'BlockOpType',
+ 'data': [
+ 'backup-source',
+ 'backup-target',
+ 'change',
+ 'commit',
+ 'dataplane',
+ 'drive-del',
+ 'eject',
+ 'external-snapshot',
+ 'internal-snapshot',
+ 'internal-snapshot-delete',
+ 'mirror',
+ 'resize',
+ 'stream'
+] }
+
+##
# @BlockJobInfo:
#
# Information about a long-running block device operation.
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 2/7] block: Introduce op_blockers to BlockDriverState
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 3/7] block: Replace in_use with operation blocker Fam Zheng
` (4 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
BlockDriverState.op_blockers is an array of lists with BLOCK_OP_TYPE_MAX
elements. Each list is a list of blockers of an operation type
(BlockOpType), that marks this BDS as currently blocked for a certain
type of operation with reason errors stored in the list. The rule of
usage is:
* BDS user who wants to take an operation should check if there's any
blocker of the type with bdrv_op_is_blocked().
* BDS user who wants to block certain types of operation, should call
bdrv_op_block (or bdrv_op_block_all to block all types of operations,
which is similar to bdrv_set_in_use of now).
* A blocker is only referenced by op_blockers, so the lifecycle is
managed by caller, and shouldn't be lost until unblock, so typically
a caller does these:
- Allocate a blocker with error_setg or similar, call bdrv_op_block()
to block some operations.
- Hold the blocker, do his job.
- Unblock operations that it blocked, with the same reason pointer
passed to bdrv_op_unblock().
- Release the blocker with error_free().
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++
include/block/block.h | 6 +++++
include/block/block_int.h | 5 +++++
3 files changed, 68 insertions(+)
diff --git a/block.c b/block.c
index 382ea71..45410ef 100644
--- a/block.c
+++ b/block.c
@@ -4425,6 +4425,63 @@ void bdrv_unref(BlockDriverState *bs)
}
}
+struct BdrvOpBlocker {
+ Error *reason;
+ QLIST_ENTRY(BdrvOpBlocker) list;
+};
+
+bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
+{
+ BdrvOpBlocker *blocker;
+ assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+ if (!QLIST_EMPTY(&bs->op_blockers[op])) {
+ blocker = QLIST_FIRST(&bs->op_blockers[op]);
+ if (errp) {
+ *errp = error_copy(blocker->reason);
+ }
+ return true;
+ }
+ return false;
+}
+
+void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason)
+{
+ BdrvOpBlocker *blocker;
+ assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+
+ blocker = g_malloc0(sizeof(BdrvOpBlocker));
+ blocker->reason = reason;
+ QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list);
+}
+
+void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason)
+{
+ BdrvOpBlocker *blocker, *next;
+ assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+ QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
+ if (blocker->reason == reason) {
+ QLIST_REMOVE(blocker, list);
+ g_free(blocker);
+ }
+ }
+}
+
+void bdrv_op_block_all(BlockDriverState *bs, Error *reason)
+{
+ int i;
+ for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+ bdrv_op_block(bs, i, reason);
+ }
+}
+
+void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason)
+{
+ int i;
+ for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+ bdrv_op_unblock(bs, i, reason);
+ }
+}
+
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
{
assert(bs->in_use != in_use);
diff --git a/include/block/block.h b/include/block/block.h
index 3560deb..693d305 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -403,6 +403,12 @@ void bdrv_unref(BlockDriverState *bs);
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
int bdrv_in_use(BlockDriverState *bs);
+bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
+void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
+void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason);
+void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
+void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
+
#ifdef CONFIG_LINUX_AIO
int raw_get_aio_fd(BlockDriverState *bs);
#else
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 1666066..d8cef85 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -230,6 +230,8 @@ struct BlockDriver {
QLIST_ENTRY(BlockDriver) list;
};
+typedef struct BdrvOpBlocker BdrvOpBlocker;
+
/*
* Note: the function bdrv_append() copies and swaps contents of
* BlockDriverStates, so if you add new fields to this struct, please
@@ -308,6 +310,9 @@ struct BlockDriverState {
QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
+ /* operation blockers */
+ QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX];
+
/* long-running background operation */
BlockJob *job;
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 3/7] block: Replace in_use with operation blocker
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 2/7] block: Introduce op_blockers to BlockDriverState Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations Fam Zheng
` (3 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
This drops BlockDriverState.in_use with op_blockers:
- Call bdrv_op_block_all in place of bdrv_set_in_use(bs, 1).
- Call bdrv_op_unblock_all in place of bdrv_set_in_use(bs, 0).
- Check bdrv_op_is_blocked() in place of bdrv_in_use(bs).
The specific types are used, e.g. in place of starting block backup,
bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP, ...).
- Check bdrv_op_blocker_is_empty() in place of assert(!bs->in_use).
Note: there is no block for only specific types for now, i.e. a caller
blocks all or none. So although the checks are type specific, the above
changes can still be seen as identical in logic.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block-migration.c | 8 ++++++--
block.c | 34 +++++++++++++++++++++-------------
blockdev.c | 29 +++++++++++++++++++----------
blockjob.c | 12 +++++++-----
hw/block/dataplane/virtio-blk.c | 16 ++++++++++------
include/block/block.h | 2 --
include/block/block_int.h | 1 -
include/block/blockjob.h | 3 +++
8 files changed, 66 insertions(+), 39 deletions(-)
diff --git a/block-migration.c b/block-migration.c
index daf9ec1..12afcfa 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -58,6 +58,8 @@ typedef struct BlkMigDevState {
/* Protected by block migration lock. */
unsigned long *aio_bitmap;
int64_t completed_sectors;
+
+ Error *blocker;
} BlkMigDevState;
typedef struct BlkMigBlock {
@@ -336,7 +338,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
bmds->completed_sectors = 0;
bmds->shared_base = block_mig_state.shared_base;
alloc_aio_bitmap(bmds);
- bdrv_set_in_use(bs, 1);
+ error_setg(&bmds->blocker, "block device is in use by migration");
+ bdrv_op_block_all(bs, bmds->blocker);
bdrv_ref(bs);
block_mig_state.total_sector_sum += sectors;
@@ -574,7 +577,8 @@ static void blk_mig_cleanup(void)
blk_mig_lock();
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
- bdrv_set_in_use(bmds->bs, 0);
+ bdrv_op_unblock_all(bmds->bs, bmds->blocker);
+ error_free(bmds->blocker);
bdrv_unref(bmds->bs);
g_free(bmds->aio_bitmap);
g_free(bmds);
diff --git a/block.c b/block.c
index 45410ef..c2ab6d8 100644
--- a/block.c
+++ b/block.c
@@ -1628,15 +1628,17 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
bs_dest->refcnt = bs_src->refcnt;
/* job */
- bs_dest->in_use = bs_src->in_use;
bs_dest->job = bs_src->job;
/* keep the same entry in bdrv_states */
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
+ memcpy(bs_dest->op_blockers, bs_src->op_blockers,
+ sizeof(bs_dest->op_blockers));
bs_dest->list = bs_src->list;
}
+static bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
/*
* Swap bs contents for two image chains while they are live,
* while keeping required fields on the BlockDriverState that is
@@ -1658,7 +1660,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
assert(bs_new->dirty_bitmap == NULL);
assert(bs_new->job == NULL);
assert(bs_new->dev == NULL);
- assert(bs_new->in_use == 0);
+ assert(bdrv_op_blocker_is_empty(bs_new));
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
@@ -1677,7 +1679,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
/* Check a few fields that should remain attached to the device */
assert(bs_new->dev == NULL);
assert(bs_new->job == NULL);
- assert(bs_new->in_use == 0);
+ assert(bdrv_op_blocker_is_empty(bs_new));
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
@@ -1714,7 +1716,7 @@ static void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->dev);
assert(!bs->job);
- assert(!bs->in_use);
+ assert(bdrv_op_blocker_is_empty(bs));
assert(!bs->refcnt);
bdrv_close(bs);
@@ -1887,6 +1889,7 @@ int bdrv_commit(BlockDriverState *bs)
int ret = 0;
uint8_t *buf;
char filename[PATH_MAX];
+ Error *local_err;
if (!drv)
return -ENOMEDIUM;
@@ -1895,7 +1898,9 @@ int bdrv_commit(BlockDriverState *bs)
return -ENOTSUP;
}
- if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, &local_err) ||
+ bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, &local_err)) {
+ error_free(local_err);
return -EBUSY;
}
@@ -2831,6 +2836,7 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
int bdrv_truncate(BlockDriverState *bs, int64_t offset)
{
BlockDriver *drv = bs->drv;
+ Error *local_err;
int ret;
if (!drv)
return -ENOMEDIUM;
@@ -2838,8 +2844,10 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return -ENOTSUP;
if (bs->read_only)
return -EACCES;
- if (bdrv_in_use(bs))
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, &local_err)) {
+ error_free(local_err);
return -EBUSY;
+ }
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
@@ -4482,15 +4490,15 @@ void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason)
}
}
-void bdrv_set_in_use(BlockDriverState *bs, int in_use)
+static bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
{
- assert(bs->in_use != in_use);
- bs->in_use = in_use;
-}
+ bool ret = true;
+ int i;
-int bdrv_in_use(BlockDriverState *bs)
-{
- return bs->in_use;
+ for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+ ret = ret && QLIST_EMPTY(&bs->op_blockers[i]);
+ }
+ return ret;
}
void bdrv_iostatus_enable(BlockDriverState *bs)
diff --git a/blockdev.c b/blockdev.c
index 330aa4a..1efa806 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1224,8 +1224,8 @@ static void external_snapshot_prepare(BlkTransactionState *common,
return;
}
- if (bdrv_in_use(state->old_bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, device);
+ if (bdrv_op_is_blocked(state->old_bs,
+ BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
return;
}
@@ -1441,10 +1441,10 @@ exit:
static void eject_device(BlockDriverState *bs, int force, Error **errp)
{
- if (bdrv_in_use(bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
return;
}
+
if (!bdrv_dev_has_removable_media(bs)) {
error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
return;
@@ -1637,14 +1637,16 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
BlockDriverState *bs;
+ Error *local_err;
bs = bdrv_find(id);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, id);
return -1;
}
- if (bdrv_in_use(bs)) {
- qerror_report(QERR_DEVICE_IN_USE, id);
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
return -1;
}
@@ -1755,6 +1757,10 @@ void qmp_block_stream(const char *device, bool has_base,
return;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
+ return;
+ }
+
if (base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
@@ -1795,6 +1801,10 @@ void qmp_block_commit(const char *device,
return;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
+ return;
+ }
+
/* default top_bs is the active layer */
top_bs = bs;
@@ -1881,8 +1891,7 @@ void qmp_drive_backup(const char *device, const char *target,
}
}
- if (bdrv_in_use(bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, device);
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
return;
}
@@ -2011,11 +2020,11 @@ void qmp_drive_mirror(const char *device, const char *target,
}
}
- if (bdrv_in_use(bs)) {
- error_set(errp, QERR_DEVICE_IN_USE, device);
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
return;
}
+
flags = bs->open_flags | BDRV_O_RDWR;
source = bs->backing_hd;
if (!source && sync == MIRROR_SYNC_MODE_TOP) {
diff --git a/blockjob.c b/blockjob.c
index 9e5fd5c..e198cb2 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -41,13 +41,11 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
{
BlockJob *job;
- if (bs->job || bdrv_in_use(bs)) {
+ if (bs->job) {
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
return NULL;
}
bdrv_ref(bs);
- bdrv_set_in_use(bs, 1);
-
job = g_malloc0(driver->instance_size);
job->driver = driver;
job->bs = bs;
@@ -64,11 +62,14 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
if (error_is_set(&local_err)) {
bs->job = NULL;
g_free(job);
- bdrv_set_in_use(bs, 0);
error_propagate(errp, local_err);
return NULL;
}
}
+ error_setg(&job->blocker, "block device is in use by block job: %s",
+ BlockJobType_lookup[driver->job_type]);
+ bdrv_op_block_all(bs, job->blocker);
+
return job;
}
@@ -79,8 +80,9 @@ void block_job_completed(BlockJob *job, int ret)
assert(bs->job == job);
job->cb(job->opaque, ret);
bs->job = NULL;
+ bdrv_op_unblock_all(bs, job->blocker);
+ error_free(job->blocker);
g_free(job);
- bdrv_set_in_use(bs, 0);
}
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index f2d7350..0a7b759 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -69,6 +69,9 @@ struct VirtIOBlockDataPlane {
queue */
unsigned int num_reqs;
+
+ /* Operation blocker on BDS */
+ Error *blocker;
};
/* Raise an interrupt to signal guest, if necessary */
@@ -385,6 +388,7 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
{
VirtIOBlockDataPlane *s;
int fd;
+ Error *local_err = NULL;
*dataplane = NULL;
@@ -406,8 +410,9 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
/* If dataplane is (re-)enabled while the guest is running there could be
* block jobs that can conflict.
*/
- if (bdrv_in_use(blk->conf.bs)) {
- error_report("cannot start dataplane thread while device is in use");
+ if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
return false;
}
@@ -422,9 +427,8 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
s->vdev = vdev;
s->fd = fd;
s->blk = blk;
-
- /* Prevent block operations that conflict with data plane thread */
- bdrv_set_in_use(blk->conf.bs, 1);
+ error_setg(&s->blocker, "block device is in use by data plane");
+ bdrv_op_block_all(blk->conf.bs, s->blocker);
*dataplane = s;
return true;
@@ -437,7 +441,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
}
virtio_blk_data_plane_stop(s);
- bdrv_set_in_use(s->blk->conf.bs, 0);
+ bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
g_free(s);
}
diff --git a/include/block/block.h b/include/block/block.h
index 693d305..173c09a 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -400,8 +400,6 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
void bdrv_ref(BlockDriverState *bs);
void bdrv_unref(BlockDriverState *bs);
-void bdrv_set_in_use(BlockDriverState *bs, int in_use);
-int bdrv_in_use(BlockDriverState *bs);
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index d8cef85..60edc80 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -305,7 +305,6 @@ struct BlockDriverState {
char device_name[32];
HBitmap *dirty_bitmap;
int refcnt;
- int in_use; /* users other than guest access, eg. block migration */
QTAILQ_ENTRY(BlockDriverState) list;
QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index d76de62..c0a7875 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -106,6 +106,9 @@ struct BlockJob {
/** The completion function that will be called when the job completes. */
BlockDriverCompletionFunc *cb;
+ /** Block other operations when block job is running */
+ Error *blocker;
+
/** The opaque value that is passed to the completion function. */
void *opaque;
};
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
` (2 preceding siblings ...)
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 3/7] block: Replace in_use with operation blocker Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 16:13 ` Paolo Bonzini
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS Fam Zheng
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
Before operate on a BlockDriverState, respective types are checked
against bs->op_blockers and it will error out if there's a blocker.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
blockdev.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 1efa806..cfb815f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1001,6 +1001,11 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
return NULL;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
+ errp)) {
+ return NULL;
+ }
+
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
@@ -1098,6 +1103,10 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
return;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
+ return;
+ }
+
if (!bdrv_is_inserted(bs)) {
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
@@ -1536,6 +1545,10 @@ void qmp_change_blockdev(const char *device, const char *filename,
return;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
+ return;
+ }
+
if (format) {
drv = bdrv_find_whitelisted_format(format, bs->read_only);
if (!drv) {
@@ -1684,6 +1697,10 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
return;
}
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, errp)) {
+ return;
+ }
+
if (size < 0) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
return;
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
` (3 preceding siblings ...)
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 16:18 ` Paolo Bonzini
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 6/7] qmp: add command 'blockdev-backup' Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 7/7] block: Allow backup on referenced named BlockDriverState Fam Zheng
6 siblings, 1 reply; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block.c | 31 ++++++++++++++++++++++++++++---
block/mirror.c | 2 +-
include/block/block.h | 3 ++-
include/block/block_int.h | 3 +++
4 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/block.c b/block.c
index c2ab6d8..d633f2b 100644
--- a/block.c
+++ b/block.c
@@ -959,18 +959,39 @@ fail:
/*
* Opens the backing file for a BlockDriverState if not yet open
*
+ * If backing_bs is not NULL or empty, find the BDS by name and reference it as
+ * the backing_hd, in this case options is ignored.
+ *
* options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict is transferred to this
* function (even on failure), so if the caller intends to reuse the dictionary,
* it needs to use QINCREF() before calling bdrv_file_open.
*/
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+int bdrv_open_backing_file(BlockDriverState *bs, const char *backing_bs,
+ QDict *options, Error **errp)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
BlockDriver *back_drv = NULL;
Error *local_err = NULL;
+ if (backing_bs && *backing_bs != '\0') {
+ bs->backing_hd = bdrv_find(backing_bs);
+ if (!bs->backing_hd) {
+ error_setg(errp, "Backing device not found: %s", backing_bs);
+ return -ENOENT;
+ }
+ bdrv_ref(bs->backing_hd);
+ assert(!bs->backing_blocker);
+ error_setg(&bs->backing_blocker,
+ "device is used as backing hd of '%s'",
+ bs->device_name);
+ bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
+ bs->backing_hd->filename);
+ pstrcpy(bs->backing_format, sizeof(bs->backing_format),
+ bs->backing_hd->drv->format_name);
+ }
if (bs->backing_hd != NULL) {
QDECREF(options);
return 0;
@@ -1166,9 +1187,11 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
/* If there is a backing file, use it */
if ((flags & BDRV_O_NO_BACKING) == 0) {
QDict *backing_options;
-
qdict_extract_subqdict(options, &backing_options, "backing.");
- ret = bdrv_open_backing_file(bs, backing_options, &local_err);
+ ret = bdrv_open_backing_file(bs, qdict_get_try_str(options, "backing"),
+ backing_options, &local_err);
+
+ qdict_del(options, "backing");
if (ret < 0) {
goto close_and_fail;
}
@@ -1461,6 +1484,8 @@ void bdrv_close(BlockDriverState *bs)
if (bs->drv) {
if (bs->backing_hd) {
+ bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
+ error_free(bs->backing_blocker);
bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
}
diff --git a/block/mirror.c b/block/mirror.c
index 7b95acf..ce0103a 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -508,7 +508,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
Error *local_err = NULL;
int ret;
- ret = bdrv_open_backing_file(s->target, NULL, &local_err);
+ ret = bdrv_open_backing_file(s->target, NULL, NULL, &local_err);
if (ret < 0) {
char backing_filename[PATH_MAX];
bdrv_get_full_backing_filename(s->target, backing_filename,
diff --git a/include/block/block.h b/include/block/block.h
index 173c09a..e6ec03e 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -157,7 +157,8 @@ int bdrv_parse_cache_flags(const char *mode, int *flags);
int bdrv_parse_discard_flags(const char *mode, int *flags);
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
QDict *options, int flags, Error **errp);
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
+int bdrv_open_backing_file(BlockDriverState *bs, const char *backing_bs,
+ QDict *options, Error **errp);
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv, Error **errp);
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 60edc80..6db30c9 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -316,6 +316,9 @@ struct BlockDriverState {
BlockJob *job;
QDict *options;
+
+ /* For backing reference, block the operations of named backing device */
+ Error *backing_blocker;
};
int get_tmp_filename(char *filename, int size);
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 6/7] qmp: add command 'blockdev-backup'
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
` (4 preceding siblings ...)
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 7/7] block: Allow backup on referenced named BlockDriverState Fam Zheng
6 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
Similar to drive-backup, but this command uses a device id as target
instead of creating/opening an image file.
Also add blocker on target bs, since the target is also a named device
now.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block/backup.c | 21 +++++++++++++++++++++
blockdev.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
qapi-schema.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
qmp-commands.hx | 44 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 161 insertions(+)
diff --git a/block/backup.c b/block/backup.c
index cad14c9..b620531 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -338,6 +338,7 @@ static void coroutine_fn backup_run(void *opaque)
hbitmap_free(job->bitmap);
bdrv_iostatus_disable(target);
+ bdrv_op_unblock_all(target, job->common.blocker);
bdrv_unref(target);
block_job_completed(&job->common, ret);
@@ -363,6 +364,24 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
return;
}
+ if (!bdrv_is_inserted(bs)) {
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bs->device_name);
+ return;
+ }
+
+ if (!bdrv_is_inserted(target)) {
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, target->device_name);
+ return;
+ }
+
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ return;
+ }
+
+ if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
+ return;
+ }
+
len = bdrv_getlength(bs);
if (len < 0) {
error_setg_errno(errp, -len, "unable to get length for '%s'",
@@ -376,6 +395,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
return;
}
+ bdrv_op_block_all(target, job->common.blocker);
+
job->on_source_error = on_source_error;
job->on_target_error = on_target_error;
job->target = target;
diff --git a/blockdev.c b/blockdev.c
index cfb815f..1866b64 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1892,6 +1892,8 @@ void qmp_drive_backup(const char *device, const char *target,
return;
}
+ /* Although backup_run has this check too, we need to use bs->drv below, so
+ * do an early check redundantly. */
if (!bdrv_is_inserted(bs)) {
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
@@ -1908,6 +1910,7 @@ void qmp_drive_backup(const char *device, const char *target,
}
}
+ /* Early check to avoid creating target */
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
return;
}
@@ -1966,6 +1969,50 @@ void qmp_drive_backup(const char *device, const char *target,
}
}
+void qmp_blockdev_backup(const char *device, const char *target,
+ enum MirrorSyncMode sync,
+ bool has_speed, int64_t speed,
+ bool has_on_source_error,
+ BlockdevOnError on_source_error,
+ bool has_on_target_error,
+ BlockdevOnError on_target_error,
+ Error **errp)
+{
+ BlockDriverState *bs;
+ BlockDriverState *target_bs;
+ Error *local_err = NULL;
+
+ if (!has_speed) {
+ speed = 0;
+ }
+ if (!has_on_source_error) {
+ on_source_error = BLOCKDEV_ON_ERROR_REPORT;
+ }
+ if (!has_on_target_error) {
+ on_target_error = BLOCKDEV_ON_ERROR_REPORT;
+ }
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
+ }
+
+ target_bs = bdrv_find(target);
+ if (!target_bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, target);
+ return;
+ }
+
+ bdrv_ref(target_bs);
+ backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
+ block_job_cb, bs, &local_err);
+ if (local_err != NULL) {
+ bdrv_unref(target_bs);
+ error_propagate(errp, local_err);
+ }
+}
+
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
void qmp_drive_mirror(const char *device, const char *target,
diff --git a/qapi-schema.json b/qapi-schema.json
index c9e513c..3150699 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1868,6 +1868,40 @@
'*on-target-error': 'BlockdevOnError' } }
##
+# @BlockdevBackup
+#
+# @device: the name of the device which should be copied.
+#
+# @target: the name of the backup target device.
+#
+# @sync: what parts of the disk image should be copied to the destination
+# (all the disk, only the sectors allocated in the topmost image, or
+# only new I/O).
+#
+# @speed: #optional the maximum speed, in bytes per second.
+#
+# @on-source-error: #optional the action to take on an error on the source,
+# default 'report'. 'stop' and 'enospc' can only be used
+# if the block device supports io-status (see BlockInfo).
+#
+# @on-target-error: #optional the action to take on an error on the target,
+# default 'report' (no limitations, since this applies to
+# a different block device than @device).
+#
+# Note that @on-source-error and @on-target-error only affect background I/O.
+# If an error occurs during a guest write request, the device's rerror/werror
+# actions will be used.
+#
+# Since: 1.8
+##
+{ 'type': 'BlockdevBackup',
+ 'data': { 'device': 'str', 'target': 'str',
+ 'sync': 'MirrorSyncMode',
+ '*speed': 'int',
+ '*on-source-error': 'BlockdevOnError',
+ '*on-target-error': 'BlockdevOnError' } }
+
+##
# @Abort
#
# This action can be used to test transaction failure.
@@ -2057,6 +2091,21 @@
{ 'command': 'drive-backup', 'data': 'DriveBackup' }
##
+# @blockdev-backup
+#
+# Block device version for drive-backup command. Use existing device as target
+# of backup.
+#
+# For the arguments, see the documentation of BlockdevBackup.
+#
+# Returns: Nothing on success.
+# If @device or @target is not a valid block device, DeviceNotFound.
+#
+# Since 1.8
+##
+{ 'command': 'blockdev-backup', 'data': 'BlockdevBackup' }
+
+##
# @drive-mirror
#
# Start mirroring a block device's writes to a new destination.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index fba15cd..32e2b10 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -963,6 +963,50 @@ Example:
"sync": "full",
"target": "backup.img" } }
<- { "return": {} }
+
+EQMP
+
+ {
+ .name = "blockdev-backup",
+ .args_type = "sync:s,device:B,target:B,speed:i?,"
+ "on-source-error:s?,on-target-error:s?",
+ .mhandler.cmd_new = qmp_marshal_input_blockdev_backup,
+ },
+
+SQMP
+blockdev-backup
+------------
+
+The device version of drive-backup: this command takes a existing named device
+as backup target.
+
+Arguments:
+
+- "device": the name of the device which should be copied.
+ (json-string)
+- "target": the target of the new image. If the file exists, or if it is a
+ device, the existing file/device will be used as the new
+ destination. If it does not exist, a new file will be created.
+ (json-string)
+- "sync": what parts of the disk image should be copied to the destination;
+ possibilities include "full" for all the disk, "top" for only the
+ sectors allocated in the topmost image, or "none" to only replicate
+ new I/O (MirrorSyncMode).
+- "speed": the maximum speed, in bytes per second (json-int, optional)
+- "on-source-error": the action to take on an error on the source, default
+ 'report'. 'stop' and 'enospc' can only be used
+ if the block device supports io-status.
+ (BlockdevOnError, optional)
+- "on-target-error": the action to take on an error on the target, default
+ 'report' (no limitations, since this applies to
+ a different block device than device).
+ (BlockdevOnError, optional)
+
+Example:
+-> { "execute": "blockdev-backup", "arguments": { "device": "src-id",
+ "target": "tgt-id" } }
+<- { "return": {} }
+
EQMP
{
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH v5 7/7] block: Allow backup on referenced named BlockDriverState
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
` (5 preceding siblings ...)
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 6/7] qmp: add command 'blockdev-backup' Fam Zheng
@ 2013-11-26 4:05 ` Fam Zheng
6 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-26 4:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, hbrock, rjones, imain, stefanha, pbonzini
Drive backup is a read only operation on source bs. We want to allow
this specific case to enable image-fleecing. Note that when
image-fleecing job starts, the job still add its blocker to source bs,
and any other operation on it will be blocked by that.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block.c b/block.c
index d633f2b..bb279d2 100644
--- a/block.c
+++ b/block.c
@@ -987,6 +987,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, const char *backing_bs,
"device is used as backing hd of '%s'",
bs->device_name);
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
+ bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
+ bs->backing_blocker);
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->backing_hd->filename);
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
--
1.8.4.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations Fam Zheng
@ 2013-11-26 16:13 ` Paolo Bonzini
2013-11-28 3:39 ` Fam Zheng
0 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2013-11-26 16:13 UTC (permalink / raw)
To: Fam Zheng; +Cc: kwolf, hbrock, qemu-devel, rjones, imain, stefanha
Il 26/11/2013 05:05, Fam Zheng ha scritto:
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1001,6 +1001,11 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
> return NULL;
> }
>
> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
> + errp)) {
> + return NULL;
> + }
Why not check in bdrv_snapshot_delete...
> ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
> if (error_is_set(&local_err)) {
> error_propagate(errp, local_err);
> @@ -1098,6 +1103,10 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
> return;
> }
>
> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
> + return;
> + }
... and bdrv_snapshot_create?
> if (!bdrv_is_inserted(bs)) {
> error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
> return;
> @@ -1536,6 +1545,10 @@ void qmp_change_blockdev(const char *device, const char *filename,
> return;
> }
>
> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
> + return;
> + }
> +
> if (format) {
> drv = bdrv_find_whitelisted_format(format, bs->read_only);
> if (!drv) {
> @@ -1684,6 +1697,10 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
> return;
> }
>
> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, errp)) {
> + return;
> + }
> +
> if (size < 0) {
> error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
> return;
> --
This should be redundant since bdrv_truncate already checks.
Paolo
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS Fam Zheng
@ 2013-11-26 16:18 ` Paolo Bonzini
2013-11-27 0:56 ` Fam Zheng
0 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2013-11-26 16:18 UTC (permalink / raw)
To: Fam Zheng; +Cc: kwolf, hbrock, qemu-devel, rjones, imain, stefanha
Il 26/11/2013 05:05, Fam Zheng ha scritto:
> + if (backing_bs && *backing_bs != '\0') {
> + bs->backing_hd = bdrv_find(backing_bs);
> + if (!bs->backing_hd) {
> + error_setg(errp, "Backing device not found: %s", backing_bs);
> + return -ENOENT;
> + }
> + bdrv_ref(bs->backing_hd);
> + assert(!bs->backing_blocker);
> + error_setg(&bs->backing_blocker,
> + "device is used as backing hd of '%s'",
> + bs->device_name);
> + bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
Why should this blocker only apply to the "named backing file" case, and
not to all backing files?
Paolo
> + pstrcpy(bs->backing_file, sizeof(bs->backing_file),
> + bs->backing_hd->filename);
> + pstrcpy(bs->backing_format, sizeof(bs->backing_format),
> + bs->backing_hd->drv->format_name);
> + }
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum Fam Zheng
@ 2013-11-26 16:21 ` Paolo Bonzini
0 siblings, 0 replies; 13+ messages in thread
From: Paolo Bonzini @ 2013-11-26 16:21 UTC (permalink / raw)
To: Fam Zheng; +Cc: kwolf, hbrock, qemu-devel, rjones, imain, stefanha
Il 26/11/2013 05:05, Fam Zheng ha scritto:
> +#
> +# @backup-source: As a backup source. See the 'drive-backup' command.
> +#
> +# @backup-target: As a backup target. See the 'drive-backup' command.
> +#
> +# @change: See the 'change' command.
> +#
> +# @commit: See the 'block-commi' command.
block-commit.
Paolo
> +#
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS
2013-11-26 16:18 ` Paolo Bonzini
@ 2013-11-27 0:56 ` Fam Zheng
0 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-27 0:56 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kwolf, hbrock, qemu-devel, rjones, imain, stefanha
On 2013年11月27日 00:18, Paolo Bonzini wrote:
> Il 26/11/2013 05:05, Fam Zheng ha scritto:
>> + if (backing_bs && *backing_bs != '\0') {
>> + bs->backing_hd = bdrv_find(backing_bs);
>> + if (!bs->backing_hd) {
>> + error_setg(errp, "Backing device not found: %s", backing_bs);
>> + return -ENOENT;
>> + }
>> + bdrv_ref(bs->backing_hd);
>> + assert(!bs->backing_blocker);
>> + error_setg(&bs->backing_blocker,
>> + "device is used as backing hd of '%s'",
>> + bs->device_name);
>> + bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
>
> Why should this blocker only apply to the "named backing file" case, and
> not to all backing files?
>
Good point, thanks.
Fam
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations
2013-11-26 16:13 ` Paolo Bonzini
@ 2013-11-28 3:39 ` Fam Zheng
0 siblings, 0 replies; 13+ messages in thread
From: Fam Zheng @ 2013-11-28 3:39 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kwolf, hbrock, qemu-devel, rjones, imain, stefanha
On 2013年11月27日 00:13, Paolo Bonzini wrote:
> Il 26/11/2013 05:05, Fam Zheng ha scritto:
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1001,6 +1001,11 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
>> return NULL;
>> }
>>
>> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
>> + errp)) {
>> + return NULL;
>> + }
>
> Why not check in bdrv_snapshot_delete...
>
>> ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
>> if (error_is_set(&local_err)) {
>> error_propagate(errp, local_err);
>> @@ -1098,6 +1103,10 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
>> return;
>> }
>>
>> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
>> + return;
>> + }
>
> ... and bdrv_snapshot_create?
>
OK.
>> if (!bdrv_is_inserted(bs)) {
>> error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
>> return;
>> @@ -1536,6 +1545,10 @@ void qmp_change_blockdev(const char *device, const char *filename,
>> return;
>> }
>>
>> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
>> + return;
>> + }
>> +
>> if (format) {
>> drv = bdrv_find_whitelisted_format(format, bs->read_only);
>> if (!drv) {
>> @@ -1684,6 +1697,10 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
>> return;
>> }
>>
>> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, errp)) {
>> + return;
>> + }
>> +
>> if (size < 0) {
>> error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
>> return;
>> --
>
> This should be redundant since bdrv_truncate already checks.
>
It doesn't hurt and skips bdrv_drain_all if op is blocked.
Fam
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2013-11-28 3:39 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-26 4:05 [Qemu-devel] [PATCH v5 0/7] Drop in_use from BlockDriverState and enable point-in-time snapshot exporting over NBD Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 1/7] qapi: Add BlockOperationType enum Fam Zheng
2013-11-26 16:21 ` Paolo Bonzini
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 2/7] block: Introduce op_blockers to BlockDriverState Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 3/7] block: Replace in_use with operation blocker Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 4/7] block: Add checks of blocker in block operations Fam Zheng
2013-11-26 16:13 ` Paolo Bonzini
2013-11-28 3:39 ` Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 5/7] block: Parse "backing" option to reference existing BDS Fam Zheng
2013-11-26 16:18 ` Paolo Bonzini
2013-11-27 0:56 ` Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 6/7] qmp: add command 'blockdev-backup' Fam Zheng
2013-11-26 4:05 ` [Qemu-devel] [PATCH v5 7/7] block: Allow backup on referenced named BlockDriverState Fam Zheng
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.