1
The following changes since commit d5d31c9a8ab5e87db4230602a6fd5da8eb13135c:
1
The following changes since commit 6d8e75d41c58892ccc5d4ad61c4da476684c1c83:
2
2
3
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-for-3.1-pull-request' into staging (2018-11-27 09:55:05 +0000)
3
Merge remote-tracking branch 'remotes/rth/tags/pull-axp-20190519' into staging (2019-05-20 11:38:36 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 6da021815e752b3ca3a547eed53f3e92a8a35452:
9
for you to fetch changes up to c423a6af592cf36b4f149c54e2966dd0016b7e96:
10
10
11
nvme: Fix spurious interrupts (2018-11-27 12:59:00 +0100)
11
iotests: Make 245 faster and more reliable (2019-05-20 17:08:57 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- block: Fix crash on migration with explicit child nodes
16
- block: AioContext management, part 1
17
- nvme: Fix spurious interrupts
17
- qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE
18
- nvme: fix copy direction in DMA reads going to CMB
19
- file-posix: Fix block status for unaligned raw images with O_DIRECT
20
- file-posix: Fix xfs_write_zeroes() after EOF
21
- Documentation and iotests improvements
18
22
19
----------------------------------------------------------------
23
----------------------------------------------------------------
20
Keith Busch (1):
24
Alberto Garcia (2):
21
nvme: Fix spurious interrupts
25
qcow2: Define and use QCOW2_COMPRESSED_SECTOR_SIZE
26
block: Use BDRV_REQUEST_MAX_BYTES instead of BDRV_REQUEST_MAX_SECTORS
22
27
23
Kevin Wolf (2):
28
Kevin Wolf (10):
24
block: Don't inactivate children before parents
29
block: Add bdrv_try_set_aio_context()
25
iotests: Test migration with -blockdev
30
block: Make bdrv_attach/detach_aio_context() static
31
block: Move recursion to bdrv_set_aio_context()
32
block: Propagate AioContext change to parents
33
test-block-iothread: Test AioContext propagation through the tree
34
block: Implement .(can_)set_aio_ctx for BlockBackend
35
block: Add blk_set_allow_aio_context_change()
36
blockjob: Propagate AioContext change to all job nodes
37
blockjob: Remove AioContext notifiers
38
test-block-iothread: Test AioContext propagation for block jobs
26
39
27
block.c | 84 +++++++++++++++++++------------
40
Klaus Birkelund Jensen (1):
28
hw/block/nvme.c | 4 +-
41
nvme: fix copy direction in DMA reads going to CMB
29
tests/qemu-iotests/234 | 121 +++++++++++++++++++++++++++++++++++++++++++++
30
tests/qemu-iotests/234.out | 30 +++++++++++
31
tests/qemu-iotests/group | 1 +
32
5 files changed, 208 insertions(+), 32 deletions(-)
33
create mode 100755 tests/qemu-iotests/234
34
create mode 100644 tests/qemu-iotests/234.out
35
42
43
Max Reitz (9):
44
block/file-posix: Truncate in xfs_write_zeroes()
45
block/file-posix: Unaligned O_DIRECT block-status
46
iotests: Test unaligned raw images with O_DIRECT
47
qemu-img.texi: Be specific about JSON object types
48
qemu-img.texi: Describe human-readable info output
49
block: Improve "Block node is read-only" message
50
iotests.py: Let assert_qmp() accept an array
51
iotests.py: Fix VM.run_job
52
iotests: Make 245 faster and more reliable
53
54
Vladimir Sementsov-Ogievskiy (2):
55
qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE
56
iotest: fix 169: do not run qmp_cont in RUN_STATE_FINISH_MIGRATE
57
58
block/qcow2.h | 4 +
59
include/block/block.h | 10 ++
60
include/block/block_int.h | 25 +----
61
include/sysemu/block-backend.h | 1 +
62
block.c | 174 +++++++++++++++++++++++++++++++----
63
block/backup.c | 8 --
64
block/block-backend.c | 55 ++++++++++-
65
block/file-posix.c | 29 ++++++
66
block/io.c | 6 +-
67
block/mirror.c | 10 +-
68
block/qcow2-cluster.c | 5 +-
69
block/qcow2-refcount.c | 25 ++---
70
block/qcow2.c | 3 +-
71
blockjob.c | 77 ++++++++--------
72
hw/block/nvme.c | 2 +-
73
qemu-io-cmds.c | 7 +-
74
qmp.c | 3 +
75
tests/test-block-iothread.c | 202 +++++++++++++++++++++++++++++++++++++++++
76
qemu-img.texi | 52 ++++++++++-
77
tests/qemu-iotests/169 | 7 +-
78
tests/qemu-iotests/221 | 4 +
79
tests/qemu-iotests/245 | 22 +++--
80
tests/qemu-iotests/245.out | 12 +++
81
tests/qemu-iotests/253 | 84 +++++++++++++++++
82
tests/qemu-iotests/253.out | 14 +++
83
tests/qemu-iotests/group | 1 +
84
tests/qemu-iotests/iotests.py | 20 +++-
85
27 files changed, 728 insertions(+), 134 deletions(-)
86
create mode 100755 tests/qemu-iotests/253
87
create mode 100644 tests/qemu-iotests/253.out
88
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
XFS_IOC_ZERO_RANGE does not increase the file length:
4
$ touch foo
5
$ xfs_io -c 'zero 0 65536' foo
6
$ stat -c "size=%s, blocks=%b" foo
7
size=0, blocks=128
8
9
We do want writes beyond the EOF to automatically increase the file
10
length, however. This is evidenced by the fact that iotest 061 is
11
broken on XFS since qcow2's check implementation checks for blocks
12
beyond the EOF.
13
14
Reported-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block/file-posix.c | 13 +++++++++++++
19
1 file changed, 13 insertions(+)
20
21
diff --git a/block/file-posix.c b/block/file-posix.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/file-posix.c
24
+++ b/block/file-posix.c
25
@@ -XXX,XX +XXX,XX @@ out:
26
#ifdef CONFIG_XFS
27
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
28
{
29
+ int64_t len;
30
struct xfs_flock64 fl;
31
int err;
32
33
+ len = lseek(s->fd, 0, SEEK_END);
34
+ if (len < 0) {
35
+ return -errno;
36
+ }
37
+
38
+ if (offset + bytes > len) {
39
+ /* XFS_IOC_ZERO_RANGE does not increase the file length */
40
+ if (ftruncate(s->fd, offset + bytes) < 0) {
41
+ return -errno;
42
+ }
43
+ }
44
+
45
memset(&fl, 0, sizeof(fl));
46
fl.l_whence = SEEK_SET;
47
fl.l_start = offset;
48
--
49
2.20.1
50
51
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
When an L2 table entry points to a compressed cluster the space used
4
by the data is specified in 512-byte sectors. This size is independent
5
from BDRV_SECTOR_SIZE and is specific to the qcow2 file format.
6
7
The QCOW2_COMPRESSED_SECTOR_SIZE constant defined in this patch makes
8
this explicit.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/qcow2.h | 4 ++++
14
block/qcow2-cluster.c | 5 +++--
15
block/qcow2-refcount.c | 25 ++++++++++++++-----------
16
block/qcow2.c | 3 ++-
17
4 files changed, 23 insertions(+), 14 deletions(-)
18
19
diff --git a/block/qcow2.h b/block/qcow2.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.h
22
+++ b/block/qcow2.h
23
@@ -XXX,XX +XXX,XX @@
24
#define MIN_CLUSTER_BITS 9
25
#define MAX_CLUSTER_BITS 21
26
27
+/* Defined in the qcow2 spec (compressed cluster descriptor) */
28
+#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
29
+#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1))
30
+
31
/* Must be at least 2 to cover COW */
32
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
33
34
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/qcow2-cluster.c
37
+++ b/block/qcow2-cluster.c
38
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
39
return cluster_offset;
40
}
41
42
- nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
43
- (cluster_offset >> 9);
44
+ nb_csectors =
45
+ (cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
46
+ (cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
47
48
cluster_offset |= QCOW_OFLAG_COMPRESSED |
49
((uint64_t)nb_csectors << s->csize_shift);
50
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/qcow2-refcount.c
53
+++ b/block/qcow2-refcount.c
54
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
55
switch (ctype) {
56
case QCOW2_CLUSTER_COMPRESSED:
57
{
58
- int nb_csectors;
59
- nb_csectors = ((l2_entry >> s->csize_shift) &
60
- s->csize_mask) + 1;
61
- qcow2_free_clusters(bs,
62
- (l2_entry & s->cluster_offset_mask) & ~511,
63
- nb_csectors * 512, type);
64
+ int64_t offset = (l2_entry & s->cluster_offset_mask)
65
+ & QCOW2_COMPRESSED_SECTOR_MASK;
66
+ int size = QCOW2_COMPRESSED_SECTOR_SIZE *
67
+ (((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
68
+ qcow2_free_clusters(bs, offset, size, type);
69
}
70
break;
71
case QCOW2_CLUSTER_NORMAL:
72
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
73
nb_csectors = ((entry >> s->csize_shift) &
74
s->csize_mask) + 1;
75
if (addend != 0) {
76
+ uint64_t coffset = (entry & s->cluster_offset_mask)
77
+ & QCOW2_COMPRESSED_SECTOR_MASK;
78
ret = update_refcount(
79
- bs, (entry & s->cluster_offset_mask) & ~511,
80
- nb_csectors * 512, abs(addend), addend < 0,
81
+ bs, coffset,
82
+ nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
83
+ abs(addend), addend < 0,
84
QCOW2_DISCARD_SNAPSHOT);
85
if (ret < 0) {
86
goto fail;
87
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
88
nb_csectors = ((l2_entry >> s->csize_shift) &
89
s->csize_mask) + 1;
90
l2_entry &= s->cluster_offset_mask;
91
- ret = qcow2_inc_refcounts_imrt(bs, res,
92
- refcount_table, refcount_table_size,
93
- l2_entry & ~511, nb_csectors * 512);
94
+ ret = qcow2_inc_refcounts_imrt(
95
+ bs, res, refcount_table, refcount_table_size,
96
+ l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
97
+ nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
98
if (ret < 0) {
99
goto fail;
100
}
101
diff --git a/block/qcow2.c b/block/qcow2.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block/qcow2.c
104
+++ b/block/qcow2.c
105
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
106
107
coffset = file_cluster_offset & s->cluster_offset_mask;
108
nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
109
- csize = nb_csectors * 512 - (coffset & 511);
110
+ csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
111
+ (coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
112
113
buf = g_try_malloc(csize);
114
if (!buf) {
115
--
116
2.20.1
117
118
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
There are a few places in which we turn a number of bytes into sectors
4
in order to compare the result against BDRV_REQUEST_MAX_SECTORS
5
instead of using BDRV_REQUEST_MAX_BYTES directly.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/io.c | 6 +++---
12
qemu-io-cmds.c | 7 +++----
13
2 files changed, 6 insertions(+), 7 deletions(-)
14
15
diff --git a/block/io.c b/block/io.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/io.c
18
+++ b/block/io.c
19
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
20
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
21
size_t size)
22
{
23
- if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
24
+ if (size > BDRV_REQUEST_MAX_BYTES) {
25
return -EIO;
26
}
27
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
29
30
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
31
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
32
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
33
+ assert(bytes <= BDRV_REQUEST_MAX_BYTES);
34
assert(drv->bdrv_co_readv);
35
36
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
37
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
38
39
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
40
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
41
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
42
+ assert(bytes <= BDRV_REQUEST_MAX_BYTES);
43
44
assert(drv->bdrv_co_writev);
45
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
46
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/qemu-io-cmds.c
49
+++ b/qemu-io-cmds.c
50
@@ -XXX,XX +XXX,XX @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
51
{
52
int ret;
53
54
- if (bytes >> 9 > BDRV_REQUEST_MAX_SECTORS) {
55
+ if (bytes > BDRV_REQUEST_MAX_BYTES) {
56
return -ERANGE;
57
}
58
59
@@ -XXX,XX +XXX,XX @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
60
if (bytes < 0) {
61
print_cvtnum_err(bytes, argv[optind]);
62
return bytes;
63
- } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
64
+ } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
65
printf("length cannot exceed %"PRIu64", given %s\n",
66
- (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
67
- argv[optind]);
68
+ (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
69
return -EINVAL;
70
}
71
72
--
73
2.20.1
74
75
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
qmp_cont in RUN_STATE_FINISH_MIGRATE may lead to moving vm to
4
RUN_STATE_RUNNING, before actual migration finish. So, when migration
5
thread will try to go to RUN_STATE_POSTMIGRATE, assuming transition
6
RUN_STATE_FINISH_MIGRATE->RUN_STATE_POSTMIGRATE, it will crash, as
7
current state is RUN_STATE_RUNNING, and transition
8
RUN_STATE_RUNNING->RUN_STATE_POSTMIGRATE is forbidden.
9
10
Reported-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
qmp.c | 3 +++
16
1 file changed, 3 insertions(+)
17
18
diff --git a/qmp.c b/qmp.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/qmp.c
21
+++ b/qmp.c
22
@@ -XXX,XX +XXX,XX @@ void qmp_cont(Error **errp)
23
return;
24
} else if (runstate_check(RUN_STATE_SUSPENDED)) {
25
return;
26
+ } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
27
+ error_setg(errp, "Migration is not finalized yet");
28
+ return;
29
}
30
31
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
32
--
33
2.20.1
34
35
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
qmp_cont fails if vm in RUN_STATE_FINISH_MIGRATE, so let's wait for
4
final RUN_STATE_POSTMIGRATE. Also, while being here, check qmp_cont
5
result.
6
7
Reported-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Tested-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
tests/qemu-iotests/169 | 7 ++++++-
13
1 file changed, 6 insertions(+), 1 deletion(-)
14
15
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/169
18
+++ b/tests/qemu-iotests/169
19
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
20
event = self.vm_a.event_wait('MIGRATION')
21
if event['data']['status'] == 'completed':
22
break
23
+ while True:
24
+ result = self.vm_a.qmp('query-status')
25
+ if (result['return']['status'] == 'postmigrate'):
26
+ break
27
28
# test that bitmap is still here
29
removed = (not migrate_bitmaps) and persistent
30
self.check_bitmap(self.vm_a, False if removed else sha256)
31
32
- self.vm_a.qmp('cont')
33
+ result = self.vm_a.qmp('cont')
34
+ self.assert_qmp(result, 'return', {})
35
36
# test that bitmap is still here after invalidation
37
self.check_bitmap(self.vm_a, sha256)
38
--
39
2.20.1
40
41
diff view generated by jsdifflib
1
From: Keith Busch <keith.busch@intel.com>
1
From: Klaus Birkelund Jensen <klaus@birkelund.eu>
2
2
3
The code had asserted an interrupt every time it was requested to check
3
`nvme_dma_read_prp` erronously used `qemu_iovec_*to*_buf` instead of
4
for new completion queue entries.This can result in spurious interrupts
4
`qemu_iovec_*from*_buf` when the request involved the controller memory
5
seen by the guest OS.
5
buffer.
6
6
7
Fix this by asserting an interrupt only if there are un-acknowledged
7
Signed-off-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
8
completion queue entries available.
8
Reviewed-by: Kenneth Heitke <kenneth.heitke@intel.com>
9
10
Reported-by: Guenter Roeck <linux@roeck-us.net>
11
Signed-off-by: Keith Busch <keith.busch@intel.com>
12
Tested-by: Guenter Roeck <linux@roeck-us.net>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
10
---
15
hw/block/nvme.c | 4 +++-
11
hw/block/nvme.c | 2 +-
16
1 file changed, 3 insertions(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
17
13
18
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
14
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/block/nvme.c
16
--- a/hw/block/nvme.c
21
+++ b/hw/block/nvme.c
17
+++ b/hw/block/nvme.c
22
@@ -XXX,XX +XXX,XX @@ static void nvme_post_cqes(void *opaque)
18
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
23
sizeof(req->cqe));
19
}
24
QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
20
qemu_sglist_destroy(&qsg);
25
}
21
} else {
26
- nvme_irq_assert(n, cq);
22
- if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
27
+ if (cq->tail != cq->head) {
23
+ if (unlikely(qemu_iovec_from_buf(&iov, 0, ptr, len) != len)) {
28
+ nvme_irq_assert(n, cq);
24
trace_nvme_err_invalid_dma();
29
+ }
25
status = NVME_INVALID_FIELD | NVME_DNR;
30
}
26
}
31
32
static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
33
--
27
--
34
2.19.1
28
2.20.1
35
29
36
30
diff view generated by jsdifflib
1
bdrv_child_cb_inactivate() asserts that parents are already inactive
1
Eventually, we want to make sure that all parents and all children of a
2
when children get inactivated. This precondition is necessary because
2
node are in the same AioContext as the node itself. This means that
3
parents could still issue requests in their inactivation code.
3
changing the AioContext may fail because one of the other involved
4
parties (e.g. a guest device that was configured with an iothread)
5
cannot allow switching to a different AioContext.
4
6
5
When block nodes are created individually with -blockdev, all of them
7
Introduce a set of functions that allow to first check whether all
6
are monitor owned and will be returned by bdrv_next() in an undefined
8
involved nodes can switch to a new context and only then do the actual
7
order (in practice, in the order of their creation, which is usually
9
switch. The check recursively covers children and parents.
8
children before parents), which obviously fails the assertion:
9
10
qemu: block.c:899: bdrv_child_cb_inactivate: Assertion `bs->open_flags & BDRV_O_INACTIVE' failed.
11
12
This patch fixes the ordering by skipping nodes with still active
13
parents in bdrv_inactivate_recurse() because we know that they will be
14
covered by recursion when the last active parent becomes inactive.
15
16
With the correct parents-before-children ordering, we also got rid of
17
the reason why commit aad0b7a0bfb introduced two passes, so we can go
18
back to a single-pass recursion. This is necessary so we can rely on the
19
BDRV_O_INACTIVE flag to skip nodes with active parents (the flag used
20
to be set only in pass 2, so we would always skip non-root nodes in
21
pass 1 because all parents would still be considered active; setting the
22
flag in pass 1 would mean, that we never skip anything in pass 2 because
23
all parents are already considered inactive).
24
25
Because of the change to single pass, this patch is best reviewed with
26
whitespace changes ignored.
27
10
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
Reviewed-by: Max Reitz <mreitz@redhat.com>
30
---
12
---
31
block.c | 84 ++++++++++++++++++++++++++++++++++++---------------------
13
include/block/block.h | 8 ++++
32
1 file changed, 53 insertions(+), 31 deletions(-)
14
include/block/block_int.h | 3 ++
15
block.c | 92 +++++++++++++++++++++++++++++++++++++++
16
3 files changed, 103 insertions(+)
33
17
18
diff --git a/include/block/block.h b/include/block/block.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/block/block.h
21
+++ b/include/block/block.h
22
@@ -XXX,XX +XXX,XX @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
23
* This function must be called with iothread lock held.
24
*/
25
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
26
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
27
+ Error **errp);
28
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
29
+ BdrvChild *ignore_child, Error **errp);
30
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
31
+ GSList **ignore, Error **errp);
32
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
33
+ GSList **ignore, Error **errp);
34
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
35
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
36
37
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block_int.h
40
+++ b/include/block/block_int.h
41
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
42
* can update its reference. */
43
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
44
const char *filename, Error **errp);
45
+
46
+ bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
47
+ GSList **ignore, Error **errp);
48
};
49
50
extern const BdrvChildRole child_file;
34
diff --git a/block.c b/block.c
51
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
53
--- a/block.c
37
+++ b/block.c
54
+++ b/block.c
38
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache_all(Error **errp)
55
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_cb_inactivate(BdrvChild *child)
39
}
56
return 0;
40
}
57
}
41
58
42
-static int bdrv_inactivate_recurse(BlockDriverState *bs,
59
+static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
43
- bool setting_flag)
60
+ GSList **ignore, Error **errp)
44
+static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
45
+{
61
+{
46
+ BdrvChild *parent;
62
+ BlockDriverState *bs = child->opaque;
63
+ return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
64
+}
47
+
65
+
48
+ QLIST_FOREACH(parent, &bs->parents, next_parent) {
66
/*
49
+ if (parent->role->parent_is_bds) {
67
* Returns the options and flags that a temporary snapshot should get, based on
50
+ BlockDriverState *parent_bs = parent->opaque;
68
* the originally requested flags (the originally requested image will have
51
+ if (!only_active || !(parent_bs->open_flags & BDRV_O_INACTIVE)) {
69
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
52
+ return true;
70
.attach = bdrv_child_cb_attach,
53
+ }
71
.detach = bdrv_child_cb_detach,
72
.inactivate = bdrv_child_cb_inactivate,
73
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
74
};
75
76
/*
77
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
78
.attach = bdrv_child_cb_attach,
79
.detach = bdrv_child_cb_detach,
80
.inactivate = bdrv_child_cb_inactivate,
81
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
82
};
83
84
static void bdrv_backing_attach(BdrvChild *c)
85
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_backing = {
86
.drained_end = bdrv_child_cb_drained_end,
87
.inactivate = bdrv_child_cb_inactivate,
88
.update_filename = bdrv_backing_update_filename,
89
+ .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
90
};
91
92
static int bdrv_open_flags(BlockDriverState *bs, int flags)
93
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
94
aio_context_release(new_context);
95
}
96
97
+static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
98
+ GSList **ignore, Error **errp)
99
+{
100
+ if (g_slist_find(*ignore, c)) {
101
+ return true;
102
+ }
103
+ *ignore = g_slist_prepend(*ignore, c);
104
+
105
+ /* A BdrvChildRole that doesn't handle AioContext changes cannot
106
+ * tolerate any AioContext changes */
107
+ if (!c->role->can_set_aio_ctx) {
108
+ char *user = bdrv_child_user_desc(c);
109
+ error_setg(errp, "Changing iothreads is not supported by %s", user);
110
+ g_free(user);
111
+ return false;
112
+ }
113
+ if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) {
114
+ assert(!errp || *errp);
115
+ return false;
116
+ }
117
+ return true;
118
+}
119
+
120
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
121
+ GSList **ignore, Error **errp)
122
+{
123
+ if (g_slist_find(*ignore, c)) {
124
+ return true;
125
+ }
126
+ *ignore = g_slist_prepend(*ignore, c);
127
+ return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp);
128
+}
129
+
130
+/* @ignore will accumulate all visited BdrvChild object. The caller is
131
+ * responsible for freeing the list afterwards. */
132
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
133
+ GSList **ignore, Error **errp)
134
+{
135
+ BdrvChild *c;
136
+
137
+ if (bdrv_get_aio_context(bs) == ctx) {
138
+ return true;
139
+ }
140
+
141
+ QLIST_FOREACH(c, &bs->parents, next_parent) {
142
+ if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) {
143
+ return false;
144
+ }
145
+ }
146
+ QLIST_FOREACH(c, &bs->children, next) {
147
+ if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) {
148
+ return false;
54
+ }
149
+ }
55
+ }
150
+ }
56
+
151
+
57
+ return false;
152
+ return true;
58
+}
153
+}
59
+
154
+
60
+static int bdrv_inactivate_recurse(BlockDriverState *bs)
155
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
61
{
156
+ BdrvChild *ignore_child, Error **errp)
62
BdrvChild *child, *parent;
157
+{
63
+ uint64_t perm, shared_perm;
158
+ GSList *ignore;
64
int ret;
159
+ bool ret;
65
160
+
66
if (!bs->drv) {
161
+ ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
67
return -ENOMEDIUM;
162
+ ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp);
68
}
163
+ g_slist_free(ignore);
69
164
+
70
- if (!setting_flag && bs->drv->bdrv_inactivate) {
165
+ if (!ret) {
71
+ /* Make sure that we don't inactivate a child before its parent.
166
+ return -EPERM;
72
+ * It will be covered by recursion from the yet active parent. */
73
+ if (bdrv_has_bds_parent(bs, true)) {
74
+ return 0;
75
+ }
167
+ }
76
+
168
+
77
+ assert(!(bs->open_flags & BDRV_O_INACTIVE));
169
+ bdrv_set_aio_context(bs, ctx);
170
+ return 0;
171
+}
78
+
172
+
79
+ /* Inactivate this node */
173
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
80
+ if (bs->drv->bdrv_inactivate) {
174
+ Error **errp)
81
ret = bs->drv->bdrv_inactivate(bs);
175
+{
82
if (ret < 0) {
176
+ return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp);
83
return ret;
177
+}
84
}
85
}
86
87
- if (setting_flag && !(bs->open_flags & BDRV_O_INACTIVE)) {
88
- uint64_t perm, shared_perm;
89
-
90
- QLIST_FOREACH(parent, &bs->parents, next_parent) {
91
- if (parent->role->inactivate) {
92
- ret = parent->role->inactivate(parent);
93
- if (ret < 0) {
94
- return ret;
95
- }
96
+ QLIST_FOREACH(parent, &bs->parents, next_parent) {
97
+ if (parent->role->inactivate) {
98
+ ret = parent->role->inactivate(parent);
99
+ if (ret < 0) {
100
+ return ret;
101
}
102
}
103
+ }
104
105
- bs->open_flags |= BDRV_O_INACTIVE;
106
+ bs->open_flags |= BDRV_O_INACTIVE;
107
+
178
+
108
+ /* Update permissions, they may differ for inactive nodes */
179
void bdrv_add_aio_context_notifier(BlockDriverState *bs,
109
+ bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
180
void (*attached_aio_context)(AioContext *new_context, void *opaque),
110
+ bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort);
181
void (*detach_aio_context)(void *opaque), void *opaque)
111
+ bdrv_set_perm(bs, perm, shared_perm);
112
113
- /* Update permissions, they may differ for inactive nodes */
114
- bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
115
- bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort);
116
- bdrv_set_perm(bs, perm, shared_perm);
117
- }
118
119
+ /* Recursively inactivate children */
120
QLIST_FOREACH(child, &bs->children, next) {
121
- ret = bdrv_inactivate_recurse(child->bs, setting_flag);
122
+ ret = bdrv_inactivate_recurse(child->bs);
123
if (ret < 0) {
124
return ret;
125
}
126
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
127
BlockDriverState *bs = NULL;
128
BdrvNextIterator it;
129
int ret = 0;
130
- int pass;
131
GSList *aio_ctxs = NULL, *ctx;
132
133
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
134
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
135
}
136
}
137
138
- /* We do two passes of inactivation. The first pass calls to drivers'
139
- * .bdrv_inactivate callbacks recursively so all cache is flushed to disk;
140
- * the second pass sets the BDRV_O_INACTIVE flag so that no further write
141
- * is allowed. */
142
- for (pass = 0; pass < 2; pass++) {
143
- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
144
- ret = bdrv_inactivate_recurse(bs, pass);
145
- if (ret < 0) {
146
- bdrv_next_cleanup(&it);
147
- goto out;
148
- }
149
+ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
150
+ /* Nodes with BDS parents are covered by recursion from the last
151
+ * parent that gets inactivated. Don't inactivate them a second
152
+ * time if that has already happened. */
153
+ if (bdrv_has_bds_parent(bs, false)) {
154
+ continue;
155
+ }
156
+ ret = bdrv_inactivate_recurse(bs);
157
+ if (ret < 0) {
158
+ bdrv_next_cleanup(&it);
159
+ goto out;
160
}
161
}
162
163
--
182
--
164
2.19.1
183
2.20.1
165
184
166
185
diff view generated by jsdifflib
New patch
1
Since commit b97511c7bc8, there is no reason for block drivers any more
2
to call these functions (see the function comment in block_int.h). They
3
are now just internal helper functions for bdrv_set_aio_context()
4
and can be made static.
1
5
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
include/block/block_int.h | 21 ---------------------
9
block.c | 6 +++---
10
2 files changed, 3 insertions(+), 24 deletions(-)
11
12
diff --git a/include/block/block_int.h b/include/block/block_int.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/block/block_int.h
15
+++ b/include/block/block_int.h
16
@@ -XXX,XX +XXX,XX @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
17
void bdrv_add_before_write_notifier(BlockDriverState *bs,
18
NotifierWithReturn *notifier);
19
20
-/**
21
- * bdrv_detach_aio_context:
22
- *
23
- * May be called from .bdrv_detach_aio_context() to detach children from the
24
- * current #AioContext. This is only needed by block drivers that manage their
25
- * own children. Both ->file and ->backing are automatically handled and
26
- * block drivers should not call this function on them explicitly.
27
- */
28
-void bdrv_detach_aio_context(BlockDriverState *bs);
29
-
30
-/**
31
- * bdrv_attach_aio_context:
32
- *
33
- * May be called from .bdrv_attach_aio_context() to attach children to the new
34
- * #AioContext. This is only needed by block drivers that manage their own
35
- * children. Both ->file and ->backing are automatically handled and block
36
- * drivers should not call this function on them explicitly.
37
- */
38
-void bdrv_attach_aio_context(BlockDriverState *bs,
39
- AioContext *new_context);
40
-
41
/**
42
* bdrv_add_aio_context_notifier:
43
*
44
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
47
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
49
g_free(ban);
50
}
51
52
-void bdrv_detach_aio_context(BlockDriverState *bs)
53
+static void bdrv_detach_aio_context(BlockDriverState *bs)
54
{
55
BdrvAioNotifier *baf, *baf_tmp;
56
BdrvChild *child;
57
@@ -XXX,XX +XXX,XX @@ void bdrv_detach_aio_context(BlockDriverState *bs)
58
bs->aio_context = NULL;
59
}
60
61
-void bdrv_attach_aio_context(BlockDriverState *bs,
62
- AioContext *new_context)
63
+static void bdrv_attach_aio_context(BlockDriverState *bs,
64
+ AioContext *new_context)
65
{
66
BdrvAioNotifier *ban, *ban_tmp;
67
BdrvChild *child;
68
--
69
2.20.1
70
71
diff view generated by jsdifflib
New patch
1
Instead of having two recursions, in bdrv_attach_aio_context() and in
2
bdrv_detach_aio_context(), just having one recursion is enough. Said
3
functions are only about a single node now.
1
4
5
It is important that the recursion doesn't happen between detaching and
6
attaching a context to the current node because the nested call will
7
drain the node, and draining with a NULL context would segfault.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 15 +++++++--------
12
1 file changed, 7 insertions(+), 8 deletions(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
19
static void bdrv_detach_aio_context(BlockDriverState *bs)
20
{
21
BdrvAioNotifier *baf, *baf_tmp;
22
- BdrvChild *child;
23
24
assert(!bs->walking_aio_notifiers);
25
bs->walking_aio_notifiers = true;
26
@@ -XXX,XX +XXX,XX @@ static void bdrv_detach_aio_context(BlockDriverState *bs)
27
if (bs->drv && bs->drv->bdrv_detach_aio_context) {
28
bs->drv->bdrv_detach_aio_context(bs);
29
}
30
- QLIST_FOREACH(child, &bs->children, next) {
31
- bdrv_detach_aio_context(child->bs);
32
- }
33
34
if (bs->quiesce_counter) {
35
aio_enable_external(bs->aio_context);
36
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
37
AioContext *new_context)
38
{
39
BdrvAioNotifier *ban, *ban_tmp;
40
- BdrvChild *child;
41
42
if (bs->quiesce_counter) {
43
aio_disable_external(new_context);
44
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
45
46
bs->aio_context = new_context;
47
48
- QLIST_FOREACH(child, &bs->children, next) {
49
- bdrv_attach_aio_context(child->bs, new_context);
50
- }
51
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
52
bs->drv->bdrv_attach_aio_context(bs, new_context);
53
}
54
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
55
* the same as the current context of bs). */
56
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
57
{
58
+ BdrvChild *child;
59
+
60
if (bdrv_get_aio_context(bs) == new_context) {
61
return;
62
}
63
64
bdrv_drained_begin(bs);
65
+
66
+ QLIST_FOREACH(child, &bs->children, next) {
67
+ bdrv_set_aio_context(child->bs, new_context);
68
+ }
69
+
70
bdrv_detach_aio_context(bs);
71
72
/* This function executes in the old AioContext so acquire the new one in
73
--
74
2.20.1
75
76
diff view generated by jsdifflib
New patch
1
All block nodes and users in any connected component of the block graph
2
must be in the same AioContext, so changing the AioContext of one node
3
must not only change all of its children, but all of its parents (and
4
in turn their children etc.) as well.
1
5
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
include/block/block.h | 2 ++
9
include/block/block_int.h | 1 +
10
block.c | 48 ++++++++++++++++++++++++++++++++++-----
11
3 files changed, 45 insertions(+), 6 deletions(-)
12
13
diff --git a/include/block/block.h b/include/block/block.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block.h
16
+++ b/include/block/block.h
17
@@ -XXX,XX +XXX,XX @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
18
* This function must be called with iothread lock held.
19
*/
20
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
21
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
22
+ AioContext *new_context, GSList **ignore);
23
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
24
Error **errp);
25
int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
26
diff --git a/include/block/block_int.h b/include/block/block_int.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block_int.h
29
+++ b/include/block/block_int.h
30
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
31
32
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
33
GSList **ignore, Error **errp);
34
+ void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
35
};
36
37
extern const BdrvChildRole child_file;
38
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
41
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
43
return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
44
}
45
46
+static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx,
47
+ GSList **ignore)
48
+{
49
+ BlockDriverState *bs = child->opaque;
50
+ return bdrv_set_aio_context_ignore(bs, ctx, ignore);
51
+}
52
+
53
/*
54
* Returns the options and flags that a temporary snapshot should get, based on
55
* the originally requested flags (the originally requested image will have
56
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_file = {
57
.detach = bdrv_child_cb_detach,
58
.inactivate = bdrv_child_cb_inactivate,
59
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
60
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
61
};
62
63
/*
64
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_format = {
65
.detach = bdrv_child_cb_detach,
66
.inactivate = bdrv_child_cb_inactivate,
67
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
68
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
69
};
70
71
static void bdrv_backing_attach(BdrvChild *c)
72
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_backing = {
73
.inactivate = bdrv_child_cb_inactivate,
74
.update_filename = bdrv_backing_update_filename,
75
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
76
+ .set_aio_ctx = bdrv_child_cb_set_aio_ctx,
77
};
78
79
static int bdrv_open_flags(BlockDriverState *bs, int flags)
80
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
81
bs->walking_aio_notifiers = false;
82
}
83
84
-/* The caller must own the AioContext lock for the old AioContext of bs, but it
85
- * must not own the AioContext lock for new_context (unless new_context is
86
- * the same as the current context of bs). */
87
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
88
+/* @ignore will accumulate all visited BdrvChild object. The caller is
89
+ * responsible for freeing the list afterwards. */
90
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
91
+ AioContext *new_context, GSList **ignore)
92
{
93
BdrvChild *child;
94
95
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
96
bdrv_drained_begin(bs);
97
98
QLIST_FOREACH(child, &bs->children, next) {
99
- bdrv_set_aio_context(child->bs, new_context);
100
+ if (g_slist_find(*ignore, child)) {
101
+ continue;
102
+ }
103
+ *ignore = g_slist_prepend(*ignore, child);
104
+ bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
105
+ }
106
+ QLIST_FOREACH(child, &bs->parents, next_parent) {
107
+ if (g_slist_find(*ignore, child)) {
108
+ continue;
109
+ }
110
+ if (child->role->set_aio_ctx) {
111
+ *ignore = g_slist_prepend(*ignore, child);
112
+ child->role->set_aio_ctx(child, new_context, ignore);
113
+ }
114
}
115
116
bdrv_detach_aio_context(bs);
117
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
118
aio_context_release(new_context);
119
}
120
121
+/* The caller must own the AioContext lock for the old AioContext of bs, but it
122
+ * must not own the AioContext lock for new_context (unless new_context is
123
+ * the same as the current context of bs). */
124
+void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
125
+{
126
+ GSList *ignore_list = NULL;
127
+ bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
128
+ g_slist_free(ignore_list);
129
+}
130
+
131
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
132
GSList **ignore, Error **errp)
133
{
134
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
135
return -EPERM;
136
}
137
138
- bdrv_set_aio_context(bs, ctx);
139
+ ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
140
+ bdrv_set_aio_context_ignore(bs, ctx, &ignore);
141
+ g_slist_free(ignore);
142
+
143
return 0;
144
}
145
146
--
147
2.20.1
148
149
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-block-iothread.c | 131 ++++++++++++++++++++++++++++++++++++
4
1 file changed, 131 insertions(+)
1
5
6
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
7
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-block-iothread.c
9
+++ b/tests/test-block-iothread.c
10
@@ -XXX,XX +XXX,XX @@
11
#include "block/blockjob_int.h"
12
#include "sysemu/block-backend.h"
13
#include "qapi/error.h"
14
+#include "qapi/qmp/qdict.h"
15
#include "iothread.h"
16
17
static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs,
18
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
19
blk_unref(blk);
20
}
21
22
+/*
23
+ * Test that changing the AioContext for one node in a tree (here through blk)
24
+ * changes all other nodes as well:
25
+ *
26
+ * blk
27
+ * |
28
+ * | bs_verify [blkverify]
29
+ * | / \
30
+ * | / \
31
+ * bs_a [bdrv_test] bs_b [bdrv_test]
32
+ *
33
+ */
34
+static void test_propagate_basic(void)
35
+{
36
+ IOThread *iothread = iothread_new();
37
+ AioContext *ctx = iothread_get_aio_context(iothread);
38
+ BlockBackend *blk;
39
+ BlockDriverState *bs_a, *bs_b, *bs_verify;
40
+ QDict *options;
41
+
42
+ /* Create bs_a and its BlockBackend */
43
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
44
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
45
+ blk_insert_bs(blk, bs_a, &error_abort);
46
+
47
+ /* Create bs_b */
48
+ bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
49
+
50
+ /* Create blkverify filter that references both bs_a and bs_b */
51
+ options = qdict_new();
52
+ qdict_put_str(options, "driver", "blkverify");
53
+ qdict_put_str(options, "test", "bs_a");
54
+ qdict_put_str(options, "raw", "bs_b");
55
+
56
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
57
+
58
+ /* Switch the AioContext */
59
+ blk_set_aio_context(blk, ctx);
60
+ g_assert(blk_get_aio_context(blk) == ctx);
61
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
62
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
63
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
64
+
65
+ /* Switch the AioContext back */
66
+ ctx = qemu_get_aio_context();
67
+ blk_set_aio_context(blk, ctx);
68
+ g_assert(blk_get_aio_context(blk) == ctx);
69
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
70
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
71
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
72
+
73
+ bdrv_unref(bs_verify);
74
+ bdrv_unref(bs_b);
75
+ bdrv_unref(bs_a);
76
+ blk_unref(blk);
77
+}
78
+
79
+/*
80
+ * Test that diamonds in the graph don't lead to endless recursion:
81
+ *
82
+ * blk
83
+ * |
84
+ * bs_verify [blkverify]
85
+ * / \
86
+ * / \
87
+ * bs_b [raw] bs_c[raw]
88
+ * \ /
89
+ * \ /
90
+ * bs_a [bdrv_test]
91
+ */
92
+static void test_propagate_diamond(void)
93
+{
94
+ IOThread *iothread = iothread_new();
95
+ AioContext *ctx = iothread_get_aio_context(iothread);
96
+ BlockBackend *blk;
97
+ BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
98
+ QDict *options;
99
+
100
+ /* Create bs_a */
101
+ bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
102
+
103
+ /* Create bs_b and bc_c */
104
+ options = qdict_new();
105
+ qdict_put_str(options, "driver", "raw");
106
+ qdict_put_str(options, "file", "bs_a");
107
+ qdict_put_str(options, "node-name", "bs_b");
108
+ bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
109
+
110
+ options = qdict_new();
111
+ qdict_put_str(options, "driver", "raw");
112
+ qdict_put_str(options, "file", "bs_a");
113
+ qdict_put_str(options, "node-name", "bs_c");
114
+ bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
115
+
116
+ /* Create blkverify filter that references both bs_b and bs_c */
117
+ options = qdict_new();
118
+ qdict_put_str(options, "driver", "blkverify");
119
+ qdict_put_str(options, "test", "bs_b");
120
+ qdict_put_str(options, "raw", "bs_c");
121
+
122
+ bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
123
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
124
+ blk_insert_bs(blk, bs_verify, &error_abort);
125
+
126
+ /* Switch the AioContext */
127
+ blk_set_aio_context(blk, ctx);
128
+ g_assert(blk_get_aio_context(blk) == ctx);
129
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
130
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
131
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
132
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
133
+
134
+ /* Switch the AioContext back */
135
+ ctx = qemu_get_aio_context();
136
+ blk_set_aio_context(blk, ctx);
137
+ g_assert(blk_get_aio_context(blk) == ctx);
138
+ g_assert(bdrv_get_aio_context(bs_verify) == ctx);
139
+ g_assert(bdrv_get_aio_context(bs_a) == ctx);
140
+ g_assert(bdrv_get_aio_context(bs_b) == ctx);
141
+ g_assert(bdrv_get_aio_context(bs_c) == ctx);
142
+
143
+ blk_unref(blk);
144
+ bdrv_unref(bs_verify);
145
+ bdrv_unref(bs_c);
146
+ bdrv_unref(bs_b);
147
+ bdrv_unref(bs_a);
148
+}
149
+
150
int main(int argc, char **argv)
151
{
152
int i;
153
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
154
}
155
156
g_test_add_func("/attach/blockjob", test_attach_blockjob);
157
+ g_test_add_func("/propagate/basic", test_propagate_basic);
158
+ g_test_add_func("/propagate/diamond", test_propagate_diamond);
159
160
return g_test_run();
161
}
162
--
163
2.20.1
164
165
diff view generated by jsdifflib
New patch
1
bdrv_try_set_aio_context() currently fails if a BlockBackend is attached
2
to a node because it doesn't implement the BdrvChildRole callbacks for
3
AioContext management.
1
4
5
We can allow changing the AioContext of monitor-owned BlockBackends as
6
long as no device is attached to them.
7
8
When setting the AioContext of the root node of a BlockBackend, we now
9
need to pass blk->root as an ignored child because we don't want the
10
root node to recursively call back into BlockBackend and execute
11
blk_do_set_aio_context() a second time.
12
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/block-backend.c | 45 +++++++++++++++++++++++++++++++++++++++++--
16
1 file changed, 43 insertions(+), 2 deletions(-)
17
18
diff --git a/block/block-backend.c b/block/block-backend.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/block-backend.c
21
+++ b/block/block-backend.c
22
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child);
23
static void blk_root_change_media(BdrvChild *child, bool load);
24
static void blk_root_resize(BdrvChild *child);
25
26
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
27
+ GSList **ignore, Error **errp);
28
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
29
+ GSList **ignore);
30
+
31
static char *blk_root_get_parent_desc(BdrvChild *child)
32
{
33
BlockBackend *blk = child->opaque;
34
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
35
36
.attach = blk_root_attach,
37
.detach = blk_root_detach,
38
+
39
+ .can_set_aio_ctx = blk_root_can_set_aio_ctx,
40
+ .set_aio_ctx = blk_root_set_aio_ctx,
41
};
42
43
/*
44
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
45
return blk_get_aio_context(blk_acb->blk);
46
}
47
48
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
49
+static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
50
+ bool update_root_node)
51
{
52
BlockDriverState *bs = blk_bs(blk);
53
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
54
@@ -XXX,XX +XXX,XX @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
55
throttle_group_attach_aio_context(tgm, new_context);
56
bdrv_drained_end(bs);
57
}
58
- bdrv_set_aio_context(bs, new_context);
59
+ if (update_root_node) {
60
+ GSList *ignore = g_slist_prepend(NULL, blk->root);
61
+ bdrv_set_aio_context_ignore(bs, new_context, &ignore);
62
+ g_slist_free(ignore);
63
+ }
64
}
65
}
66
67
+void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
68
+{
69
+ blk_do_set_aio_context(blk, new_context, true);
70
+}
71
+
72
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
73
+ GSList **ignore, Error **errp)
74
+{
75
+ BlockBackend *blk = child->opaque;
76
+
77
+ /* Only manually created BlockBackends that are not attached to anything
78
+ * can change their AioContext without updating their user. */
79
+ if (!blk->name || blk->dev) {
80
+ /* TODO Add BB name/QOM path */
81
+ error_setg(errp, "Cannot change iothread of active block backend");
82
+ return false;
83
+ }
84
+
85
+ return true;
86
+}
87
+
88
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
89
+ GSList **ignore)
90
+{
91
+ BlockBackend *blk = child->opaque;
92
+ blk_do_set_aio_context(blk, ctx, false);
93
+}
94
+
95
void blk_add_aio_context_notifier(BlockBackend *blk,
96
void (*attached_aio_context)(AioContext *new_context, void *opaque),
97
void (*detach_aio_context)(void *opaque), void *opaque)
98
--
99
2.20.1
100
101
diff view generated by jsdifflib
New patch
1
Some users (like block jobs) can tolerate an AioContext change for their
2
BlockBackend. Add a function that tells the BlockBackend that it can
3
allow changes.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
include/sysemu/block-backend.h | 1 +
8
block/block-backend.c | 10 ++++++++++
9
2 files changed, 11 insertions(+)
10
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
12
index XXXXXXX..XXXXXXX 100644
13
--- a/include/sysemu/block-backend.h
14
+++ b/include/sysemu/block-backend.h
15
@@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
16
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
17
18
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
19
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow);
20
void blk_iostatus_enable(BlockBackend *blk);
21
bool blk_iostatus_is_enabled(const BlockBackend *blk);
22
BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
23
diff --git a/block/block-backend.c b/block/block-backend.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/block-backend.c
26
+++ b/block/block-backend.c
27
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
28
uint64_t shared_perm;
29
bool disable_perm;
30
31
+ bool allow_aio_context_change;
32
bool allow_write_beyond_eof;
33
34
NotifierList remove_bs_notifiers, insert_bs_notifiers;
35
@@ -XXX,XX +XXX,XX @@ void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow)
36
blk->allow_write_beyond_eof = allow;
37
}
38
39
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
40
+{
41
+ blk->allow_aio_context_change = allow;
42
+}
43
+
44
static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
45
size_t size)
46
{
47
@@ -XXX,XX +XXX,XX @@ static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
48
{
49
BlockBackend *blk = child->opaque;
50
51
+ if (blk->allow_aio_context_change) {
52
+ return true;
53
+ }
54
+
55
/* Only manually created BlockBackends that are not attached to anything
56
* can change their AioContext without updating their user. */
57
if (!blk->name || blk->dev) {
58
--
59
2.20.1
60
61
diff view generated by jsdifflib
New patch
1
Block jobs require that all of the nodes the job is using are in the
2
same AioContext. Therefore all BdrvChild objects of the job propagate
3
.(can_)set_aio_context to all other job nodes, so that the switch is
4
checked and performed consistently even if both nodes are in different
5
subtrees.
1
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
block/backup.c | 8 --------
10
block/mirror.c | 10 +---------
11
blockjob.c | 34 ++++++++++++++++++++++++++++++++++
12
3 files changed, 35 insertions(+), 17 deletions(-)
13
14
diff --git a/block/backup.c b/block/backup.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/backup.c
17
+++ b/block/backup.c
18
@@ -XXX,XX +XXX,XX @@ static void backup_clean(Job *job)
19
s->target = NULL;
20
}
21
22
-static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
23
-{
24
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
25
-
26
- blk_set_aio_context(s->target, aio_context);
27
-}
28
-
29
void backup_do_checkpoint(BlockJob *job, Error **errp)
30
{
31
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
32
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
33
.abort = backup_abort,
34
.clean = backup_clean,
35
},
36
- .attached_aio_context = backup_attached_aio_context,
37
.drain = backup_drain,
38
};
39
40
diff --git a/block/mirror.c b/block/mirror.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block/mirror.c
43
+++ b/block/mirror.c
44
@@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job)
45
return !!s->in_flight;
46
}
47
48
-static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context)
49
-{
50
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
51
-
52
- blk_set_aio_context(s->target, new_context);
53
-}
54
-
55
static void mirror_drain(BlockJob *job)
56
{
57
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
58
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
59
.complete = mirror_complete,
60
},
61
.drained_poll = mirror_drained_poll,
62
- .attached_aio_context = mirror_attached_aio_context,
63
.drain = mirror_drain,
64
};
65
66
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
67
.complete = mirror_complete,
68
},
69
.drained_poll = mirror_drained_poll,
70
- .attached_aio_context = mirror_attached_aio_context,
71
.drain = mirror_drain,
72
};
73
74
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
75
* ensure that. */
76
blk_set_force_allow_inactivate(s->target);
77
}
78
+ blk_set_allow_aio_context_change(s->target, true);
79
80
s->replaces = g_strdup(replaces);
81
s->on_source_error = on_source_error;
82
diff --git a/blockjob.c b/blockjob.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/blockjob.c
85
+++ b/blockjob.c
86
@@ -XXX,XX +XXX,XX @@ static void child_job_drained_end(BdrvChild *c)
87
job_resume(&job->job);
88
}
89
90
+static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
91
+ GSList **ignore, Error **errp)
92
+{
93
+ BlockJob *job = c->opaque;
94
+ GSList *l;
95
+
96
+ for (l = job->nodes; l; l = l->next) {
97
+ BdrvChild *sibling = l->data;
98
+ if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) {
99
+ return false;
100
+ }
101
+ }
102
+ return true;
103
+}
104
+
105
+static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
106
+ GSList **ignore)
107
+{
108
+ BlockJob *job = c->opaque;
109
+ GSList *l;
110
+
111
+ for (l = job->nodes; l; l = l->next) {
112
+ BdrvChild *sibling = l->data;
113
+ if (g_slist_find(*ignore, sibling)) {
114
+ continue;
115
+ }
116
+ *ignore = g_slist_prepend(*ignore, sibling);
117
+ bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
118
+ }
119
+}
120
+
121
static const BdrvChildRole child_job = {
122
.get_parent_desc = child_job_get_parent_desc,
123
.drained_begin = child_job_drained_begin,
124
.drained_poll = child_job_drained_poll,
125
.drained_end = child_job_drained_end,
126
+ .can_set_aio_ctx = child_job_can_set_aio_ctx,
127
+ .set_aio_ctx = child_job_set_aio_ctx,
128
.stay_at_node = true,
129
};
130
131
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
132
133
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
134
block_job_detach_aio_context, job);
135
+ blk_set_allow_aio_context_change(blk, true);
136
137
/* Only set speed when necessary to avoid NotSupported error */
138
if (speed != 0) {
139
--
140
2.20.1
141
142
diff view generated by jsdifflib
New patch
1
The notifiers made sure that the job is quiesced and that the
2
job->aio_context field is updated. The first part is unnecessary today
3
since bdrv_set_aio_context_ignore() drains the block node, and this
4
means drainig the block job, too. The second part can be done in the
5
.set_aio_ctx callback of the block job BdrvChildRole.
1
6
7
The notifiers were problematic because they poll the AioContext while
8
the graph is in an inconsistent state with some nodes already in the new
9
context, but others still in the old context. So removing the notifiers
10
not only simplifies the code, but actually makes the code safer.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
blockjob.c | 43 ++-----------------------------------------
15
1 file changed, 2 insertions(+), 41 deletions(-)
16
17
diff --git a/blockjob.c b/blockjob.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/blockjob.c
20
+++ b/blockjob.c
21
@@ -XXX,XX +XXX,XX @@ BlockJob *block_job_get(const char *id)
22
}
23
}
24
25
-static void block_job_attached_aio_context(AioContext *new_context,
26
- void *opaque);
27
-static void block_job_detach_aio_context(void *opaque);
28
-
29
void block_job_free(Job *job)
30
{
31
BlockJob *bjob = container_of(job, BlockJob, job);
32
@@ -XXX,XX +XXX,XX @@ void block_job_free(Job *job)
33
34
bs->job = NULL;
35
block_job_remove_all_bdrv(bjob);
36
- blk_remove_aio_context_notifier(bjob->blk,
37
- block_job_attached_aio_context,
38
- block_job_detach_aio_context, bjob);
39
blk_unref(bjob->blk);
40
error_free(bjob->blocker);
41
}
42
43
-static void block_job_attached_aio_context(AioContext *new_context,
44
- void *opaque)
45
-{
46
- BlockJob *job = opaque;
47
- const JobDriver *drv = job->job.driver;
48
- BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
49
-
50
- job->job.aio_context = new_context;
51
- if (bjdrv->attached_aio_context) {
52
- bjdrv->attached_aio_context(job, new_context);
53
- }
54
-
55
- job_resume(&job->job);
56
-}
57
-
58
void block_job_drain(Job *job)
59
{
60
BlockJob *bjob = container_of(job, BlockJob, job);
61
@@ -XXX,XX +XXX,XX @@ void block_job_drain(Job *job)
62
}
63
}
64
65
-static void block_job_detach_aio_context(void *opaque)
66
-{
67
- BlockJob *job = opaque;
68
-
69
- /* In case the job terminates during aio_poll()... */
70
- job_ref(&job->job);
71
-
72
- job_pause(&job->job);
73
-
74
- while (!job->job.paused && !job_is_completed(&job->job)) {
75
- job_drain(&job->job);
76
- }
77
-
78
- job->job.aio_context = NULL;
79
- job_unref(&job->job);
80
-}
81
-
82
static char *child_job_get_parent_desc(BdrvChild *c)
83
{
84
BlockJob *job = c->opaque;
85
@@ -XXX,XX +XXX,XX @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
86
*ignore = g_slist_prepend(*ignore, sibling);
87
bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
88
}
89
+
90
+ job->job.aio_context = ctx;
91
}
92
93
static const BdrvChildRole child_job = {
94
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
95
96
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
97
98
- blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
99
- block_job_detach_aio_context, job);
100
blk_set_allow_aio_context_change(blk, true);
101
102
/* Only set speed when necessary to avoid NotSupported error */
103
--
104
2.20.1
105
106
diff view generated by jsdifflib
New patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
3
tests/test-block-iothread.c | 71 +++++++++++++++++++++++++++++++++++++
4
1 file changed, 71 insertions(+)
1
5
6
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
7
index XXXXXXX..XXXXXXX 100644
8
--- a/tests/test-block-iothread.c
9
+++ b/tests/test-block-iothread.c
10
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
11
bdrv_unref(bs_a);
12
}
13
14
+static void test_propagate_mirror(void)
15
+{
16
+ IOThread *iothread = iothread_new();
17
+ AioContext *ctx = iothread_get_aio_context(iothread);
18
+ AioContext *main_ctx = qemu_get_aio_context();
19
+ BlockDriverState *src, *target;
20
+ BlockBackend *blk;
21
+ Job *job;
22
+ Error *local_err = NULL;
23
+
24
+ /* Create src and target*/
25
+ src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
26
+ target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
27
+ &error_abort);
28
+
29
+ /* Start a mirror job */
30
+ mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
31
+ MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
32
+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
33
+ false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
34
+ &error_abort);
35
+ job = job_get("job0");
36
+
37
+ /* Change the AioContext of src */
38
+ bdrv_try_set_aio_context(src, ctx, &error_abort);
39
+ g_assert(bdrv_get_aio_context(src) == ctx);
40
+ g_assert(bdrv_get_aio_context(target) == ctx);
41
+ g_assert(job->aio_context == ctx);
42
+
43
+ /* Change the AioContext of target */
44
+ aio_context_acquire(ctx);
45
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
46
+ aio_context_release(ctx);
47
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
48
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
49
+
50
+ /* With a BlockBackend on src, changing target must fail */
51
+ blk = blk_new(0, BLK_PERM_ALL);
52
+ blk_insert_bs(blk, src, &error_abort);
53
+
54
+ bdrv_try_set_aio_context(target, ctx, &local_err);
55
+ g_assert(local_err);
56
+ error_free(local_err);
57
+
58
+ g_assert(blk_get_aio_context(blk) == main_ctx);
59
+ g_assert(bdrv_get_aio_context(src) == main_ctx);
60
+ g_assert(bdrv_get_aio_context(target) == main_ctx);
61
+
62
+ /* ...unless we explicitly allow it */
63
+ aio_context_acquire(ctx);
64
+ blk_set_allow_aio_context_change(blk, true);
65
+ bdrv_try_set_aio_context(target, ctx, &error_abort);
66
+ aio_context_release(ctx);
67
+
68
+ g_assert(blk_get_aio_context(blk) == ctx);
69
+ g_assert(bdrv_get_aio_context(src) == ctx);
70
+ g_assert(bdrv_get_aio_context(target) == ctx);
71
+
72
+ job_cancel_sync_all();
73
+
74
+ aio_context_acquire(ctx);
75
+ blk_set_aio_context(blk, main_ctx);
76
+ bdrv_try_set_aio_context(target, main_ctx, &error_abort);
77
+ aio_context_release(ctx);
78
+
79
+ blk_unref(blk);
80
+ bdrv_unref(src);
81
+ bdrv_unref(target);
82
+}
83
+
84
int main(int argc, char **argv)
85
{
86
int i;
87
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
88
g_test_add_func("/attach/blockjob", test_attach_blockjob);
89
g_test_add_func("/propagate/basic", test_propagate_basic);
90
g_test_add_func("/propagate/diamond", test_propagate_diamond);
91
+ g_test_add_func("/propagate/mirror", test_propagate_mirror);
92
93
return g_test_run();
94
}
95
--
96
2.20.1
97
98
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
Currently, qemu crashes whenever someone queries the block status of an
4
unaligned image tail of an O_DIRECT image:
5
$ echo > foo
6
$ qemu-img map --image-opts driver=file,filename=foo,cache.direct=on
7
Offset Length Mapped to File
8
qemu-img: block/io.c:2093: bdrv_co_block_status: Assertion `*pnum &&
9
QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset'
10
failed.
11
12
This is because bdrv_co_block_status() checks that the result returned
13
by the driver's implementation is aligned to the request_alignment, but
14
file-posix can fail to do so, which is actually mentioned in a comment
15
there: "[...] possibly including a partial sector at EOF".
16
17
Fix this by rounding up those partial sectors.
18
19
There are two possible alternative fixes:
20
(1) We could refuse to open unaligned image files with O_DIRECT
21
altogether. That sounds reasonable until you realize that qcow2
22
does necessarily not fill up its metadata clusters, and that nobody
23
runs qemu-img create with O_DIRECT. Therefore, unpreallocated qcow2
24
files usually have an unaligned image tail.
25
26
(2) bdrv_co_block_status() could ignore unaligned tails. It actually
27
throws away everything past the EOF already, so that sounds
28
reasonable.
29
Unfortunately, the block layer knows file lengths only with a
30
granularity of BDRV_SECTOR_SIZE, so bdrv_co_block_status() usually
31
would have to guess whether its file length information is inexact
32
or whether the driver is broken.
33
34
Fixing what raw_co_block_status() returns is the safest thing to do.
35
36
There seems to be no other block driver that sets request_alignment and
37
does not make sure that it always returns aligned values.
38
39
Cc: qemu-stable@nongnu.org
40
Signed-off-by: Max Reitz <mreitz@redhat.com>
41
Reviewed-by: Eric Blake <eblake@redhat.com>
42
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
43
---
44
block/file-posix.c | 16 ++++++++++++++++
45
1 file changed, 16 insertions(+)
46
47
diff --git a/block/file-posix.c b/block/file-posix.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/file-posix.c
50
+++ b/block/file-posix.c
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
52
off_t data = 0, hole = 0;
53
int ret;
54
55
+ assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
56
+
57
ret = fd_open(bs);
58
if (ret < 0) {
59
return ret;
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
61
/* On a data extent, compute bytes to the end of the extent,
62
* possibly including a partial sector at EOF. */
63
*pnum = MIN(bytes, hole - offset);
64
+
65
+ /*
66
+ * We are not allowed to return partial sectors, though, so
67
+ * round up if necessary.
68
+ */
69
+ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
70
+ int64_t file_length = raw_getlength(bs);
71
+ if (file_length > 0) {
72
+ /* Ignore errors, this is just a safeguard */
73
+ assert(hole == file_length);
74
+ }
75
+ *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
76
+ }
77
+
78
ret = BDRV_BLOCK_DATA;
79
} else {
80
/* On a hole, compute bytes to the beginning of the next extent. */
81
--
82
2.20.1
83
84
diff view generated by jsdifflib
1
Check that block node activation and inactivation works with a block
1
From: Max Reitz <mreitz@redhat.com>
2
graph that is built with individually created nodes.
3
2
3
We already have 221 for accesses through the page cache, but it is
4
better to create a new file for O_DIRECT instead of integrating those
5
test cases into 221. This way, we can make use of
6
_supported_cache_modes (and _default_cache_mode) so the test is
7
automatically skipped on filesystems that do not support O_DIRECT.
8
9
As part of the split, add _supported_cache_modes to 221. With that, it
10
no longer fails when run with -c none or -c directsync.
11
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
15
---
7
tests/qemu-iotests/234 | 121 +++++++++++++++++++++++++++++++++++++
16
tests/qemu-iotests/221 | 4 ++
8
tests/qemu-iotests/234.out | 30 +++++++++
17
tests/qemu-iotests/253 | 84 ++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/group | 1 +
18
tests/qemu-iotests/253.out | 14 +++++++
10
3 files changed, 152 insertions(+)
19
tests/qemu-iotests/group | 1 +
11
create mode 100755 tests/qemu-iotests/234
20
4 files changed, 103 insertions(+)
12
create mode 100644 tests/qemu-iotests/234.out
21
create mode 100755 tests/qemu-iotests/253
22
create mode 100644 tests/qemu-iotests/253.out
13
23
14
diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234
24
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
25
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/221
27
+++ b/tests/qemu-iotests/221
28
@@ -XXX,XX +XXX,XX @@
29
#!/usr/bin/env bash
30
#
31
# Test qemu-img vs. unaligned images
32
+# (See also 253, which is the O_DIRECT version)
33
#
34
# Copyright (C) 2018-2019 Red Hat, Inc.
35
#
36
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
37
_supported_proto file
38
_supported_os Linux
39
40
+_default_cache_mode writeback
41
+_supported_cache_modes writeback writethrough unsafe
42
+
43
echo
44
echo "=== Check mapping of unaligned raw image ==="
45
echo
46
diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253
15
new file mode 100755
47
new file mode 100755
16
index XXXXXXX..XXXXXXX
48
index XXXXXXX..XXXXXXX
17
--- /dev/null
49
--- /dev/null
18
+++ b/tests/qemu-iotests/234
50
+++ b/tests/qemu-iotests/253
19
@@ -XXX,XX +XXX,XX @@
51
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python
52
+#!/usr/bin/env bash
21
+#
53
+#
22
+# Copyright (C) 2018 Red Hat, Inc.
54
+# Test qemu-img vs. unaligned images; O_DIRECT version
55
+# (Originates from 221)
56
+#
57
+# Copyright (C) 2019 Red Hat, Inc.
23
+#
58
+#
24
+# This program is free software; you can redistribute it and/or modify
59
+# This program is free software; you can redistribute it and/or modify
25
+# it under the terms of the GNU General Public License as published by
60
+# it under the terms of the GNU General Public License as published by
26
+# the Free Software Foundation; either version 2 of the License, or
61
+# the Free Software Foundation; either version 2 of the License, or
27
+# (at your option) any later version.
62
+# (at your option) any later version.
...
...
32
+# GNU General Public License for more details.
67
+# GNU General Public License for more details.
33
+#
68
+#
34
+# You should have received a copy of the GNU General Public License
69
+# You should have received a copy of the GNU General Public License
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
70
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
36
+#
71
+#
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
38
+#
39
+# Check that block node activation and inactivation works with a block graph
40
+# that is built with individually created nodes
41
+
72
+
42
+import iotests
73
+seq="$(basename $0)"
43
+import os
74
+echo "QA output created by $seq"
44
+
75
+
45
+iotests.verify_image_format(supported_fmts=['qcow2'])
76
+status=1 # failure is the default!
46
+iotests.verify_platform(['linux'])
47
+
77
+
48
+with iotests.FilePath('img') as img_path, \
78
+_cleanup()
49
+ iotests.FilePath('backing') as backing_path, \
79
+{
50
+ iotests.FilePath('mig_fifo_a') as fifo_a, \
80
+ _cleanup_test_img
51
+ iotests.FilePath('mig_fifo_b') as fifo_b, \
81
+}
52
+ iotests.VM(path_suffix='a') as vm_a, \
82
+trap "_cleanup; exit \$status" 0 1 2 3 15
53
+ iotests.VM(path_suffix='b') as vm_b:
54
+
83
+
55
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, backing_path, '64M')
84
+# get standard environment, filters and checks
56
+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, img_path, '64M')
85
+. ./common.rc
86
+. ./common.filter
57
+
87
+
58
+ os.mkfifo(fifo_a)
88
+_supported_fmt raw
59
+ os.mkfifo(fifo_b)
89
+_supported_proto file
90
+_supported_os Linux
60
+
91
+
61
+ iotests.log('Launching source VM...')
92
+_default_cache_mode none
62
+ (vm_a.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path))
93
+_supported_cache_modes none directsync
63
+ .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt))
64
+ .add_blockdev('file,filename=%s,node-name=drive0-backing-file' % (backing_path))
65
+ .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt))
66
+ .launch())
67
+
94
+
68
+ iotests.log('Launching destination VM...')
95
+echo
69
+ (vm_b.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path))
96
+echo "=== Check mapping of unaligned raw image ==="
70
+ .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt))
97
+echo
71
+ .add_blockdev('file,filename=%s,node-name=drive0-backing-file' % (backing_path))
72
+ .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt))
73
+ .add_incoming("exec: cat '%s'" % (fifo_a))
74
+ .launch())
75
+
98
+
76
+ # Add a child node that was created after the parent node. The reverse case
99
+# We do not know how large a physical sector is, but it is certainly
77
+ # is covered by the -blockdev options above.
100
+# going to be a factor of 1 MB
78
+ iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing',
101
+size=$((1 * 1024 * 1024 - 1))
79
+ overlay='drive0'))
80
+ iotests.log(vm_b.qmp('blockdev-snapshot', node='drive0-backing',
81
+ overlay='drive0'))
82
+
102
+
83
+ iotests.log('Enabling migration QMP events on A...')
103
+# qemu-img create rounds size up to BDRV_SECTOR_SIZE
84
+ iotests.log(vm_a.qmp('migrate-set-capabilities', capabilities=[
104
+_make_test_img $size
85
+ {
105
+$QEMU_IMG map --output=json --image-opts \
86
+ 'capability': 'events',
106
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
87
+ 'state': True
107
+ | _filter_qemu_img_map
88
+ }
89
+ ]))
90
+
108
+
91
+ iotests.log('Starting migration to B...')
109
+# so we resize it and check again
92
+ iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo_a)))
110
+truncate --size=$size "$TEST_IMG"
93
+ with iotests.Timeout(3, 'Migration does not complete'):
111
+$QEMU_IMG map --output=json --image-opts \
94
+ while True:
112
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
95
+ event = vm_a.event_wait('MIGRATION')
113
+ | _filter_qemu_img_map
96
+ iotests.log(event, filters=[iotests.filter_qmp_event])
97
+ if event['data']['status'] == 'completed':
98
+ break
99
+
114
+
100
+ iotests.log(vm_a.qmp('query-migrate')['return']['status'])
115
+# qemu-io with O_DIRECT always writes whole physical sectors. Again,
101
+ iotests.log(vm_b.qmp('query-migrate')['return']['status'])
116
+# we do not know how large a physical sector is, so we just start
117
+# writing from a 64 kB boundary, which should always be aligned.
118
+offset=$((1 * 1024 * 1024 - 64 * 1024))
119
+$QEMU_IO -c "w $offset $((size - offset))" "$TEST_IMG" | _filter_qemu_io
120
+$QEMU_IMG map --output=json --image-opts \
121
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
122
+ | _filter_qemu_img_map
102
+
123
+
103
+ iotests.log(vm_a.qmp('query-status'))
124
+# Resize it and check again -- contrary to 221, we may not get partial
104
+ iotests.log(vm_b.qmp('query-status'))
125
+# sectors here, so there should be only two areas (one zero, one
126
+# data).
127
+truncate --size=$size "$TEST_IMG"
128
+$QEMU_IMG map --output=json --image-opts \
129
+ "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
130
+ | _filter_qemu_img_map
105
+
131
+
106
+ iotests.log('Add a second parent to drive0-file...')
132
+# success, all done
107
+ iotests.log(vm_b.qmp('blockdev-add', driver='raw', file='drive0-file',
133
+echo '*** done'
108
+ node_name='drive0-raw'))
134
+rm -f $seq.full
109
+
135
+status=0
110
+ iotests.log('Restart A with -incoming and second parent...')
136
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
111
+ vm_a.shutdown()
112
+ (vm_a.add_blockdev('raw,file=drive0-file,node-name=drive0-raw')
113
+ .add_incoming("exec: cat '%s'" % (fifo_b))
114
+ .launch())
115
+
116
+ iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing',
117
+ overlay='drive0'))
118
+
119
+ iotests.log('Enabling migration QMP events on B...')
120
+ iotests.log(vm_b.qmp('migrate-set-capabilities', capabilities=[
121
+ {
122
+ 'capability': 'events',
123
+ 'state': True
124
+ }
125
+ ]))
126
+
127
+ iotests.log('Starting migration back to A...')
128
+ iotests.log(vm_b.qmp('migrate', uri='exec:cat >%s' % (fifo_b)))
129
+ with iotests.Timeout(3, 'Migration does not complete'):
130
+ while True:
131
+ event = vm_b.event_wait('MIGRATION')
132
+ iotests.log(event, filters=[iotests.filter_qmp_event])
133
+ if event['data']['status'] == 'completed':
134
+ break
135
+
136
+ iotests.log(vm_a.qmp('query-migrate')['return']['status'])
137
+ iotests.log(vm_b.qmp('query-migrate')['return']['status'])
138
+
139
+ iotests.log(vm_a.qmp('query-status'))
140
+ iotests.log(vm_b.qmp('query-status'))
141
diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out
142
new file mode 100644
137
new file mode 100644
143
index XXXXXXX..XXXXXXX
138
index XXXXXXX..XXXXXXX
144
--- /dev/null
139
--- /dev/null
145
+++ b/tests/qemu-iotests/234.out
140
+++ b/tests/qemu-iotests/253.out
146
@@ -XXX,XX +XXX,XX @@
141
@@ -XXX,XX +XXX,XX @@
147
+Launching source VM...
142
+QA output created by 253
148
+Launching destination VM...
143
+
149
+{"return": {}}
144
+=== Check mapping of unaligned raw image ===
150
+{"return": {}}
145
+
151
+Enabling migration QMP events on A...
146
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
152
+{"return": {}}
147
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
153
+Starting migration to B...
148
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
154
+{"return": {}}
149
+wrote 65535/65535 bytes at offset 983040
155
+{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
150
+63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
+{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
151
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
157
+{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
152
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
158
+completed
153
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
159
+completed
154
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
160
+{"return": {"running": false, "singlestep": false, "status": "postmigrate"}}
155
+*** done
161
+{"return": {"running": true, "singlestep": false, "status": "running"}}
162
+Add a second parent to drive0-file...
163
+{"return": {}}
164
+Restart A with -incoming and second parent...
165
+{"return": {}}
166
+Enabling migration QMP events on B...
167
+{"return": {}}
168
+Starting migration back to A...
169
+{"return": {}}
170
+{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
171
+{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
172
+{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
173
+completed
174
+completed
175
+{"return": {"running": true, "singlestep": false, "status": "running"}}
176
+{"return": {"running": false, "singlestep": false, "status": "postmigrate"}}
177
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
156
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
178
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
179
--- a/tests/qemu-iotests/group
158
--- a/tests/qemu-iotests/group
180
+++ b/tests/qemu-iotests/group
159
+++ b/tests/qemu-iotests/group
181
@@ -XXX,XX +XXX,XX @@
160
@@ -XXX,XX +XXX,XX @@
182
231 auto quick
161
248 rw auto quick
183
232 auto quick
162
249 rw auto quick
184
233 auto quick
163
252 rw auto backing quick
185
+234 auto quick migration
164
+253 rw auto quick
186
--
165
--
187
2.19.1
166
2.20.1
188
167
189
168
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
Just writing that --output=json outputs JSON information does not really
4
help; we should also make a note of what QAPI type the result object
5
has. (The map subcommand does not emit a QAPI-typed object, but its
6
section already describes the object structure well enough.)
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
qemu-img.texi | 11 ++++++++---
12
1 file changed, 8 insertions(+), 3 deletions(-)
13
14
diff --git a/qemu-img.texi b/qemu-img.texi
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.texi
17
+++ b/qemu-img.texi
18
@@ -XXX,XX +XXX,XX @@ overridden with a pattern byte specified by @var{pattern}.
19
20
Perform a consistency check on the disk image @var{filename}. The command can
21
output in the format @var{ofmt} which is either @code{human} or @code{json}.
22
+The JSON output is an object of QAPI type @code{ImageCheck}.
23
24
If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
25
during the check. @code{-r leaks} repairs only cluster leaks, whereas
26
@@ -XXX,XX +XXX,XX @@ The size syntax is similar to dd(1)'s size syntax.
27
Give information about the disk image @var{filename}. Use it in
28
particular to know the size reserved on disk which can be different
29
from the displayed size. If VM snapshots are stored in the disk image,
30
-they are displayed too. The command can output in the format @var{ofmt}
31
-which is either @code{human} or @code{json}.
32
+they are displayed too.
33
34
If a disk image has a backing file chain, information about each disk image in
35
the chain can be recursively enumerated by using the option @code{--backing-chain}.
36
@@ -XXX,XX +XXX,XX @@ To enumerate information about each disk image in the above chain, starting from
37
qemu-img info --backing-chain snap2.qcow2
38
@end example
39
40
+The command can output in the format @var{ofmt} which is either @code{human} or
41
+@code{json}. The JSON output is an object of QAPI type @code{ImageInfo}; with
42
+@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
43
+
44
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
45
46
Dump the metadata of image @var{filename} and its backing file chain.
47
@@ -XXX,XX +XXX,XX @@ Calculate the file size required for a new image. This information can be used
48
to size logical volumes or SAN LUNs appropriately for the image that will be
49
placed in them. The values reported are guaranteed to be large enough to fit
50
the image. The command can output in the format @var{ofmt} which is either
51
-@code{human} or @code{json}.
52
+@code{human} or @code{json}. The JSON output is an object of QAPI type
53
+@code{BlockMeasureInfo}.
54
55
If the size @var{N} is given then act as if creating a new empty image file
56
using @command{qemu-img create}. If @var{filename} is given then act as if
57
--
58
2.20.1
59
60
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
Ideally, it should be self-explanatory. However, keys like "disk size"
4
arguably really are not self-explanatory. In any case, there is no harm
5
in going into a some more detail here.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
qemu-img.texi | 41 +++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 41 insertions(+)
12
13
diff --git a/qemu-img.texi b/qemu-img.texi
14
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-img.texi
16
+++ b/qemu-img.texi
17
@@ -XXX,XX +XXX,XX @@ The command can output in the format @var{ofmt} which is either @code{human} or
18
@code{json}. The JSON output is an object of QAPI type @code{ImageInfo}; with
19
@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
20
21
+@code{--output=human} reports the following information (for every image in the
22
+chain):
23
+@table @var
24
+@item image
25
+The image file name
26
+
27
+@item file format
28
+The image format
29
+
30
+@item virtual size
31
+The size of the guest disk
32
+
33
+@item disk size
34
+How much space the image file occupies on the host file system (may be shown as
35
+0 if this information is unavailable, e.g. because there is no file system)
36
+
37
+@item cluster_size
38
+Cluster size of the image format, if applicable
39
+
40
+@item encrypted
41
+Whether the image is encrypted (only present if so)
42
+
43
+@item cleanly shut down
44
+This is shown as @code{no} if the image is dirty and will have to be
45
+auto-repaired the next time it is opened in qemu.
46
+
47
+@item backing file
48
+The backing file name, if present
49
+
50
+@item backing file format
51
+The format of the backing file, if the image enforces it
52
+
53
+@item Snapshot list
54
+A list of all internal snapshots
55
+
56
+@item Format specific information
57
+Further information whose structure depends on the image format. This section
58
+is a textual representation of the respective @code{ImageInfoSpecific*} QAPI
59
+object (e.g. @code{ImageInfoSpecificQCow2} for qcow2 images).
60
+@end table
61
+
62
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
63
64
Dump the metadata of image @var{filename} and its backing file chain.
65
--
66
2.20.1
67
68
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
This message does not make any sense when it appears as the response to
4
making an R/W node read-only. We should detect that case and emit a
5
different message, then.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block.c | 17 ++++++++++++++++-
12
1 file changed, 16 insertions(+), 1 deletion(-)
13
14
diff --git a/block.c b/block.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
19
GSList *ignore_children, Error **errp);
20
static void bdrv_child_abort_perm_update(BdrvChild *c);
21
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
22
+static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
23
+ uint64_t *shared_perm);
24
25
typedef struct BlockReopenQueueEntry {
26
bool prepared;
27
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
28
if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
29
!bdrv_is_writable_after_reopen(bs, q))
30
{
31
- error_setg(errp, "Block node is read-only");
32
+ if (!bdrv_is_writable_after_reopen(bs, NULL)) {
33
+ error_setg(errp, "Block node is read-only");
34
+ } else {
35
+ uint64_t current_perms, current_shared;
36
+ bdrv_get_cumulative_perm(bs, &current_perms, &current_shared);
37
+ if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
38
+ error_setg(errp, "Cannot make block node read-only, there is "
39
+ "a writer on it");
40
+ } else {
41
+ error_setg(errp, "Cannot make block node read-only and create "
42
+ "a writer on it");
43
+ }
44
+ }
45
+
46
return -EPERM;
47
}
48
49
--
50
2.20.1
51
52
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
Sometimes we cannot tell which error message qemu will emit, and we do
4
not care. With this change, we can then just pass an array of all
5
possible messages to assert_qmp() and it will choose the right one.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
tests/qemu-iotests/iotests.py | 18 ++++++++++++++++--
12
1 file changed, 16 insertions(+), 2 deletions(-)
13
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
17
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
19
self.fail('path "%s" has value "%s"' % (path, str(result)))
20
21
def assert_qmp(self, d, path, value):
22
- '''Assert that the value for a specific path in a QMP dict matches'''
23
+ '''Assert that the value for a specific path in a QMP dict
24
+ matches. When given a list of values, assert that any of
25
+ them matches.'''
26
+
27
result = self.dictpath(d, path)
28
- self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
29
+
30
+ # [] makes no sense as a list of valid values, so treat it as
31
+ # an actual single value.
32
+ if isinstance(value, list) and value != []:
33
+ for v in value:
34
+ if result == v:
35
+ return
36
+ self.fail('no match for "%s" in %s' % (str(result), str(value)))
37
+ else:
38
+ self.assertEqual(result, value,
39
+ 'values not equal "%s" and "%s"'
40
+ % (str(result), str(value)))
41
42
def assert_no_active_block_jobs(self):
43
result = self.vm.qmp('query-block-jobs')
44
--
45
2.20.1
46
47
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
log() is in the current module, there is no need to prefix it. In fact,
4
doing so may make VM.run_job() unusable in tests that never use
5
iotests.log() themselves.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
tests/qemu-iotests/iotests.py | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
17
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
19
elif status == 'null':
20
return error
21
else:
22
- iotests.log(ev)
23
+ log(ev)
24
25
def node_info(self, node_name):
26
nodes = self.qmp('query-named-block-nodes')
27
--
28
2.20.1
29
30
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
Sometimes, 245 fails for me because some stream job has already finished
4
while the test expects it to still be active. (With -c none, it fails
5
basically every time.) The most reliable way to fix this is to simply
6
set auto_finalize=false so the job will remain in the block graph as
7
long as we need it. This allows us to drop the rate limiting, too,
8
which makes the test faster.
9
10
The only problem with this is that there is a single place that yields a
11
different error message depending on whether the stream job is still
12
copying data (so COR is enabled) or not (COR has been disabled, but the
13
job still has the WRITE_UNCHANGED permission on the target node). We
14
can easily address that by expecting either error message.
15
16
Note that we do not need auto_finalize=false (or rate limiting) for the
17
active commit job, because It never completes without an explicit
18
block-job-complete anyway.
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Alberto Garcia <berto@igalia.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
24
tests/qemu-iotests/245 | 22 ++++++++++++++--------
25
tests/qemu-iotests/245.out | 12 ++++++++++++
26
2 files changed, 26 insertions(+), 8 deletions(-)
27
28
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
29
index XXXXXXX..XXXXXXX 100644
30
--- a/tests/qemu-iotests/245
31
+++ b/tests/qemu-iotests/245
32
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
33
34
# hd2 <- hd0
35
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
36
- device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
37
+ device = 'hd0', base_node = 'hd2',
38
+ auto_finalize = False)
39
self.assert_qmp(result, 'return', {})
40
41
# We can't remove hd2 while the stream job is ongoing
42
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
43
opts['backing'] = None
44
self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
45
46
- self.wait_until_completed(drive = 'stream0')
47
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
48
49
# Reopen the chain during a block-stream job (from hd2 to hd1)
50
def test_block_stream_4(self):
51
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
52
53
# hd1 <- hd0
54
result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
55
- device = 'hd1', speed = 512 * 1024)
56
+ device = 'hd1', auto_finalize = False)
57
self.assert_qmp(result, 'return', {})
58
59
# We can't reopen with the original options because that would
60
# make hd1 read-only and block-stream requires it to be read-write
61
- self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
62
+ # (Which error message appears depends on whether the stream job is
63
+ # already done with copying at this point.)
64
+ self.reopen(opts, {},
65
+ ["Can't set node 'hd1' to r/o with copy-on-read enabled",
66
+ "Cannot make block node read-only, there is a writer on it"])
67
68
# We can't remove hd2 while the stream job is ongoing
69
opts['backing']['backing'] = None
70
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
71
opts['backing'] = None
72
self.reopen(opts)
73
74
- self.wait_until_completed(drive = 'stream0')
75
+ self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
76
77
# Reopen the chain during a block-commit job (from hd0 to hd2)
78
def test_block_commit_1(self):
79
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
80
self.assert_qmp(result, 'return', {})
81
82
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
83
- device = 'hd0', speed = 1024 * 1024)
84
+ device = 'hd0')
85
self.assert_qmp(result, 'return', {})
86
87
# We can't remove hd2 while the commit job is ongoing
88
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
89
self.assert_qmp(result, 'return', {})
90
91
result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
92
- device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
93
+ device = 'hd0', top_node = 'hd1',
94
+ auto_finalize = False)
95
self.assert_qmp(result, 'return', {})
96
97
# We can't remove hd2 while the commit job is ongoing
98
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
99
self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
100
101
# hd2 <- hd0
102
- self.wait_until_completed(drive = 'commit0')
103
+ self.vm.run_job('commit0', auto_finalize = False, auto_dismiss = True)
104
105
self.assert_qmp(self.get_node('hd0'), 'ro', False)
106
self.assertEqual(self.get_node('hd1'), None)
107
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
108
index XXXXXXX..XXXXXXX 100644
109
--- a/tests/qemu-iotests/245.out
110
+++ b/tests/qemu-iotests/245.out
111
@@ -XXX,XX +XXX,XX @@
112
Ran 18 tests
113
114
OK
115
+{"execute": "job-finalize", "arguments": {"id": "commit0"}}
116
+{"return": {}}
117
+{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
118
+{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
119
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
120
+{"return": {}}
121
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
122
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
123
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
124
+{"return": {}}
125
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
126
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
127
--
128
2.20.1
129
130
diff view generated by jsdifflib