1
The following changes since commit ad88e4252f09c2956b99c90de39e95bab2e8e7af:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-1-2019' into staging (2019-06-03 10:25:12 +0100)
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00: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 9593db8ccd27800ce4a17f1d5b735b9130c541a2:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
10
10
11
iotests: Fix duplicated diff output on failure (2019-06-03 16:33:20 +0200)
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- block: AioContext management, part 2
16
- Fix resize (extending) of short overlays
17
- Avoid recursive block_status call (i.e. lseek() calls) if possible
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- linux-aio: Drop unused BlockAIOCB submission method
18
- qemu-storage-daemon: Fix non-string --object properties
19
- nvme: add Get/Set Feature Timestamp support
20
- Fix crash on commit job start with active I/O on base node
21
- Fix crash in bdrv_drained_end
22
- Fix integer overflow in qcow2 discard
23
19
24
----------------------------------------------------------------
20
----------------------------------------------------------------
25
John Snow (1):
21
Alberto Garcia (1):
26
blockdev: fix missed target unref for drive-backup
22
qcow2: Add incompatibility note between backing files and raw external data files
27
23
28
Julia Suvorova (1):
24
Andrzej Jakowski (1):
29
block/linux-aio: Drop unused BlockAIOCB submission method
25
nvme: introduce PMR support from NVMe 1.4 spec
30
26
31
Kenneth Heitke (1):
27
Kevin Wolf (12):
32
nvme: add Get/Set Feature Timestamp support
28
block: Add flags to BlockDriver.bdrv_co_truncate()
29
block: Add flags to bdrv(_co)_truncate()
30
block-backend: Add flags to blk_truncate()
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
34
block: truncate: Don't make backing file data visible
35
iotests: Filter testfiles out in filter_img_info()
36
iotests: Test committing to short backing file
37
qcow2: Forward ZERO_WRITE flag for full preallocation
38
qom: Factor out user_creatable_add_dict()
39
qemu-storage-daemon: Fix non-string --object properties
33
40
34
Kevin Wolf (19):
41
Paolo Bonzini (1):
35
block: Drain source node in bdrv_replace_node()
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
36
iotests: Test commit job start with concurrent I/O
37
test-block-iothread: Check filter node in test_propagate_mirror
38
nbd-server: Call blk_set_allow_aio_context_change()
39
block: Add Error to blk_set_aio_context()
40
block: Add BlockBackend.ctx
41
block: Add qdev_prop_drive_iothread property type
42
scsi-disk: Use qdev_prop_drive_iothread
43
block: Adjust AioContexts when attaching nodes
44
test-block-iothread: Test adding parent to iothread node
45
test-block-iothread: BlockBackend AioContext across root node change
46
block: Move node without parents to main AioContext
47
blockdev: Use bdrv_try_set_aio_context() for monitor commands
48
block: Remove wrong bdrv_set_aio_context() calls
49
virtio-scsi-test: Test attaching new overlay with iothreads
50
iotests: Attach new devices to node in non-default iothread
51
test-bdrv-drain: Use bdrv_try_set_aio_context()
52
block: Remove bdrv_set_aio_context()
53
iotests: Fix duplicated diff output on failure
54
43
55
Max Reitz (2):
44
docs/interop/qcow2.txt | 3 +
56
block/io: Delay decrementing the quiesce_counter
45
hw/block/nvme.h | 2 +
57
iotests: Test cancelling a job and closing the VM
46
include/block/block.h | 5 +-
47
include/block/block_int.h | 10 +-
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
49
include/qom/object_interfaces.h | 16 +++
50
include/sysemu/block-backend.h | 2 +-
51
block.c | 3 +-
52
block/block-backend.c | 4 +-
53
block/commit.c | 4 +-
54
block/crypto.c | 7 +-
55
block/file-posix.c | 6 +-
56
block/file-win32.c | 2 +-
57
block/gluster.c | 1 +
58
block/io.c | 43 ++++++-
59
block/iscsi.c | 2 +-
60
block/mirror.c | 2 +-
61
block/nfs.c | 3 +-
62
block/parallels.c | 6 +-
63
block/qcow.c | 4 +-
64
block/qcow2-cluster.c | 2 +-
65
block/qcow2-refcount.c | 2 +-
66
block/qcow2.c | 73 +++++++++--
67
block/qed.c | 3 +-
68
block/raw-format.c | 6 +-
69
block/rbd.c | 1 +
70
block/sheepdog.c | 4 +-
71
block/ssh.c | 2 +-
72
block/vdi.c | 2 +-
73
block/vhdx-log.c | 2 +-
74
block/vhdx.c | 6 +-
75
block/vmdk.c | 8 +-
76
block/vpc.c | 2 +-
77
blockdev.c | 2 +-
78
hw/block/nvme.c | 109 ++++++++++++++++
79
qemu-img.c | 2 +-
80
qemu-io-cmds.c | 2 +-
81
qemu-storage-daemon.c | 4 +-
82
qom/object_interfaces.c | 31 +++++
83
qom/qom-qmp-cmds.c | 24 +---
84
tests/test-block-iothread.c | 9 +-
85
tests/qemu-iotests/iotests.py | 5 +-
86
hw/block/Makefile.objs | 2 +-
87
hw/block/trace-events | 4 +
88
tests/qemu-iotests/244 | 10 +-
89
tests/qemu-iotests/244.out | 9 +-
90
tests/qemu-iotests/274 | 155 +++++++++++++++++++++++
91
tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++
92
tests/qemu-iotests/group | 1 +
93
49 files changed, 951 insertions(+), 96 deletions(-)
94
create mode 100755 tests/qemu-iotests/274
95
create mode 100644 tests/qemu-iotests/274.out
58
96
59
Vladimir Sementsov-Ogievskiy (4):
60
tests/perf: Test lseek influence on qcow2 block-status
61
block: avoid recursive block_status call if possible
62
block/qcow2-refcount: add trace-point to qcow2_process_discards
63
block/io: bdrv_pdiscard: support int64_t bytes parameter
64
97
65
docs/devel/multiple-iothreads.txt | 4 +-
66
block/qcow2.h | 4 +
67
hw/block/nvme.h | 2 +
68
include/block/block.h | 21 ++---
69
include/block/block_int.h | 1 +
70
include/block/nvme.h | 2 +
71
include/block/raw-aio.h | 3 -
72
include/hw/block/block.h | 7 +-
73
include/hw/qdev-properties.h | 3 +
74
include/hw/scsi/scsi.h | 1 +
75
include/sysemu/block-backend.h | 5 +-
76
tests/libqtest.h | 11 +++
77
block.c | 79 ++++++++++++-----
78
block/backup.c | 3 +-
79
block/block-backend.c | 47 ++++++----
80
block/commit.c | 13 +--
81
block/crypto.c | 3 +-
82
block/io.c | 28 +++---
83
block/linux-aio.c | 72 +++------------
84
block/mirror.c | 4 +-
85
block/parallels.c | 3 +-
86
block/qcow.c | 3 +-
87
block/qcow2-refcount.c | 39 ++++++++-
88
block/qcow2.c | 17 +++-
89
block/qed.c | 3 +-
90
block/sheepdog.c | 3 +-
91
block/vdi.c | 3 +-
92
block/vhdx.c | 3 +-
93
block/vmdk.c | 3 +-
94
block/vpc.c | 3 +-
95
blockdev.c | 61 +++++++------
96
blockjob.c | 12 ++-
97
hmp.c | 3 +-
98
hw/block/dataplane/virtio-blk.c | 12 ++-
99
hw/block/dataplane/xen-block.c | 6 +-
100
hw/block/fdc.c | 2 +-
101
hw/block/nvme.c | 106 +++++++++++++++++++++-
102
hw/block/xen-block.c | 2 +-
103
hw/core/qdev-properties-system.c | 41 ++++++++-
104
hw/ide/qdev.c | 2 +-
105
hw/scsi/scsi-disk.c | 24 +++--
106
hw/scsi/virtio-scsi.c | 25 +++---
107
migration/block.c | 3 +-
108
nbd/server.c | 6 +-
109
qemu-img.c | 6 +-
110
tests/libqtest.c | 19 ++++
111
tests/test-bdrv-drain.c | 50 ++++++-----
112
tests/test-bdrv-graph-mod.c | 5 +-
113
tests/test-block-backend.c | 6 +-
114
tests/test-block-iothread.c | 104 ++++++++++++++++++----
115
tests/test-blockjob.c | 2 +-
116
tests/test-throttle.c | 6 +-
117
tests/virtio-scsi-test.c | 62 +++++++++++++
118
block/trace-events | 3 +
119
hw/block/trace-events | 2 +
120
tests/perf/block/qcow2/convert-blockstatus | 71 +++++++++++++++
121
tests/qemu-iotests/051 | 24 +++++
122
tests/qemu-iotests/051.out | 3 +
123
tests/qemu-iotests/051.pc.out | 27 ++++++
124
tests/qemu-iotests/102 | 2 +-
125
tests/qemu-iotests/102.out | 3 +-
126
tests/qemu-iotests/141.out | 2 +-
127
tests/qemu-iotests/144.out | 2 +-
128
tests/qemu-iotests/240 | 21 +++++
129
tests/qemu-iotests/240.out | 15 +++-
130
tests/qemu-iotests/255 | 135 +++++++++++++++++++++++++++++
131
tests/qemu-iotests/255.out | 40 +++++++++
132
tests/qemu-iotests/check | 1 -
133
tests/qemu-iotests/group | 1 +
134
tests/qemu-iotests/iotests.py | 10 ++-
135
70 files changed, 1048 insertions(+), 272 deletions(-)
136
create mode 100755 tests/perf/block/qcow2/convert-blockstatus
137
create mode 100755 tests/qemu-iotests/255
138
create mode 100644 tests/qemu-iotests/255.out
139
diff view generated by jsdifflib
Deleted patch
1
Instead of just asserting that no requests are in flight in
2
bdrv_replace_node(), which is a requirement that most callers ignore, we
3
can just drain the source node right there. This fixes at least starting
4
a commit job while I/O is active on the backing chain, but probably
5
other callers, too.
6
1
7
Having requests in flight on the target node isn't a problem because the
8
target just gets new parents, but the call path of running requests
9
isn't modified. So we can just drop this assertion without a replacement.
10
11
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1711643
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
---
15
block.c | 7 ++++---
16
1 file changed, 4 insertions(+), 3 deletions(-)
17
18
diff --git a/block.c b/block.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
21
+++ b/block.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
23
uint64_t perm = 0, shared = BLK_PERM_ALL;
24
int ret;
25
26
- assert(!atomic_read(&from->in_flight));
27
- assert(!atomic_read(&to->in_flight));
28
-
29
/* Make sure that @from doesn't go away until we have successfully attached
30
* all of its parents to @to. */
31
bdrv_ref(from);
32
33
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
34
+ bdrv_drained_begin(from);
35
+
36
/* Put all parents into @list and calculate their cumulative permissions */
37
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
38
assert(c->bs == from);
39
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
40
41
out:
42
g_slist_free(list);
43
+ bdrv_drained_end(from);
44
bdrv_unref(from);
45
}
46
47
--
48
2.20.1
49
50
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Let's at least trace ignored failure.
3
Backing files and raw external data files are mutually exclusive.
4
The documentation of the raw external data bit (in autoclear_features)
5
already indicates that, but we should also mention it on the other
6
side.
4
7
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Suggested-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
13
---
9
block/qcow2-refcount.c | 7 ++++++-
14
docs/interop/qcow2.txt | 3 +++
10
block/trace-events | 3 +++
15
1 file changed, 3 insertions(+)
11
2 files changed, 9 insertions(+), 1 deletion(-)
12
16
13
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2-refcount.c
19
--- a/docs/interop/qcow2.txt
16
+++ b/block/qcow2-refcount.c
20
+++ b/docs/interop/qcow2.txt
17
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
18
#include "qemu/range.h"
22
is stored (NB: The string is not null terminated). 0 if the
19
#include "qemu/bswap.h"
23
image doesn't have a backing file.
20
#include "qemu/cutils.h"
24
21
+#include "trace.h"
25
+ Note: backing files are incompatible with raw external data
22
26
+ files (auto-clear feature bit 1).
23
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
24
uint64_t max);
25
@@ -XXX,XX +XXX,XX @@ void qcow2_process_discards(BlockDriverState *bs, int ret)
26
27
/* Discard is optional, ignore the return value */
28
if (ret >= 0) {
29
- bdrv_pdiscard(bs->file, d->offset, d->bytes);
30
+ int r2 = bdrv_pdiscard(bs->file, d->offset, d->bytes);
31
+ if (r2 < 0) {
32
+ trace_qcow2_process_discards_failed_region(d->offset, d->bytes,
33
+ r2);
34
+ }
35
}
36
37
g_free(d);
38
diff --git a/block/trace-events b/block/trace-events
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/trace-events
41
+++ b/block/trace-events
42
@@ -XXX,XX +XXX,XX @@ qcow2_cache_get_done(void *co, int c, int i) "co %p is_l2_cache %d index %d"
43
qcow2_cache_flush(void *co, int c) "co %p is_l2_cache %d"
44
qcow2_cache_entry_flush(void *co, int c, int i) "co %p is_l2_cache %d index %d"
45
46
+# qcow2-refcount.c
47
+qcow2_process_discards_failed_region(uint64_t offset, uint64_t bytes, int ret) "offset 0x%" PRIx64 " bytes 0x%" PRIx64 " ret %d"
48
+
27
+
49
# qed-l2-cache.c
28
16 - 19: backing_file_size
50
qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
29
Length of the backing file name in bytes. Must not be
51
qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
30
longer than 1023 bytes. Undefined if the image doesn't have
52
--
31
--
53
2.20.1
32
2.25.3
54
33
55
34
diff view generated by jsdifflib
1
Commit 70ff5b07 wanted to move the diff between actual and reference
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
output to the end after printing the test result line. It really only
3
copied it, though, so the diff is now displayed twice. Remove the old
4
one.
5
2
6
Fixes: 70ff5b07fcdd378180ad2d5cc0b0d5e67e7ef325
3
Test 244 checks the expected behavior of qcow2 external data files
4
with respect to zero and discarded clusters. Filesystems however
5
are free to ignore discard requests, and this seems to be the
6
case for overlayfs. Relax the tests to skip checks on the
7
external data file for discarded areas, which implies not using
8
qemu-img compare in the data_file_raw=on case.
9
10
This fixes docker tests on RHEL8.
11
12
Cc: Kevin Wolf <kwolf@redhat.com>
13
Cc: qemu-block@nongnu.org
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
17
---
9
tests/qemu-iotests/check | 1 -
18
tests/qemu-iotests/244 | 10 ++++++++--
10
1 file changed, 1 deletion(-)
19
tests/qemu-iotests/244.out | 9 ++++++---
20
2 files changed, 14 insertions(+), 5 deletions(-)
11
21
12
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
22
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
13
index XXXXXXX..XXXXXXX 100755
23
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/check
24
--- a/tests/qemu-iotests/244
15
+++ b/tests/qemu-iotests/check
25
+++ b/tests/qemu-iotests/244
16
@@ -XXX,XX +XXX,XX @@ do
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
17
fi
27
echo
18
else
28
$QEMU_IO -c 'read -P 0 0 1M' \
19
mv $tmp.out $seq.out.bad
29
-c 'read -P 0x11 1M 1M' \
20
- $diff -w "$reference" "$PWD"/$seq.out.bad
30
- -c 'read -P 0 2M 2M' \
21
status="fail"
31
-c 'read -P 0x11 4M 1M' \
22
results="output mismatch (see $seq.out.bad)"
32
-c 'read -P 0 5M 1M' \
23
printdiff=true
33
-f raw "$TEST_IMG.data" |
34
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
35
-f $IMGFMT "$TEST_IMG" |
36
_filter_qemu_io
37
38
+# Discarded clusters are only marked as such in the qcow2 metadata, but
39
+# they can contain stale data in the external data file. Instead, zero
40
+# clusters must be zeroed in the external data file too.
41
echo
42
-$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
43
+$QEMU_IO -c 'read -P 0 0 1M' \
44
+ -c 'read -P 0x11 1M 1M' \
45
+ -c 'read -P 0 3M 3M' \
46
+ -f raw "$TEST_IMG".data |
47
+ _filter_qemu_io
48
49
echo -n "qcow2 file size after I/O: "
50
du -b $TEST_IMG | cut -f1
51
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
52
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/244.out
54
+++ b/tests/qemu-iotests/244.out
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
57
read 1048576/1048576 bytes at offset 1048576
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
59
-read 2097152/2097152 bytes at offset 2097152
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
61
read 1048576/1048576 bytes at offset 4194304
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
63
read 1048576/1048576 bytes at offset 5242880
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
65
read 4194304/4194304 bytes at offset 2097152
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
67
68
-Images are identical.
69
+read 1048576/1048576 bytes at offset 0
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
71
+read 1048576/1048576 bytes at offset 1048576
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
73
+read 3145728/3145728 bytes at offset 3145728
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
qcow2 file size after I/O: 327680
76
77
=== bdrv_co_block_status test for file and offset=0 ===
24
--
78
--
25
2.20.1
79
2.25.3
26
80
27
81
diff view generated by jsdifflib
1
A node should only be in a non-default AioContext if a user is attached
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
2
to it that requires this. When the last parent of a node is gone, it can
2
driver callbacks, and a supported_truncate_flags field in
3
move back to the main AioContext.
3
BlockDriverState that allows drivers to advertise support for request
4
4
flags in the context of truncate.
5
6
For now, we always pass 0 and no drivers declare support for any flag.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
14
---
7
block.c | 4 ++++
15
include/block/block_int.h | 10 +++++++++-
8
tests/test-bdrv-drain.c | 2 +-
16
block/crypto.c | 3 ++-
9
tests/test-block-iothread.c | 3 +--
17
block/file-posix.c | 2 +-
10
3 files changed, 6 insertions(+), 3 deletions(-)
18
block/file-win32.c | 2 +-
11
19
block/gluster.c | 1 +
12
diff --git a/block.c b/block.c
20
block/io.c | 8 +++++++-
13
index XXXXXXX..XXXXXXX 100644
21
block/iscsi.c | 2 +-
14
--- a/block.c
22
block/nfs.c | 3 ++-
15
+++ b/block.c
23
block/qcow2.c | 2 +-
16
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
24
block/qed.c | 1 +
17
bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
25
block/raw-format.c | 2 +-
18
bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, &error_abort);
26
block/rbd.c | 1 +
19
bdrv_set_perm(old_bs, perm, shared_perm);
27
block/sheepdog.c | 4 ++--
20
+
28
block/ssh.c | 2 +-
21
+ /* When the parent requiring a non-default AioContext is removed, the
29
tests/test-block-iothread.c | 3 ++-
22
+ * node moves back to the main AioContext */
30
15 files changed, 33 insertions(+), 13 deletions(-)
23
+ bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL);
31
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
*/
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
39
bool exact, PreallocMode prealloc,
40
- Error **errp);
41
+ BdrvRequestFlags flags, Error **errp);
42
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
44
bool has_variable_length;
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
55
+ */
56
+ unsigned int supported_truncate_flags;
57
58
/* the following member gives a name to every node on the bs graph. */
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
63
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
65
66
static int coroutine_fn
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
79
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
81
bool exact, PreallocMode prealloc,
82
- Error **errp)
83
+ BdrvRequestFlags flags, Error **errp)
84
{
85
BDRVRawState *s = bs->opaque;
86
struct stat st;
87
diff --git a/block/file-win32.c b/block/file-win32.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/file-win32.c
90
+++ b/block/file-win32.c
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
92
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
94
bool exact, PreallocMode prealloc,
95
- Error **errp)
96
+ BdrvRequestFlags flags, Error **errp)
97
{
98
BDRVRawState *s = bs->opaque;
99
LONG low, high;
100
diff --git a/block/gluster.c b/block/gluster.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/gluster.c
103
+++ b/block/gluster.c
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
105
int64_t offset,
106
bool exact,
107
PreallocMode prealloc,
108
+ BdrvRequestFlags flags,
109
Error **errp)
110
{
111
BDRVGlusterState *s = bs->opaque;
112
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
115
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
BlockDriverState *bs = child->bs;
118
BlockDriver *drv = bs->drv;
119
BdrvTrackedRequest req;
120
+ BdrvRequestFlags flags = 0;
121
int64_t old_size, new_bytes;
122
int ret;
123
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
24
}
125
}
25
126
26
if (new_bs) {
127
if (drv->bdrv_co_truncate) {
27
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
28
index XXXXXXX..XXXXXXX 100644
129
+ if (flags & ~bs->supported_truncate_flags) {
29
--- a/tests/test-bdrv-drain.c
130
+ error_setg(errp, "Block driver does not support requested flags");
30
+++ b/tests/test-bdrv-drain.c
131
+ ret = -ENOTSUP;
31
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
132
+ goto out;
32
133
+ }
33
if (use_iothread) {
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
34
blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
135
} else if (bs->file && drv->is_filter) {
35
- blk_set_aio_context(blk_target, qemu_get_aio_context(), &error_abort);
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
36
+ assert(blk_get_aio_context(blk_target) == qemu_get_aio_context());
137
} else {
37
}
138
diff --git a/block/iscsi.c b/block/iscsi.c
38
aio_context_release(ctx);
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/iscsi.c
141
+++ b/block/iscsi.c
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
143
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
145
bool exact, PreallocMode prealloc,
146
- Error **errp)
147
+ BdrvRequestFlags flags, Error **errp)
148
{
149
IscsiLun *iscsilun = bs->opaque;
150
int64_t cur_length;
151
diff --git a/block/nfs.c b/block/nfs.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/block/nfs.c
154
+++ b/block/nfs.c
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
156
157
static int coroutine_fn
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
159
- PreallocMode prealloc, Error **errp)
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
161
+ Error **errp)
162
{
163
NFSClient *client = bs->opaque;
164
int ret;
165
diff --git a/block/qcow2.c b/block/qcow2.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/qcow2.c
168
+++ b/block/qcow2.c
169
@@ -XXX,XX +XXX,XX @@ fail:
170
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
172
bool exact, PreallocMode prealloc,
173
- Error **errp)
174
+ BdrvRequestFlags flags, Error **errp)
175
{
176
BDRVQcow2State *s = bs->opaque;
177
uint64_t old_length;
178
diff --git a/block/qed.c b/block/qed.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/qed.c
181
+++ b/block/qed.c
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
183
int64_t offset,
184
bool exact,
185
PreallocMode prealloc,
186
+ BdrvRequestFlags flags,
187
Error **errp)
188
{
189
BDRVQEDState *s = bs->opaque;
190
diff --git a/block/raw-format.c b/block/raw-format.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/raw-format.c
193
+++ b/block/raw-format.c
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
195
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
197
bool exact, PreallocMode prealloc,
198
- Error **errp)
199
+ BdrvRequestFlags flags, Error **errp)
200
{
201
BDRVRawState *s = bs->opaque;
202
203
diff --git a/block/rbd.c b/block/rbd.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/rbd.c
206
+++ b/block/rbd.c
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
208
int64_t offset,
209
bool exact,
210
PreallocMode prealloc,
211
+ BdrvRequestFlags flags,
212
Error **errp)
213
{
214
int r;
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/sheepdog.c
218
+++ b/block/sheepdog.c
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
220
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
222
bool exact, PreallocMode prealloc,
223
- Error **errp)
224
+ BdrvRequestFlags flags, Error **errp)
225
{
226
BDRVSheepdogState *s = bs->opaque;
227
int ret, fd;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
231
if (offset > s->inode.vdi_size) {
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
234
if (ret < 0) {
235
return ret;
236
}
237
diff --git a/block/ssh.c b/block/ssh.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/ssh.c
240
+++ b/block/ssh.c
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
242
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
244
bool exact, PreallocMode prealloc,
245
- Error **errp)
246
+ BdrvRequestFlags flags, Error **errp)
247
{
248
BDRVSSHState *s = bs->opaque;
39
249
40
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
41
index XXXXXXX..XXXXXXX 100644
251
index XXXXXXX..XXXXXXX 100644
42
--- a/tests/test-block-iothread.c
252
--- a/tests/test-block-iothread.c
43
+++ b/tests/test-block-iothread.c
253
+++ b/tests/test-block-iothread.c
44
@@ -XXX,XX +XXX,XX @@ static void test_attach_preserve_blk_ctx(void)
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
45
255
46
/* Remove the node again */
256
static int coroutine_fn
47
blk_remove_bs(blk);
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
48
- /* TODO bs should move back to main context here */
258
- PreallocMode prealloc, Error **errp)
49
g_assert(blk_get_aio_context(blk) == ctx);
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
50
- g_assert(bdrv_get_aio_context(bs) == ctx);
260
+ Error **errp)
51
+ g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
261
{
52
262
return 0;
53
/* Re-attach the node */
263
}
54
blk_insert_bs(blk, bs, &error_abort);
55
--
264
--
56
2.20.1
265
2.25.3
57
266
58
267
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
bdrv_truncate().
2
4
3
drv_co_block_status digs bs->file for additional, more accurate search
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
for hole inside region, reported as DATA by bs since 5daa74a6ebc.
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
This accuracy is not free: assume we have qcow2 disk. Actually, qcow2
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
knows, where are holes and where is data. But every block_status
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
8
request calls lseek additionally. Assume a big disk, full of
9
data, in any iterative copying block job (or img convert) we'll call
10
lseek(HOLE) on every iteration, and each of these lseeks will have to
11
iterate through all metadata up to the end of file. It's obviously
12
ineffective behavior. And for many scenarios we don't need this lseek
13
at all.
14
15
However, lseek is needed when we have metadata-preallocated image.
16
17
So, let's detect metadata-preallocation case and don't dig qcow2's
18
protocol file in other cases.
19
20
The idea is to compare allocation size in POV of filesystem with
21
allocations size in POV of Qcow2 (by refcounts). If allocation in fs is
22
significantly lower, consider it as metadata-preallocation case.
23
24
102 iotest changed, as our detector can't detect shrinked file as
25
metadata-preallocation, which don't seem to be wrong, as with metadata
26
preallocation we always have valid file length.
27
28
Two other iotests have a slight change in their QMP output sequence:
29
Active 'block-commit' returns earlier because the job coroutine yields
30
earlier on a blocking operation. This operation is loading the refcount
31
blocks in qcow2_detect_metadata_preallocation().
32
33
Suggested-by: Denis V. Lunev <den@openvz.org>
34
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
35
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
36
---
11
---
37
block/qcow2.h | 4 ++++
12
include/block/block.h | 5 +++--
38
include/block/block.h | 8 +++++++-
13
block/block-backend.c | 2 +-
39
block/io.c | 9 ++++++++-
14
block/crypto.c | 2 +-
40
block/qcow2-refcount.c | 32 ++++++++++++++++++++++++++++++++
15
block/io.c | 12 +++++++-----
41
block/qcow2.c | 11 +++++++++++
16
block/parallels.c | 6 +++---
42
tests/qemu-iotests/102 | 2 +-
17
block/qcow.c | 4 ++--
43
tests/qemu-iotests/102.out | 3 ++-
18
block/qcow2-refcount.c | 2 +-
44
tests/qemu-iotests/141.out | 2 +-
19
block/qcow2.c | 15 +++++++++------
45
tests/qemu-iotests/144.out | 2 +-
20
block/raw-format.c | 2 +-
46
9 files changed, 67 insertions(+), 6 deletions(-)
21
block/vhdx-log.c | 2 +-
22
block/vhdx.c | 2 +-
23
block/vmdk.c | 2 +-
24
tests/test-block-iothread.c | 6 +++---
25
13 files changed, 34 insertions(+), 28 deletions(-)
47
26
48
diff --git a/block/qcow2.h b/block/qcow2.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/qcow2.h
51
+++ b/block/qcow2.h
52
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
53
int nb_threads;
54
55
BdrvChild *data_file;
56
+
57
+ bool metadata_preallocation_checked;
58
+ bool metadata_preallocation;
59
} BDRVQcow2State;
60
61
typedef struct Qcow2COWRegion {
62
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
63
void *cb_opaque, Error **errp);
64
int qcow2_shrink_reftable(BlockDriverState *bs);
65
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
66
+int qcow2_detect_metadata_preallocation(BlockDriverState *bs);
67
68
/* qcow2-cluster.c functions */
69
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
70
diff --git a/include/block/block.h b/include/block/block.h
27
diff --git a/include/block/block.h b/include/block/block.h
71
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
72
--- a/include/block/block.h
29
--- a/include/block/block.h
73
+++ b/include/block/block.h
30
+++ b/include/block/block.h
74
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
75
* BDRV_BLOCK_EOF: the returned pnum covers through end of file for this
32
void bdrv_refresh_filename(BlockDriverState *bs);
76
* layer, set by block layer
33
77
*
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
78
- * Internal flag:
35
- PreallocMode prealloc, Error **errp);
79
+ * Internal flags:
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
80
* BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request
37
+ Error **errp);
81
* that the block layer recompute the answer from the returned
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
82
* BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID.
39
- PreallocMode prealloc, Error **errp);
83
+ * BDRV_BLOCK_RECURSE: request that the block layer will recursively search for
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
84
+ * zeroes in file child of current block node inside
41
85
+ * returned region. Only valid together with both
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
86
+ * BDRV_BLOCK_DATA and BDRV_BLOCK_OFFSET_VALID. Should not
43
int64_t bdrv_getlength(BlockDriverState *bs);
87
+ * appear with BDRV_BLOCK_ZERO.
44
diff --git a/block/block-backend.c b/block/block-backend.c
88
*
45
index XXXXXXX..XXXXXXX 100644
89
* If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the
46
--- a/block/block-backend.c
90
* host offset within the returned BDS that is allocated for the
47
+++ b/block/block-backend.c
91
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
92
#define BDRV_BLOCK_RAW 0x08
49
return -ENOMEDIUM;
93
#define BDRV_BLOCK_ALLOCATED 0x10
50
}
94
#define BDRV_BLOCK_EOF 0x20
51
95
+#define BDRV_BLOCK_RECURSE 0x40
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
96
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
97
54
}
98
typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
55
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
60
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
62
63
offset += payload_offset;
64
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
}
68
69
static void block_crypto_close(BlockDriverState *bs)
99
diff --git a/block/io.c b/block/io.c
70
diff --git a/block/io.c b/block/io.c
100
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
101
--- a/block/io.c
72
--- a/block/io.c
102
+++ b/block/io.c
73
+++ b/block/io.c
103
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
104
*/
75
* 'offset' bytes in length.
105
assert(*pnum && QEMU_IS_ALIGNED(*pnum, align) &&
76
*/
106
align > offset - aligned_offset);
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
107
+ if (ret & BDRV_BLOCK_RECURSE) {
78
- PreallocMode prealloc, Error **errp)
108
+ assert(ret & BDRV_BLOCK_DATA);
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
109
+ assert(ret & BDRV_BLOCK_OFFSET_VALID);
80
+ Error **errp)
110
+ assert(!(ret & BDRV_BLOCK_ZERO));
81
{
111
+ }
82
BlockDriverState *bs = child->bs;
112
+
83
BlockDriver *drv = bs->drv;
113
*pnum -= offset - aligned_offset;
84
BdrvTrackedRequest req;
114
if (*pnum > bytes) {
85
- BdrvRequestFlags flags = 0;
115
*pnum = bytes;
86
int64_t old_size, new_bytes;
116
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
87
int ret;
117
}
88
118
}
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
119
90
}
120
- if (want_zero && local_file && local_file != bs &&
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
121
+ if (want_zero && ret & BDRV_BLOCK_RECURSE &&
92
} else if (bs->file && drv->is_filter) {
122
+ local_file && local_file != bs &&
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
123
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
124
(ret & BDRV_BLOCK_OFFSET_VALID)) {
95
} else {
125
int64_t file_pnum;
96
error_setg(errp, "Image format driver does not support resize");
97
ret = -ENOTSUP;
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
99
int64_t offset;
100
bool exact;
101
PreallocMode prealloc;
102
+ BdrvRequestFlags flags;
103
Error **errp;
104
int ret;
105
} TruncateCo;
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
107
{
108
TruncateCo *tco = opaque;
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
110
- tco->prealloc, tco->errp);
111
+ tco->prealloc, tco->flags, tco->errp);
112
aio_wait_kick();
113
}
114
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
116
- PreallocMode prealloc, Error **errp)
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
118
{
119
Coroutine *co;
120
TruncateCo tco = {
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
122
.offset = offset,
123
.exact = exact,
124
.prealloc = prealloc,
125
+ .flags = flags,
126
.errp = errp,
127
.ret = NOT_DONE,
128
};
129
diff --git a/block/parallels.c b/block/parallels.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/parallels.c
132
+++ b/block/parallels.c
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
134
} else {
135
ret = bdrv_truncate(bs->file,
136
(s->data_end + space) << BDRV_SECTOR_BITS,
137
- false, PREALLOC_MODE_OFF, NULL);
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
139
}
140
if (ret < 0) {
141
return ret;
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
143
* That means we have to pass exact=true.
144
*/
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
146
- PREALLOC_MODE_OFF, &local_err);
147
+ PREALLOC_MODE_OFF, 0, &local_err);
148
if (ret < 0) {
149
error_report_err(local_err);
150
res->check_errors++;
151
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
152
153
/* errors are ignored, so we might as well pass exact=true */
154
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
155
- PREALLOC_MODE_OFF, NULL);
156
+ PREALLOC_MODE_OFF, 0, NULL);
157
}
158
159
g_free(s->bat_dirty_bmap);
160
diff --git a/block/qcow.c b/block/qcow.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qcow.c
163
+++ b/block/qcow.c
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
165
return -E2BIG;
166
}
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
168
- false, PREALLOC_MODE_OFF, NULL);
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
170
if (ret < 0) {
171
return ret;
172
}
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
174
l1_length) < 0)
175
return -1;
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
177
- PREALLOC_MODE_OFF, NULL);
178
+ PREALLOC_MODE_OFF, 0, NULL);
179
if (ret < 0)
180
return ret;
181
126
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
127
index XXXXXXX..XXXXXXX 100644
183
index XXXXXXX..XXXXXXX 100644
128
--- a/block/qcow2-refcount.c
184
--- a/block/qcow2-refcount.c
129
+++ b/block/qcow2-refcount.c
185
+++ b/block/qcow2-refcount.c
130
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
131
"There are no references in the refcount table.");
187
}
132
return -EIO;
188
133
}
189
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
134
+
190
- PREALLOC_MODE_OFF, &local_err);
135
+int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
191
+ PREALLOC_MODE_OFF, 0, &local_err);
136
+{
192
if (ret < 0) {
137
+ BDRVQcow2State *s = bs->opaque;
193
error_report_err(local_err);
138
+ int64_t i, end_cluster, cluster_count = 0, threshold;
194
goto resize_fail;
139
+ int64_t file_length, real_allocation, real_clusters;
140
+
141
+ file_length = bdrv_getlength(bs->file->bs);
142
+ if (file_length < 0) {
143
+ return file_length;
144
+ }
145
+
146
+ real_allocation = bdrv_get_allocated_file_size(bs->file->bs);
147
+ if (real_allocation < 0) {
148
+ return real_allocation;
149
+ }
150
+
151
+ real_clusters = real_allocation / s->cluster_size;
152
+ threshold = MAX(real_clusters * 10 / 9, real_clusters + 2);
153
+
154
+ end_cluster = size_to_clusters(s, file_length);
155
+ for (i = 0; i < end_cluster && cluster_count < threshold; i++) {
156
+ uint64_t refcount;
157
+ int ret = qcow2_get_refcount(bs, i, &refcount);
158
+ if (ret < 0) {
159
+ return ret;
160
+ }
161
+ cluster_count += !!refcount;
162
+ }
163
+
164
+ return cluster_count >= threshold;
165
+}
166
diff --git a/block/qcow2.c b/block/qcow2.c
195
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
196
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
197
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
198
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
171
unsigned int bytes;
200
mode = PREALLOC_MODE_OFF;
172
int status = 0;
201
}
173
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
174
+ if (!s->metadata_preallocation_checked) {
203
- mode, errp);
175
+ ret = qcow2_detect_metadata_preallocation(bs);
204
+ mode, 0, errp);
176
+ s->metadata_preallocation = (ret == 1);
205
if (ret < 0) {
177
+ s->metadata_preallocation_checked = true;
206
return ret;
178
+ }
207
}
179
+
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
180
bytes = MIN(INT_MAX, count);
209
* always fulfilled, so there is no need to pass it on.)
181
qemu_co_mutex_lock(&s->lock);
210
*/
182
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
211
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
183
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
212
- false, PREALLOC_MODE_OFF, &local_err);
184
} else if (ret != QCOW2_CLUSTER_UNALLOCATED) {
213
+ false, PREALLOC_MODE_OFF, 0, &local_err);
185
status |= BDRV_BLOCK_DATA;
214
if (local_err) {
186
}
215
warn_reportf_err(local_err,
187
+ if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
216
"Failed to truncate the tail of the image: ");
188
+ (status & BDRV_BLOCK_OFFSET_VALID))
217
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
189
+ {
218
* file should be resized to the exact target size, too,
190
+ status |= BDRV_BLOCK_RECURSE;
219
* so we pass @exact here.
191
+ }
220
*/
192
return status;
221
- ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp);
193
}
222
+ ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
194
223
+ errp);
195
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
224
if (ret < 0) {
196
index XXXXXXX..XXXXXXX 100755
225
goto fail;
197
--- a/tests/qemu-iotests/102
226
}
198
+++ b/tests/qemu-iotests/102
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
199
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
228
new_file_size = allocation_start +
200
$QEMU_IMG resize -f raw --shrink "$TEST_IMG" $((5 * 64 * 1024))
229
nb_new_data_clusters * s->cluster_size;
201
230
/* Image file grows, so @exact does not matter */
202
$QEMU_IO -c map "$TEST_IMG"
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
203
-$QEMU_IMG map "$TEST_IMG"
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
204
+$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
233
+ errp);
205
234
if (ret < 0) {
206
echo
235
error_prepend(errp, "Failed to resize underlying file: ");
207
echo '=== Testing map on an image file truncated outside of qemu ==='
236
qcow2_free_clusters(bs, allocation_start,
208
diff --git a/tests/qemu-iotests/102.out b/tests/qemu-iotests/102.out
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
209
index XXXXXXX..XXXXXXX 100644
238
if (len < 0) {
210
--- a/tests/qemu-iotests/102.out
239
return len;
211
+++ b/tests/qemu-iotests/102.out
240
}
212
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 0
241
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
213
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
242
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
214
Image resized.
243
+ NULL);
215
64 KiB (0x10000) bytes allocated at offset 0 bytes (0x0)
244
}
216
-Offset Length Mapped to File
245
217
+Offset Length File
246
if (offset_into_cluster(s, offset)) {
218
+0 0x10000 TEST_DIR/t.IMGFMT
247
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
219
248
}
220
=== Testing map on an image file truncated outside of qemu ===
249
221
250
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
222
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
251
- PREALLOC_MODE_OFF, &local_err);
223
index XXXXXXX..XXXXXXX 100644
252
+ PREALLOC_MODE_OFF, 0, &local_err);
224
--- a/tests/qemu-iotests/141.out
253
if (ret < 0) {
225
+++ b/tests/qemu-iotests/141.out
254
error_report_err(local_err);
226
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
255
goto fail;
227
{"return": {}}
256
diff --git a/block/raw-format.c b/block/raw-format.c
228
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
257
index XXXXXXX..XXXXXXX 100644
229
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
258
--- a/block/raw-format.c
230
+{"return": {}}
259
+++ b/block/raw-format.c
231
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
232
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
261
233
-{"return": {}}
262
s->size = offset;
234
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
263
offset += s->offset;
235
{"return": {}}
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
236
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
237
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
266
}
238
index XXXXXXX..XXXXXXX 100644
267
239
--- a/tests/qemu-iotests/144.out
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
240
+++ b/tests/qemu-iotests/144.out
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
241
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
270
index XXXXXXX..XXXXXXX 100644
242
271
--- a/block/vhdx-log.c
243
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "virtio0"}}
272
+++ b/block/vhdx-log.c
244
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "virtio0"}}
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
245
+{"return": {}}
274
goto exit;
246
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "virtio0"}}
275
}
247
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
276
ret = bdrv_truncate(bs->file, new_file_size, false,
248
{"return": {}}
277
- PREALLOC_MODE_OFF, NULL);
249
-{"return": {}}
278
+ PREALLOC_MODE_OFF, 0, NULL);
250
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "virtio0"}}
279
if (ret < 0) {
251
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "virtio0"}}
280
goto exit;
252
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
281
}
282
diff --git a/block/vhdx.c b/block/vhdx.c
283
index XXXXXXX..XXXXXXX 100644
284
--- a/block/vhdx.c
285
+++ b/block/vhdx.c
286
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
287
}
288
289
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
290
- PREALLOC_MODE_OFF, NULL);
291
+ PREALLOC_MODE_OFF, 0, NULL);
292
}
293
294
/*
295
diff --git a/block/vmdk.c b/block/vmdk.c
296
index XXXXXXX..XXXXXXX 100644
297
--- a/block/vmdk.c
298
+++ b/block/vmdk.c
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
300
}
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
302
ret = bdrv_truncate(s->extents[i].file, length, false,
303
- PREALLOC_MODE_OFF, NULL);
304
+ PREALLOC_MODE_OFF, 0, NULL);
305
if (ret < 0) {
306
return ret;
307
}
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/tests/test-block-iothread.c
311
+++ b/tests/test-block-iothread.c
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
313
int ret;
314
315
/* Normal success path */
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
318
g_assert_cmpint(ret, ==, 0);
319
320
/* Early error: Negative offset */
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
323
g_assert_cmpint(ret, ==, -EINVAL);
324
325
/* Error: Read-only image */
326
c->bs->read_only = true;
327
c->bs->open_flags &= ~BDRV_O_RDWR;
328
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
331
g_assert_cmpint(ret, ==, -EACCES);
332
333
c->bs->read_only = false;
253
--
334
--
254
2.20.1
335
2.25.3
255
336
256
337
diff view generated by jsdifflib
1
This adds a new parameter to blk_new() which requires its callers to
1
Now that node level interface bdrv_truncate() supports passing request
2
declare from which AioContext this BlockBackend is going to be used (or
2
flags to the block driver, expose this on the BlockBackend level, too.
3
the locks of which AioContext need to be taken anyway).
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
The given context is only stored and kept up to date when changing
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
AioContexts. Actually applying the stored AioContext to the root node
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
is saved for another commit.
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
include/sysemu/block-backend.h | 2 +-
11
include/sysemu/block-backend.h | 2 +-
12
block.c | 2 +-
12
block.c | 3 ++-
13
block/backup.c | 3 ++-
13
block/block-backend.c | 4 ++--
14
block/block-backend.c | 18 +++++++++++++++---
14
block/commit.c | 4 ++--
15
block/commit.c | 11 +++++++----
15
block/crypto.c | 2 +-
16
block/crypto.c | 3 ++-
16
block/mirror.c | 2 +-
17
block/mirror.c | 3 ++-
17
block/qcow2.c | 4 ++--
18
block/parallels.c | 3 ++-
18
block/qed.c | 2 +-
19
block/qcow.c | 3 ++-
19
block/vdi.c | 2 +-
20
block/qcow2.c | 6 ++++--
20
block/vhdx.c | 4 ++--
21
block/qed.c | 3 ++-
21
block/vmdk.c | 6 +++---
22
block/sheepdog.c | 3 ++-
22
block/vpc.c | 2 +-
23
block/vdi.c | 3 ++-
23
blockdev.c | 2 +-
24
block/vhdx.c | 3 ++-
24
qemu-img.c | 2 +-
25
block/vmdk.c | 3 ++-
25
qemu-io-cmds.c | 2 +-
26
block/vpc.c | 3 ++-
26
15 files changed, 22 insertions(+), 21 deletions(-)
27
blockdev.c | 4 ++--
28
blockjob.c | 2 +-
29
hmp.c | 3 ++-
30
hw/block/fdc.c | 2 +-
31
hw/block/xen-block.c | 2 +-
32
hw/core/qdev-properties-system.c | 4 +++-
33
hw/ide/qdev.c | 2 +-
34
hw/scsi/scsi-disk.c | 2 +-
35
migration/block.c | 3 ++-
36
nbd/server.c | 5 +++--
37
qemu-img.c | 6 ++++--
38
tests/test-bdrv-drain.c | 30 +++++++++++++++---------------
39
tests/test-bdrv-graph-mod.c | 5 +++--
40
tests/test-block-backend.c | 6 ++++--
41
tests/test-block-iothread.c | 10 +++++-----
42
tests/test-blockjob.c | 2 +-
43
tests/test-throttle.c | 6 +++---
44
33 files changed, 102 insertions(+), 64 deletions(-)
45
27
46
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
47
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
48
--- a/include/sysemu/block-backend.h
30
--- a/include/sysemu/block-backend.h
49
+++ b/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
50
@@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendPublic {
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
51
ThrottleGroupMember throttle_group_member;
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
52
} BlockBackendPublic;
34
int bytes);
53
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
54
-BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
36
- PreallocMode prealloc, Error **errp);
55
+BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
56
BlockBackend *blk_new_open(const char *filename, const char *reference,
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
57
QDict *options, int flags, Error **errp);
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
58
int blk_get_refcnt(BlockBackend *blk);
40
int64_t pos, int size);
59
diff --git a/block.c b/block.c
41
diff --git a/block.c b/block.c
60
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
61
--- a/block.c
43
--- a/block.c
62
+++ b/block.c
44
+++ b/block.c
63
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
64
/* Not requesting BLK_PERM_CONSISTENT_READ because we're only
46
int64_t size;
65
* looking at the header to guess the image format. This works even
47
int ret;
66
* in cases where a guest would not see a consistent state. */
48
67
- file = blk_new(0, BLK_PERM_ALL);
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
68
+ file = blk_new(bdrv_get_aio_context(file_bs), 0, BLK_PERM_ALL);
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
69
blk_insert_bs(file, file_bs, &local_err);
51
+ &local_err);
70
bdrv_unref(file_bs);
52
if (ret < 0 && ret != -ENOTSUP) {
71
if (local_err) {
53
error_propagate(errp, local_err);
72
diff --git a/block/backup.c b/block/backup.c
54
return ret;
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/backup.c
75
+++ b/block/backup.c
76
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
77
}
78
79
/* The target must match the source in size, so no resize here either */
80
- job->target = blk_new(BLK_PERM_WRITE,
81
+ job->target = blk_new(job->common.job.aio_context,
82
+ BLK_PERM_WRITE,
83
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
84
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD);
85
ret = blk_insert_bs(job->target, target, errp);
86
diff --git a/block/block-backend.c b/block/block-backend.c
55
diff --git a/block/block-backend.c b/block/block-backend.c
87
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
88
--- a/block/block-backend.c
57
--- a/block/block-backend.c
89
+++ b/block/block-backend.c
58
+++ b/block/block-backend.c
90
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
91
char *name;
60
}
92
int refcnt;
61
93
BdrvChild *root;
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
94
+ AioContext *ctx;
63
- PreallocMode prealloc, Error **errp)
95
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
96
QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */
97
QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
98
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_root = {
99
*
100
* Return the new BlockBackend on success, null on failure.
101
*/
102
-BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
103
+BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
104
{
65
{
105
BlockBackend *blk;
66
if (!blk_is_available(blk)) {
106
67
error_setg(errp, "No medium inserted");
107
blk = g_new0(BlockBackend, 1);
68
return -ENOMEDIUM;
108
blk->refcnt = 1;
69
}
109
+ blk->ctx = ctx;
70
110
blk->perm = perm;
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
111
blk->shared_perm = shared_perm;
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
112
blk_set_enable_write_cache(blk, true);
113
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
114
115
/*
116
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
117
+ * The new BlockBackend is in the main AioContext.
118
*
119
* Just as with bdrv_open(), after having called this function the reference to
120
* @options belongs to the block layer (even on failure).
121
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
122
perm |= BLK_PERM_RESIZE;
123
}
124
125
- blk = blk_new(perm, BLK_PERM_ALL);
126
+ blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL);
127
bs = bdrv_open(filename, reference, options, flags, errp);
128
if (!bs) {
129
blk_unref(blk);
130
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
131
132
AioContext *blk_get_aio_context(BlockBackend *blk)
133
{
134
- return bdrv_get_aio_context(blk_bs(blk));
135
+ BlockDriverState *bs = blk_bs(blk);
136
+
137
+ /* FIXME The AioContext of bs and blk can be inconsistent. For the moment,
138
+ * we prefer the one of bs for compatibility. */
139
+ if (bs) {
140
+ return bdrv_get_aio_context(blk_bs(blk));
141
+ }
142
+
143
+ return blk->ctx;
144
}
73
}
145
74
146
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
147
@@ -XXX,XX +XXX,XX @@ static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
148
}
149
}
150
151
+ blk->ctx = new_context;
152
return 0;
153
}
154
155
diff --git a/block/commit.c b/block/commit.c
76
diff --git a/block/commit.c b/block/commit.c
156
index XXXXXXX..XXXXXXX 100644
77
index XXXXXXX..XXXXXXX 100644
157
--- a/block/commit.c
78
--- a/block/commit.c
158
+++ b/block/commit.c
79
+++ b/block/commit.c
159
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
160
goto fail;
81
}
161
}
82
162
83
if (base_len < len) {
163
- s->base = blk_new(BLK_PERM_CONSISTENT_READ
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
164
+ s->base = blk_new(s->common.job.aio_context,
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
165
+ BLK_PERM_CONSISTENT_READ
86
if (ret) {
166
| BLK_PERM_WRITE
87
goto out;
167
| BLK_PERM_RESIZE,
88
}
168
BLK_PERM_CONSISTENT_READ
169
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
170
s->base_bs = base;
171
172
/* Required permissions are already taken with block_job_add_bdrv() */
173
- s->top = blk_new(0, BLK_PERM_ALL);
174
+ s->top = blk_new(s->common.job.aio_context, 0, BLK_PERM_ALL);
175
ret = blk_insert_bs(s->top, top, errp);
176
if (ret < 0) {
177
goto fail;
178
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
179
BlockDriverState *backing_file_bs = NULL;
90
* grow the backing file image if possible. If not possible,
180
BlockDriverState *commit_top_bs = NULL;
91
* we must return an error */
181
BlockDriver *drv = bs->drv;
92
if (length > backing_length) {
182
+ AioContext *ctx;
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
183
int64_t offset, length, backing_length;
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
184
int ro;
95
&local_err);
185
int64_t n;
96
if (ret < 0) {
186
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
97
error_report_err(local_err);
187
}
188
}
189
190
- src = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
191
- backing = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
192
+ ctx = bdrv_get_aio_context(bs);
193
+ src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
194
+ backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
195
196
ret = blk_insert_bs(src, bs, &local_err);
197
if (ret < 0) {
198
diff --git a/block/crypto.c b/block/crypto.c
98
diff --git a/block/crypto.c b/block/crypto.c
199
index XXXXXXX..XXXXXXX 100644
99
index XXXXXXX..XXXXXXX 100644
200
--- a/block/crypto.c
100
--- a/block/crypto.c
201
+++ b/block/crypto.c
101
+++ b/block/crypto.c
202
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
203
QCryptoBlock *crypto = NULL;
103
* which will be used by the crypto header
204
struct BlockCryptoCreateData data;
104
*/
205
105
return blk_truncate(data->blk, data->size + headerlen, false,
206
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
106
- data->prealloc, errp);
207
+ blk = blk_new(bdrv_get_aio_context(bs),
107
+ data->prealloc, 0, errp);
208
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
108
}
209
109
210
ret = blk_insert_bs(blk, bs, errp);
110
211
if (ret < 0) {
212
diff --git a/block/mirror.c b/block/mirror.c
111
diff --git a/block/mirror.c b/block/mirror.c
213
index XXXXXXX..XXXXXXX 100644
112
index XXXXXXX..XXXXXXX 100644
214
--- a/block/mirror.c
113
--- a/block/mirror.c
215
+++ b/block/mirror.c
114
+++ b/block/mirror.c
216
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
217
* We can allow anything except resize there.*/
116
218
target_is_backing = bdrv_chain_contains(bs, target);
117
if (s->bdev_length > base_length) {
219
target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);
118
ret = blk_truncate(s->target, s->bdev_length, false,
220
- s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |
119
- PREALLOC_MODE_OFF, NULL);
221
+ s->target = blk_new(s->common.job.aio_context,
120
+ PREALLOC_MODE_OFF, 0, NULL);
222
+ BLK_PERM_WRITE | BLK_PERM_RESIZE |
121
if (ret < 0) {
223
(target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),
122
goto immediate_exit;
224
BLK_PERM_WRITE_UNCHANGED |
123
}
225
(target_is_backing ? BLK_PERM_CONSISTENT_READ |
226
diff --git a/block/parallels.c b/block/parallels.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/block/parallels.c
229
+++ b/block/parallels.c
230
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
231
return -EIO;
232
}
233
234
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
235
+ blk = blk_new(bdrv_get_aio_context(bs),
236
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
237
ret = blk_insert_bs(blk, bs, errp);
238
if (ret < 0) {
239
goto out;
240
diff --git a/block/qcow.c b/block/qcow.c
241
index XXXXXXX..XXXXXXX 100644
242
--- a/block/qcow.c
243
+++ b/block/qcow.c
244
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
245
return -EIO;
246
}
247
248
- qcow_blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
249
+ qcow_blk = blk_new(bdrv_get_aio_context(bs),
250
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
251
ret = blk_insert_bs(qcow_blk, bs, errp);
252
if (ret < 0) {
253
goto exit;
254
diff --git a/block/qcow2.c b/block/qcow2.c
124
diff --git a/block/qcow2.c b/block/qcow2.c
255
index XXXXXXX..XXXXXXX 100644
125
index XXXXXXX..XXXXXXX 100644
256
--- a/block/qcow2.c
126
--- a/block/qcow2.c
257
+++ b/block/qcow2.c
127
+++ b/block/qcow2.c
258
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
259
}
129
260
130
/* Okay, now that we have a valid image, let's give it the right size */
261
/* Create BlockBackend to write to the image */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
262
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
132
- errp);
263
+ blk = blk_new(bdrv_get_aio_context(bs),
133
+ 0, errp);
264
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
134
if (ret < 0) {
265
ret = blk_insert_bs(blk, bs, errp);
135
error_prepend(errp, "Could not resize image: ");
266
if (ret < 0) {
267
goto out;
136
goto out;
268
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
269
}
138
* Amending image options should ensure that the image has
270
139
* exactly the given new values, so pass exact=true here.
271
if (new_size) {
140
*/
272
- BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
273
+ BlockBackend *blk = blk_new(bdrv_get_aio_context(bs),
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
274
+ BLK_PERM_RESIZE, BLK_PERM_ALL);
143
blk_unref(blk);
275
ret = blk_insert_bs(blk, bs, errp);
144
if (ret < 0) {
276
if (ret < 0) {
145
return ret;
277
blk_unref(blk);
278
diff --git a/block/qed.c b/block/qed.c
146
diff --git a/block/qed.c b/block/qed.c
279
index XXXXXXX..XXXXXXX 100644
147
index XXXXXXX..XXXXXXX 100644
280
--- a/block/qed.c
148
--- a/block/qed.c
281
+++ b/block/qed.c
149
+++ b/block/qed.c
282
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
283
return -EIO;
151
* The QED format associates file length with allocation status,
284
}
152
* so a new file (which is empty) must have a length of 0.
285
153
*/
286
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
287
+ blk = blk_new(bdrv_get_aio_context(bs),
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
288
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
289
ret = blk_insert_bs(blk, bs, errp);
290
if (ret < 0) {
156
if (ret < 0) {
291
goto out;
157
goto out;
292
diff --git a/block/sheepdog.c b/block/sheepdog.c
158
}
293
index XXXXXXX..XXXXXXX 100644
294
--- a/block/sheepdog.c
295
+++ b/block/sheepdog.c
296
@@ -XXX,XX +XXX,XX @@ static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
297
void *buf = NULL;
298
int ret;
299
300
- blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
301
+ blk = blk_new(bdrv_get_aio_context(bs),
302
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
303
BLK_PERM_ALL);
304
305
ret = blk_insert_bs(blk, bs, errp);
306
diff --git a/block/vdi.c b/block/vdi.c
159
diff --git a/block/vdi.c b/block/vdi.c
307
index XXXXXXX..XXXXXXX 100644
160
index XXXXXXX..XXXXXXX 100644
308
--- a/block/vdi.c
161
--- a/block/vdi.c
309
+++ b/block/vdi.c
162
+++ b/block/vdi.c
310
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
311
goto exit;
164
312
}
165
if (image_type == VDI_TYPE_STATIC) {
313
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
314
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
167
- PREALLOC_MODE_OFF, errp);
315
+ blk = blk_new(bdrv_get_aio_context(bs_file),
168
+ PREALLOC_MODE_OFF, 0, errp);
316
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
169
if (ret < 0) {
317
ret = blk_insert_bs(blk, bs_file, errp);
170
error_prepend(errp, "Failed to statically allocate file");
318
if (ret < 0) {
171
goto exit;
319
goto exit;
320
diff --git a/block/vhdx.c b/block/vhdx.c
172
diff --git a/block/vhdx.c b/block/vhdx.c
321
index XXXXXXX..XXXXXXX 100644
173
index XXXXXXX..XXXXXXX 100644
322
--- a/block/vhdx.c
174
--- a/block/vhdx.c
323
+++ b/block/vhdx.c
175
+++ b/block/vhdx.c
324
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
325
return -EIO;
177
/* All zeroes, so we can just extend the file - the end of the BAT
326
}
178
* is the furthest thing we have written yet */
327
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
328
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
180
- errp);
329
+ blk = blk_new(bdrv_get_aio_context(bs),
181
+ 0, errp);
330
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
182
if (ret < 0) {
331
ret = blk_insert_bs(blk, bs, errp);
183
goto exit;
332
if (ret < 0) {
184
}
333
goto delete_and_exit;
185
} else if (type == VHDX_TYPE_FIXED) {
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
187
- PREALLOC_MODE_OFF, errp);
188
+ PREALLOC_MODE_OFF, 0, errp);
189
if (ret < 0) {
190
goto exit;
191
}
334
diff --git a/block/vmdk.c b/block/vmdk.c
192
diff --git a/block/vmdk.c b/block/vmdk.c
335
index XXXXXXX..XXXXXXX 100644
193
index XXXXXXX..XXXXXXX 100644
336
--- a/block/vmdk.c
194
--- a/block/vmdk.c
337
+++ b/block/vmdk.c
195
+++ b/block/vmdk.c
338
@@ -XXX,XX +XXX,XX @@ static BlockBackend *vmdk_co_create_cb(int64_t size, int idx,
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
339
if (!bs) {
197
int gd_buf_size;
340
return NULL;
198
341
}
199
if (flat) {
342
- blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
343
+ blk = blk_new(bdrv_get_aio_context(bs),
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
344
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
202
goto exit;
345
BLK_PERM_ALL);
203
}
346
if (blk_insert_bs(blk, bs, errp)) {
204
magic = cpu_to_be32(VMDK4_MAGIC);
347
bdrv_unref(bs);
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
206
}
207
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
209
- PREALLOC_MODE_OFF, errp);
210
+ PREALLOC_MODE_OFF, 0, errp);
211
if (ret < 0) {
212
goto exit;
213
}
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
215
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
216
* for description file */
217
if (desc_offset == 0) {
218
- ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp);
219
+ ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
220
if (ret < 0) {
221
goto exit;
222
}
348
diff --git a/block/vpc.c b/block/vpc.c
223
diff --git a/block/vpc.c b/block/vpc.c
349
index XXXXXXX..XXXXXXX 100644
224
index XXXXXXX..XXXXXXX 100644
350
--- a/block/vpc.c
225
--- a/block/vpc.c
351
+++ b/block/vpc.c
226
+++ b/block/vpc.c
352
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
227
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
353
return -EIO;
228
/* Add footer to total size */
354
}
229
total_size += HEADER_SIZE;
355
230
356
- blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
231
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp);
357
+ blk = blk_new(bdrv_get_aio_context(bs),
232
+ ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
358
+ BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
233
if (ret < 0) {
359
ret = blk_insert_bs(blk, bs, errp);
234
return ret;
360
if (ret < 0) {
235
}
361
goto out;
362
diff --git a/blockdev.c b/blockdev.c
236
diff --git a/blockdev.c b/blockdev.c
363
index XXXXXXX..XXXXXXX 100644
237
index XXXXXXX..XXXXXXX 100644
364
--- a/blockdev.c
238
--- a/blockdev.c
365
+++ b/blockdev.c
239
+++ b/blockdev.c
366
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
367
if ((!file || !*file) && !qdict_size(bs_opts)) {
368
BlockBackendRootState *blk_rs;
369
370
- blk = blk_new(0, BLK_PERM_ALL);
371
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
372
blk_rs = blk_get_root_state(blk);
373
blk_rs->open_flags = bdrv_flags;
374
blk_rs->read_only = read_only;
375
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
376
goto out;
241
}
377
}
242
378
243
bdrv_drained_begin(bs);
379
- blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
380
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_RESIZE, BLK_PERM_ALL);
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
381
ret = blk_insert_bs(blk, bs, errp);
246
bdrv_drained_end(bs);
382
if (ret < 0) {
247
383
goto out;
248
out:
384
diff --git a/blockjob.c b/blockjob.c
385
index XXXXXXX..XXXXXXX 100644
386
--- a/blockjob.c
387
+++ b/blockjob.c
388
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
389
job_id = bdrv_get_device_name(bs);
390
}
391
392
- blk = blk_new(perm, shared_perm);
393
+ blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm);
394
ret = blk_insert_bs(blk, bs, errp);
395
if (ret < 0) {
396
blk_unref(blk);
397
diff --git a/hmp.c b/hmp.c
398
index XXXXXXX..XXXXXXX 100644
399
--- a/hmp.c
400
+++ b/hmp.c
401
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
402
if (!blk) {
403
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
404
if (bs) {
405
- blk = local_blk = blk_new(0, BLK_PERM_ALL);
406
+ blk = local_blk = blk_new(bdrv_get_aio_context(bs),
407
+ 0, BLK_PERM_ALL);
408
ret = blk_insert_bs(blk, bs, &err);
409
if (ret < 0) {
410
goto fail;
411
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
412
index XXXXXXX..XXXXXXX 100644
413
--- a/hw/block/fdc.c
414
+++ b/hw/block/fdc.c
415
@@ -XXX,XX +XXX,XX @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
416
417
if (!dev->conf.blk) {
418
/* Anonymous BlockBackend for an empty drive */
419
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
420
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
421
ret = blk_attach_dev(dev->conf.blk, qdev);
422
assert(ret == 0);
423
}
424
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
425
index XXXXXXX..XXXXXXX 100644
426
--- a/hw/block/xen-block.c
427
+++ b/hw/block/xen-block.c
428
@@ -XXX,XX +XXX,XX @@ static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
429
int rc;
430
431
/* Set up an empty drive */
432
- conf->blk = blk_new(0, BLK_PERM_ALL);
433
+ conf->blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
434
435
rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
436
if (!rc) {
437
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/core/qdev-properties-system.c
440
+++ b/hw/core/qdev-properties-system.c
441
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
442
if (!blk) {
443
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
444
if (bs) {
445
- blk = blk_new(0, BLK_PERM_ALL);
446
+ /* BlockBackends of devices start in the main context and are only
447
+ * later moved into another context if the device supports that. */
448
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
449
blk_created = true;
450
451
ret = blk_insert_bs(blk, bs, errp);
452
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
453
index XXXXXXX..XXXXXXX 100644
454
--- a/hw/ide/qdev.c
455
+++ b/hw/ide/qdev.c
456
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
457
return;
458
} else {
459
/* Anonymous BlockBackend for an empty drive */
460
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
461
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
462
ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
463
assert(ret == 0);
464
}
465
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
466
index XXXXXXX..XXXXXXX 100644
467
--- a/hw/scsi/scsi-disk.c
468
+++ b/hw/scsi/scsi-disk.c
469
@@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
470
if (!dev->conf.blk) {
471
/* Anonymous BlockBackend for an empty drive. As we put it into
472
* dev->conf, qdev takes care of detaching on unplug. */
473
- dev->conf.blk = blk_new(0, BLK_PERM_ALL);
474
+ dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
475
ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
476
assert(ret == 0);
477
}
478
diff --git a/migration/block.c b/migration/block.c
479
index XXXXXXX..XXXXXXX 100644
480
--- a/migration/block.c
481
+++ b/migration/block.c
482
@@ -XXX,XX +XXX,XX @@ static int init_blk_migration(QEMUFile *f)
483
}
484
485
bmds = g_new0(BlkMigDevState, 1);
486
- bmds->blk = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
487
+ bmds->blk = blk_new(qemu_get_aio_context(),
488
+ BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
489
bmds->blk_name = g_strdup(bdrv_get_device_name(bs));
490
bmds->bulk_completed = 0;
491
bmds->total_sectors = sectors;
492
diff --git a/nbd/server.c b/nbd/server.c
493
index XXXXXXX..XXXXXXX 100644
494
--- a/nbd/server.c
495
+++ b/nbd/server.c
496
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
497
if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
498
perm |= BLK_PERM_WRITE;
499
}
500
- blk = blk_new(perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
501
- BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
502
+ blk = blk_new(bdrv_get_aio_context(bs), perm,
503
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
504
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
505
ret = blk_insert_bs(blk, bs, errp);
506
if (ret < 0) {
507
goto fail;
508
diff --git a/qemu-img.c b/qemu-img.c
249
diff --git a/qemu-img.c b/qemu-img.c
509
index XXXXXXX..XXXXXXX 100644
250
index XXXXXXX..XXXXXXX 100644
510
--- a/qemu-img.c
251
--- a/qemu-img.c
511
+++ b/qemu-img.c
252
+++ b/qemu-img.c
512
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
513
BlockDriverState *base_bs = backing_bs(bs);
254
* resizing, so pass @exact=true. It is of no use to report
514
255
* success when the image has not actually been resized.
515
if (base_bs) {
256
*/
516
- blk_old_backing = blk_new(BLK_PERM_CONSISTENT_READ,
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
517
+ blk_old_backing = blk_new(qemu_get_aio_context(),
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
518
+ BLK_PERM_CONSISTENT_READ,
259
if (!ret) {
519
BLK_PERM_ALL);
260
qprintf(quiet, "Image resized.\n");
520
ret = blk_insert_bs(blk_old_backing, base_bs,
261
} else {
521
&local_err);
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
522
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
263
index XXXXXXX..XXXXXXX 100644
523
prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
264
--- a/qemu-io-cmds.c
524
if (prefix_chain_bs) {
265
+++ b/qemu-io-cmds.c
525
g_free(out_real_path);
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
526
- blk_new_backing = blk_new(BLK_PERM_CONSISTENT_READ,
267
* exact=true. It is better to err on the "emit more errors" side
527
+ blk_new_backing = blk_new(qemu_get_aio_context(),
268
* than to be overly permissive.
528
+ BLK_PERM_CONSISTENT_READ,
269
*/
529
BLK_PERM_ALL);
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
530
ret = blk_insert_bs(blk_new_backing, prefix_chain_bs,
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
531
&local_err);
272
if (ret < 0) {
532
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
273
error_report_err(local_err);
533
index XXXXXXX..XXXXXXX 100644
274
return ret;
534
--- a/tests/test-bdrv-drain.c
535
+++ b/tests/test-bdrv-drain.c
536
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
537
538
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
539
540
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
541
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
542
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
543
&error_abort);
544
s = bs->opaque;
545
@@ -XXX,XX +XXX,XX @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
546
BlockBackend *blk;
547
BlockDriverState *bs, *backing;
548
549
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
550
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
551
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
552
&error_abort);
553
blk_insert_bs(blk, bs, &error_abort);
554
@@ -XXX,XX +XXX,XX @@ static void test_nested(void)
555
BDRVTestState *s, *backing_s;
556
enum drain_type outer, inner;
557
558
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
559
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
560
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
561
&error_abort);
562
s = bs->opaque;
563
@@ -XXX,XX +XXX,XX @@ static void test_multiparent(void)
564
BlockDriverState *bs_a, *bs_b, *backing;
565
BDRVTestState *a_s, *b_s, *backing_s;
566
567
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
568
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
569
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
570
&error_abort);
571
a_s = bs_a->opaque;
572
blk_insert_bs(blk_a, bs_a, &error_abort);
573
574
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
575
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
576
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
577
&error_abort);
578
b_s = bs_b->opaque;
579
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_subtree(void)
580
BlockDriverState *bs_a, *bs_b, *backing;
581
BDRVTestState *a_s, *b_s, *backing_s;
582
583
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
584
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
585
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
586
&error_abort);
587
a_s = bs_a->opaque;
588
blk_insert_bs(blk_a, bs_a, &error_abort);
589
590
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
591
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
592
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
593
&error_abort);
594
b_s = bs_b->opaque;
595
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_all(void)
596
BDRVTestState *a_s, *b_s;
597
598
/* Create node A with a BlockBackend */
599
- blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
600
+ blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
601
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
602
&error_abort);
603
a_s = bs_a->opaque;
604
@@ -XXX,XX +XXX,XX @@ static void test_graph_change_drain_all(void)
605
g_assert_cmpint(a_s->drain_count, ==, 1);
606
607
/* Create node B with a BlockBackend */
608
- blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
609
+ blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
610
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
611
&error_abort);
612
b_s = bs_b->opaque;
613
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
614
goto out;
615
}
616
617
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
618
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
619
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
620
&error_abort);
621
s = bs->opaque;
622
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
623
bdrv_set_backing_hd(src, src_backing, &error_abort);
624
bdrv_unref(src_backing);
625
626
- blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
627
+ blk_src = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
628
blk_insert_bs(blk_src, src_overlay, &error_abort);
629
630
switch (drain_node) {
631
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
632
633
target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
634
&error_abort);
635
- blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
636
+ blk_target = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
637
blk_insert_bs(blk_target, target, &error_abort);
638
639
aio_context_acquire(ctx);
640
@@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
641
&error_abort);
642
bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
643
644
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
645
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
646
blk_insert_bs(blk, bs, &error_abort);
647
648
/* Referenced by blk now */
649
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
650
c = bdrv_new_open_driver(&bdrv_test, "c", BDRV_O_RDWR, &error_abort);
651
652
/* blk is a BB for parent-a */
653
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
654
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
655
blk_insert_bs(blk, parent_a, &error_abort);
656
bdrv_unref(parent_a);
657
658
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
659
BlockDriverState *base, *overlay;
660
BDRVTestState *base_s, *overlay_s;
661
662
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
663
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
664
base = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
665
base_s = base->opaque;
666
blk_insert_bs(blk, base, &error_abort);
667
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
668
index XXXXXXX..XXXXXXX 100644
669
--- a/tests/test-bdrv-graph-mod.c
670
+++ b/tests/test-bdrv-graph-mod.c
671
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
672
{
673
Error *local_err = NULL;
674
675
- BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
676
+ BlockBackend *root = blk_new(qemu_get_aio_context(),
677
+ BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
678
BLK_PERM_ALL & ~BLK_PERM_WRITE);
679
BlockDriverState *bs = no_perm_node("node");
680
BlockDriverState *filter = pass_through_node("filter");
681
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
682
*/
683
static void test_should_update_child(void)
684
{
685
- BlockBackend *root = blk_new(0, BLK_PERM_ALL);
686
+ BlockBackend *root = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
687
BlockDriverState *bs = no_perm_node("node");
688
BlockDriverState *filter = no_perm_node("filter");
689
BlockDriverState *target = no_perm_node("target");
690
diff --git a/tests/test-block-backend.c b/tests/test-block-backend.c
691
index XXXXXXX..XXXXXXX 100644
692
--- a/tests/test-block-backend.c
693
+++ b/tests/test-block-backend.c
694
@@ -XXX,XX +XXX,XX @@ static void test_drain_aio_error_flush_cb(void *opaque, int ret)
695
696
static void test_drain_aio_error(void)
697
{
698
- BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
699
+ BlockBackend *blk = blk_new(qemu_get_aio_context(),
700
+ BLK_PERM_ALL, BLK_PERM_ALL);
701
BlockAIOCB *acb;
702
bool completed = false;
703
704
@@ -XXX,XX +XXX,XX @@ static void test_drain_aio_error(void)
705
706
static void test_drain_all_aio_error(void)
707
{
708
- BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
709
+ BlockBackend *blk = blk_new(qemu_get_aio_context(),
710
+ BLK_PERM_ALL, BLK_PERM_ALL);
711
BlockAIOCB *acb;
712
bool completed = false;
713
714
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
715
index XXXXXXX..XXXXXXX 100644
716
--- a/tests/test-block-iothread.c
717
+++ b/tests/test-block-iothread.c
718
@@ -XXX,XX +XXX,XX @@ static void test_sync_op(const void *opaque)
719
BlockDriverState *bs;
720
BdrvChild *c;
721
722
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
723
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
724
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
725
bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
726
blk_insert_bs(blk, bs, &error_abort);
727
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
728
BlockDriverState *bs;
729
TestBlockJob *tjob;
730
731
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
732
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
733
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
734
blk_insert_bs(blk, bs, &error_abort);
735
736
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
737
QDict *options;
738
739
/* Create bs_a and its BlockBackend */
740
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
741
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
742
bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
743
blk_insert_bs(blk, bs_a, &error_abort);
744
745
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
746
qdict_put_str(options, "raw", "bs_c");
747
748
bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
749
- blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
750
+ blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
751
blk_insert_bs(blk, bs_verify, &error_abort);
752
753
/* Switch the AioContext */
754
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
755
g_assert(bdrv_get_aio_context(filter) == main_ctx);
756
757
/* With a BlockBackend on src, changing target must fail */
758
- blk = blk_new(0, BLK_PERM_ALL);
759
+ blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
760
blk_insert_bs(blk, src, &error_abort);
761
762
bdrv_try_set_aio_context(target, ctx, &local_err);
763
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
764
index XXXXXXX..XXXXXXX 100644
765
--- a/tests/test-blockjob.c
766
+++ b/tests/test-blockjob.c
767
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
768
static BlockBackend *create_blk(const char *name)
769
{
770
/* No I/O is performed on this device */
771
- BlockBackend *blk = blk_new(0, BLK_PERM_ALL);
772
+ BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
773
BlockDriverState *bs;
774
775
bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort);
776
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
777
index XXXXXXX..XXXXXXX 100644
778
--- a/tests/test-throttle.c
779
+++ b/tests/test-throttle.c
780
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
781
ThrottleGroupMember *tgm1, *tgm2, *tgm3;
782
783
/* No actual I/O is performed on these devices */
784
- blk1 = blk_new(0, BLK_PERM_ALL);
785
- blk2 = blk_new(0, BLK_PERM_ALL);
786
- blk3 = blk_new(0, BLK_PERM_ALL);
787
+ blk1 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
788
+ blk2 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
789
+ blk3 = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
790
791
blkp1 = blk_get_public(blk1);
792
blkp2 = blk_get_public(blk2);
793
--
275
--
794
2.20.1
276
2.25.3
795
277
796
278
diff view generated by jsdifflib
1
This makes use of qdev_prop_drive_iothread for scsi-disk so that the
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
2
disk can be attached to a node that is already in the target AioContext.
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
3
We need to check that the HBA actually supports iothreads, otherwise
3
undo any previous preallocation, but just adds the zero flag to all
4
scsi-disk must make sure that the node is already in the main
4
relevant L2 entries. If an external data file is in use, a write_zeroes
5
AioContext.
5
request to the data file is made instead.
6
7
This changes the error message for conflicting iothread settings.
8
Previously, virtio-scsi produced the error message, now it comes from
9
blk_set_aio_context(). Update a test case accordingly.
10
6
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
12
---
13
include/hw/scsi/scsi.h | 1 +
13
block/qcow2-cluster.c | 2 +-
14
hw/scsi/scsi-disk.c | 22 +++++++++++++++-------
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
15
hw/scsi/virtio-scsi.c | 15 ++++++++-------
15
2 files changed, 35 insertions(+), 1 deletion(-)
16
tests/qemu-iotests/240.out | 2 +-
17
4 files changed, 25 insertions(+), 15 deletions(-)
18
16
19
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/scsi/scsi.h
19
--- a/block/qcow2-cluster.c
22
+++ b/include/hw/scsi/scsi.h
20
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ struct SCSIDevice
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
24
int scsi_version;
22
/* Caller must pass aligned values, except at image end */
25
int default_scsi_version;
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
26
bool needs_vpd_bl_emulation;
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
27
+ bool hba_supports_iothread;
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
28
};
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
29
27
30
extern const VMStateDescription vmstate_scsi_device;
28
/* The zero flag is only supported by version 3 and newer */
31
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
29
if (s->qcow_version < 3) {
30
diff --git a/block/qcow2.c b/block/qcow2.c
32
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/scsi/scsi-disk.c
32
--- a/block/qcow2.c
34
+++ b/hw/scsi/scsi-disk.c
33
+++ b/block/qcow2.c
35
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
36
return;
35
36
bs->supported_zero_flags = header.version >= 3 ?
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
39
40
/* Repair image if dirty */
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
43
g_assert_not_reached();
37
}
44
}
38
45
39
+ if (blk_get_aio_context(s->qdev.conf.blk) != qemu_get_aio_context() &&
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
40
+ !s->qdev.hba_supports_iothread)
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
41
+ {
48
+
42
+ error_setg(errp, "HBA does not support iothreads");
49
+ /*
43
+ return;
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
52
+ * at the end of the image (which it is here).
53
+ */
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
55
+ if (ret < 0) {
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
57
+ goto fail;
58
+ }
59
+
60
+ /* Write explicit zeros for the unaligned head */
61
+ if (zero_start > old_length) {
62
+ uint64_t len = zero_start - old_length;
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
64
+ QEMUIOVector qiov;
65
+ qemu_iovec_init_buf(&qiov, buf, len);
66
+
67
+ qemu_co_mutex_unlock(&s->lock);
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
69
+ qemu_co_mutex_lock(&s->lock);
70
+
71
+ qemu_vfree(buf);
72
+ if (ret < 0) {
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
74
+ goto fail;
75
+ }
76
+ }
44
+ }
77
+ }
45
+
78
+
46
if (dev->type == TYPE_DISK) {
79
if (prealloc != PREALLOC_MODE_OFF) {
47
if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) {
80
/* Flush metadata before actually changing the image size */
48
return;
81
ret = qcow2_write_caches(bs);
49
@@ -XXX,XX +XXX,XX @@ static const TypeInfo scsi_disk_base_info = {
50
.abstract = true,
51
};
52
53
-#define DEFINE_SCSI_DISK_PROPERTIES() \
54
- DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \
55
- DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
56
- DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
57
- DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
58
- DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
59
- DEFINE_PROP_STRING("product", SCSIDiskState, product), \
60
+#define DEFINE_SCSI_DISK_PROPERTIES() \
61
+ DEFINE_PROP_DRIVE_IOTHREAD("drive", SCSIDiskState, qdev.conf.blk), \
62
+ DEFINE_BLOCK_PROPERTIES_BASE(SCSIDiskState, qdev.conf), \
63
+ DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
64
+ DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
65
+ DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
66
+ DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
67
+ DEFINE_PROP_STRING("product", SCSIDiskState, product), \
68
DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id)
69
70
71
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/scsi/virtio-scsi.c
74
+++ b/hw/scsi/virtio-scsi.c
75
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
76
}
77
}
78
79
+static void virtio_scsi_pre_hotplug(HotplugHandler *hotplug_dev,
80
+ DeviceState *dev, Error **errp)
81
+{
82
+ SCSIDevice *sd = SCSI_DEVICE(dev);
83
+ sd->hba_supports_iothread = true;
84
+}
85
+
86
static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
87
Error **errp)
88
{
89
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
90
int ret;
91
92
if (s->ctx && !s->dataplane_fenced) {
93
- AioContext *ctx;
94
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
95
return;
96
}
97
- ctx = blk_get_aio_context(sd->conf.blk);
98
- if (ctx != s->ctx && ctx != qemu_get_aio_context()) {
99
- error_setg(errp, "Cannot attach a blockdev that is using "
100
- "a different iothread");
101
- return;
102
- }
103
virtio_scsi_acquire(s);
104
ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
105
virtio_scsi_release(s);
106
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
107
vdc->reset = virtio_scsi_reset;
108
vdc->start_ioeventfd = virtio_scsi_dataplane_start;
109
vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
110
+ hc->pre_plug = virtio_scsi_pre_hotplug;
111
hc->plug = virtio_scsi_hotplug;
112
hc->unplug = virtio_scsi_hotunplug;
113
}
114
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
115
index XXXXXXX..XXXXXXX 100644
116
--- a/tests/qemu-iotests/240.out
117
+++ b/tests/qemu-iotests/240.out
118
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
119
{"return": {}}
120
{"return": {}}
121
{"return": {}}
122
-{"error": {"class": "GenericError", "desc": "Cannot attach a blockdev that is using a different iothread"}}
123
+{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}}
124
{"return": {}}
125
{"return": {}}
126
{"return": {}}
127
--
82
--
128
2.20.1
83
2.25.3
129
84
130
85
diff view generated by jsdifflib
1
All callers of bdrv_set_aio_context() are eliminated now, they have
1
The raw format driver can simply forward the flag and let its bs->file
2
moved to bdrv_try_set_aio_context() and related safe functions. Remove
2
child take care of actually providing the zeros.
3
bdrv_set_aio_context().
4
5
With this, we can now know that the .set_aio_ctx callback must be
6
present in bdrv_set_aio_context_ignore() because
7
bdrv_can_set_aio_context() would have returned false previously, so
8
instead of checking the condition, we can assert it.
9
3
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
docs/devel/multiple-iothreads.txt | 4 ++--
11
block/raw-format.c | 4 +++-
13
include/block/block.h | 9 ---------
12
1 file changed, 3 insertions(+), 1 deletion(-)
14
block.c | 30 ++++++++++++++----------------
15
3 files changed, 16 insertions(+), 27 deletions(-)
16
13
17
diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt
14
diff --git a/block/raw-format.c b/block/raw-format.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/devel/multiple-iothreads.txt
16
--- a/block/raw-format.c
20
+++ b/docs/devel/multiple-iothreads.txt
17
+++ b/block/raw-format.c
21
@@ -XXX,XX +XXX,XX @@ The AioContext originates from the QEMU block layer, even though nowadays
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
22
AioContext is a generic event loop that can be used by any QEMU subsystem.
19
23
20
s->size = offset;
24
The block layer has support for AioContext integrated. Each BlockDriverState
21
offset += s->offset;
25
-is associated with an AioContext using bdrv_set_aio_context() and
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
26
+is associated with an AioContext using bdrv_try_set_aio_context() and
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
27
bdrv_get_aio_context(). This allows block layer code to process I/O inside the
28
right AioContext. Other subsystems may wish to follow a similar approach.
29
30
@@ -XXX,XX +XXX,XX @@ Long-running jobs (usually in the form of coroutines) are best scheduled in
31
the BlockDriverState's AioContext to avoid the need to acquire/release around
32
each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier,
33
or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends,
34
-can be used to get a notification whenever bdrv_set_aio_context() moves a
35
+can be used to get a notification whenever bdrv_try_set_aio_context() moves a
36
BlockDriverState to a different AioContext.
37
diff --git a/include/block/block.h b/include/block/block.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block.h
40
+++ b/include/block/block.h
41
@@ -XXX,XX +XXX,XX @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs);
42
*/
43
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
44
45
-/**
46
- * bdrv_set_aio_context:
47
- *
48
- * Changes the #AioContext used for fd handlers, timers, and BHs by this
49
- * BlockDriverState and all its children.
50
- *
51
- * This function must be called with iothread lock held.
52
- */
53
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
54
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
55
AioContext *new_context, GSList **ignore);
56
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
57
diff --git a/block.c b/block.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block.c
60
+++ b/block.c
61
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
62
bs->walking_aio_notifiers = false;
63
}
24
}
64
25
65
-/* @ignore will accumulate all visited BdrvChild object. The caller is
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
66
- * responsible for freeing the list afterwards. */
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
67
+/*
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
68
+ * Changes the AioContext used for fd handlers, timers, and BHs by this
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
69
+ * BlockDriverState and all its children and parents.
30
bs->file->bs->supported_zero_flags);
70
+ *
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
71
+ * The caller must own the AioContext lock for the old AioContext of bs, but it
32
+ BDRV_REQ_ZERO_WRITE;
72
+ * must not own the AioContext lock for new_context (unless new_context is the
33
73
+ * same as the current context of bs).
34
if (bs->probed && !bdrv_is_read_only(bs)) {
74
+ *
35
bdrv_refresh_filename(bs->file->bs);
75
+ * @ignore will accumulate all visited BdrvChild object. The caller is
76
+ * responsible for freeing the list afterwards.
77
+ */
78
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
79
AioContext *new_context, GSList **ignore)
80
{
81
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
82
if (g_slist_find(*ignore, child)) {
83
continue;
84
}
85
- if (child->role->set_aio_ctx) {
86
- *ignore = g_slist_prepend(*ignore, child);
87
- child->role->set_aio_ctx(child, new_context, ignore);
88
- }
89
+ assert(child->role->set_aio_ctx);
90
+ *ignore = g_slist_prepend(*ignore, child);
91
+ child->role->set_aio_ctx(child, new_context, ignore);
92
}
93
94
bdrv_detach_aio_context(bs);
95
@@ -XXX,XX +XXX,XX @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
96
aio_context_release(new_context);
97
}
98
99
-/* The caller must own the AioContext lock for the old AioContext of bs, but it
100
- * must not own the AioContext lock for new_context (unless new_context is
101
- * the same as the current context of bs). */
102
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
103
-{
104
- GSList *ignore_list = NULL;
105
- bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
106
- g_slist_free(ignore_list);
107
-}
108
-
109
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
110
GSList **ignore, Error **errp)
111
{
112
--
36
--
113
2.20.1
37
2.25.3
114
38
115
39
diff view generated by jsdifflib
1
No reason to use the unchecked version in tests, even more so when these
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
are the last callers of bdrv_set_aio_context() outside of block.c.
2
OS, so we can advertise the flag and just ignore it.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
10
---
6
tests/test-bdrv-drain.c | 6 +++---
11
block/file-posix.c | 4 ++++
7
1 file changed, 3 insertions(+), 3 deletions(-)
12
1 file changed, 4 insertions(+)
8
13
9
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
14
diff --git a/block/file-posix.c b/block/file-posix.c
10
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/test-bdrv-drain.c
16
--- a/block/file-posix.c
12
+++ b/tests/test-bdrv-drain.c
17
+++ b/block/file-posix.c
13
@@ -XXX,XX +XXX,XX @@ static void test_set_aio_context(void)
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
14
&error_abort);
19
#endif
15
20
16
bdrv_drained_begin(bs);
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
17
- bdrv_set_aio_context(bs, ctx_a);
22
+ if (S_ISREG(st.st_mode)) {
18
+ bdrv_try_set_aio_context(bs, ctx_a, &error_abort);
23
+ /* When extending regular files, we get zeros from the OS */
19
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
20
aio_context_acquire(ctx_a);
25
+ }
21
bdrv_drained_end(bs);
26
ret = 0;
22
27
fail:
23
bdrv_drained_begin(bs);
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
24
- bdrv_set_aio_context(bs, ctx_b);
25
+ bdrv_try_set_aio_context(bs, ctx_b, &error_abort);
26
aio_context_release(ctx_a);
27
aio_context_acquire(ctx_b);
28
- bdrv_set_aio_context(bs, qemu_get_aio_context());
29
+ bdrv_try_set_aio_context(bs, qemu_get_aio_context(), &error_abort);
30
aio_context_release(ctx_b);
31
bdrv_drained_end(bs);
32
33
--
29
--
34
2.20.1
30
2.25.3
35
31
36
32
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
When extending the size of an image that has a backing file larger than
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
2
4
3
When ending a drained section, bdrv_do_drained_end() currently first
5
Consider the following scenario where the overlay is shorter than its
4
decrements the quiesce_counter, and only then actually ends the drain.
6
backing file:
5
7
6
The bdrv_drain_invoke(bs, false) call may cause graph changes. Say the
8
base.qcow2: AAAAAAAA
7
graph change involves replacing an existing BB's ("blk") BDS
9
overlay.qcow2: BBBB
8
(blk_bs(blk)) by @bs. Let us introducing the following values:
9
- bs_oqc = old_quiesce_counter
10
(so bs->quiesce_counter == bs_oqc - 1)
11
- obs_qc = blk_bs(blk)->quiesce_counter (before bdrv_drain_invoke())
12
10
13
Let us assume there is no blk_pread_unthrottled() involved, so
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
14
blk->quiesce_counter == obs_qc (before bdrv_drain_invoke()).
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
15
14
16
Now replacing blk_bs(blk) by @bs will reduce blk->quiesce_counter by
15
A similar case happens with the various variants of a commit job when an
17
obs_qc (making it 0) and increase it by bs_oqc-1 (making it bs_oqc-1).
16
intermediate file is short (- for unallocated):
18
17
19
bdrv_drain_invoke() returns and we invoke bdrv_parent_drained_end().
18
base.qcow2: A-A-AAAA
20
This will decrement blk->quiesce_counter by one, so it would be -1 --
19
mid.qcow2: BB-B
21
were there not an assertion against that in blk_root_drained_end().
20
top.qcow2: C--C--C-
22
21
23
We therefore have to keep the quiesce_counter up at least until
22
After commit top.qcow2 to mid.qcow2, the following happens:
24
bdrv_drain_invoke() returns, so that bdrv_parent_drained_end() does the
25
right thing for the parents @bs got during bdrv_drain_invoke().
26
23
27
But let us delay it even further, namely until bdrv_parent_drained_end()
24
mid.qcow2: CB-C00C0 (correct result)
28
returns, because then it mirrors bdrv_do_drained_begin(): There, we
25
mid.qcow2: CB-C--C- (before this fix)
29
first increment the quiesce_counter, then begin draining the parents,
30
and then call bdrv_drain_invoke(). It makes sense to let
31
bdrv_do_drained_end() unravel this exactly in reverse.
32
26
33
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Without the fix, blocks that previously read as zeros on top.qcow2
28
suddenly turn into A.
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
Message-Id: <20200424125448.63318-8-kwolf@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
35
---
36
block/io.c | 3 ++-
36
block/io.c | 25 +++++++++++++++++++++++++
37
1 file changed, 2 insertions(+), 1 deletion(-)
37
1 file changed, 25 insertions(+)
38
38
39
diff --git a/block/io.c b/block/io.c
39
diff --git a/block/io.c b/block/io.c
40
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/io.c
41
--- a/block/io.c
42
+++ b/block/io.c
42
+++ b/block/io.c
43
@@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
44
return;
44
goto out;
45
}
45
}
46
assert(bs->quiesce_counter > 0);
46
47
- old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
47
+ /*
48
48
+ * If the image has a backing file that is large enough that it would
49
/* Re-enable things in child-to-parent order */
49
+ * provide data for the new area, we cannot leave it unallocated because
50
bdrv_drain_invoke(bs, false);
50
+ * then the backing file content would become visible. Instead, zero-fill
51
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
51
+ * the new area.
52
+ *
53
+ * Note that if the image has a backing file, but was opened without the
54
+ * backing file, taking care of keeping things consistent with that backing
55
+ * file is the user's responsibility.
56
+ */
57
+ if (new_bytes && bs->backing) {
58
+ int64_t backing_len;
52
+
59
+
53
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
60
+ backing_len = bdrv_getlength(backing_bs(bs));
54
if (old_quiesce_counter == 1) {
61
+ if (backing_len < 0) {
55
aio_enable_external(bdrv_get_aio_context(bs));
62
+ ret = backing_len;
56
}
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
64
+ goto out;
65
+ }
66
+
67
+ if (backing_len > old_size) {
68
+ flags |= BDRV_REQ_ZERO_WRITE;
69
+ }
70
+ }
71
+
72
if (drv->bdrv_co_truncate) {
73
if (flags & ~bs->supported_truncate_flags) {
74
error_setg(errp, "Block driver does not support requested flags");
57
--
75
--
58
2.20.1
76
2.25.3
59
77
60
78
diff view generated by jsdifflib
1
This tests that blockdev-add can correctly add a qcow2 overlay to an
1
We want to keep TEST_IMG for the full path of the main test image, but
2
image used by a virtio-scsi disk in an iothread. The interesting point
2
filter_testfiles() must be called for other test images before replacing
3
here is whether the newly added node gets correctly moved into the
3
other things like the image format because the test directory path could
4
iothread AioContext.
4
contain the format as a substring.
5
5
6
If it isn't, we get an assertion failure in virtio-scsi while processing
6
Insert a filter_testfiles() call between both.
7
the next request:
8
9
virtio_scsi_ctx_check: Assertion `blk_get_aio_context(d->conf.blk) == s->ctx' failed.
10
7
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
---
13
tests/libqtest.h | 11 +++++++
14
tests/qemu-iotests/iotests.py | 5 +++--
14
tests/libqtest.c | 19 ++++++++++++
15
1 file changed, 3 insertions(+), 2 deletions(-)
15
tests/virtio-scsi-test.c | 62 ++++++++++++++++++++++++++++++++++++++++
16
3 files changed, 92 insertions(+)
17
16
18
diff --git a/tests/libqtest.h b/tests/libqtest.h
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/libqtest.h
19
--- a/tests/qemu-iotests/iotests.py
21
+++ b/tests/libqtest.h
20
+++ b/tests/qemu-iotests/iotests.py
22
@@ -XXX,XX +XXX,XX @@ static inline void qtest_end(void)
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
23
QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
22
for line in output.split('\n'):
24
23
if 'disk size' in line or 'actual-size' in line:
25
/**
24
continue
26
+ * qmp_assert_success:
25
- line = line.replace(filename, 'TEST_IMG') \
27
+ * @fmt...: QMP message to send to qemu, formatted like
26
- .replace(imgfmt, 'IMGFMT')
28
+ * qobject_from_jsonf_nofail(). See parse_escape() for what's
27
+ line = line.replace(filename, 'TEST_IMG')
29
+ * supported after '%'.
28
+ line = filter_testfiles(line)
30
+ *
29
+ line = line.replace(imgfmt, 'IMGFMT')
31
+ * Sends a QMP message to QEMU and asserts that a 'return' key is present in
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
32
+ * the response.
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
33
+ */
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
34
+void qmp_assert_success(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
35
+
36
+/*
37
* qmp_eventwait:
38
* @s: #event event to wait for.
39
*
40
diff --git a/tests/libqtest.c b/tests/libqtest.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/tests/libqtest.c
43
+++ b/tests/libqtest.c
44
@@ -XXX,XX +XXX,XX @@ QDict *qmp(const char *fmt, ...)
45
return response;
46
}
47
48
+void qmp_assert_success(const char *fmt, ...)
49
+{
50
+ va_list ap;
51
+ QDict *response;
52
+
53
+ va_start(ap, fmt);
54
+ response = qtest_vqmp(global_qtest, fmt, ap);
55
+ va_end(ap);
56
+
57
+ g_assert(response);
58
+ if (!qdict_haskey(response, "return")) {
59
+ QString *s = qobject_to_json_pretty(QOBJECT(response));
60
+ g_test_message("%s", qstring_get_str(s));
61
+ qobject_unref(s);
62
+ }
63
+ g_assert(qdict_haskey(response, "return"));
64
+ qobject_unref(response);
65
+}
66
+
67
char *hmp(const char *fmt, ...)
68
{
69
va_list ap;
70
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/tests/virtio-scsi-test.c
73
+++ b/tests/virtio-scsi-test.c
74
@@ -XXX,XX +XXX,XX @@ static void test_unaligned_write_same(void *obj, void *data,
75
qvirtio_scsi_pci_free(vs);
76
}
77
78
+static void test_iothread_attach_node(void *obj, void *data,
79
+ QGuestAllocator *t_alloc)
80
+{
81
+ QVirtioSCSI *scsi = obj;
82
+ QVirtioSCSIQueues *vs;
83
+ char tmp_path[] = "/tmp/qtest.XXXXXX";
84
+ int fd;
85
+ int ret;
86
+
87
+ uint8_t buf[512] = { 0 };
88
+ const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = {
89
+ /* WRITE(10) to LBA 0, transfer length 1 */
90
+ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
91
+ };
92
+
93
+ alloc = t_alloc;
94
+ vs = qvirtio_scsi_init(scsi->vdev);
95
+
96
+ /* Create a temporary qcow2 overlay*/
97
+ fd = mkstemp(tmp_path);
98
+ g_assert(fd >= 0);
99
+ close(fd);
100
+
101
+ if (!have_qemu_img()) {
102
+ g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
103
+ "skipping snapshot test");
104
+ goto fail;
105
+ }
106
+
107
+ mkqcow2(tmp_path, 64);
108
+
109
+ /* Attach the overlay to the null0 node */
110
+ qmp_assert_success("{'execute': 'blockdev-add', 'arguments': {"
111
+ " 'driver': 'qcow2', 'node-name': 'overlay',"
112
+ " 'backing': 'null0', 'file': {"
113
+ " 'driver': 'file', 'filename': %s}}}", tmp_path);
114
+
115
+ /* Send a request to see if the AioContext is still right */
116
+ ret = virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 512, NULL);
117
+ g_assert_cmphex(ret, ==, 0);
118
+
119
+fail:
120
+ qvirtio_scsi_pci_free(vs);
121
+ unlink(tmp_path);
122
+}
123
+
124
static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg)
125
{
126
g_string_append(cmd_line,
127
@@ -XXX,XX +XXX,XX @@ static void *virtio_scsi_setup(GString *cmd_line, void *arg)
128
return arg;
129
}
130
131
+static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg)
132
+{
133
+ g_string_append(cmd_line,
134
+ " -object iothread,id=thread0"
135
+ " -blockdev driver=null-co,node-name=null0"
136
+ " -device scsi-hd,drive=null0");
137
+ return arg;
138
+}
139
+
140
static void register_virtio_scsi_test(void)
141
{
142
QOSGraphTestOptions opts = { };
143
@@ -XXX,XX +XXX,XX @@ static void register_virtio_scsi_test(void)
144
opts.before = virtio_scsi_setup;
145
qos_add_test("unaligned-write-same", "virtio-scsi",
146
test_unaligned_write_same, &opts);
147
+
148
+ opts.before = virtio_scsi_setup_iothread;
149
+ opts.edge = (QOSGraphEdgeOptions) {
150
+ .extra_device_opts = "iothread=thread0",
151
+ };
152
+ qos_add_test("iothread-attach-node", "virtio-scsi",
153
+ test_iothread_attach_node, &opts);
154
}
155
156
libqos_init(register_virtio_scsi_test);
157
--
33
--
158
2.20.1
34
2.25.3
159
35
160
36
diff view generated by jsdifflib
1
This tests that concurrent requests are correctly drained before making
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
graph modifications instead of running into assertions in
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
bdrv_replace_node().
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/group | 1 +
10
3 files changed, 424 insertions(+)
11
create mode 100755 tests/qemu-iotests/274
12
create mode 100644 tests/qemu-iotests/274.out
4
13
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/255 | 83 +++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/255.out | 16 +++++++
10
tests/qemu-iotests/group | 1 +
11
tests/qemu-iotests/iotests.py | 10 ++++-
12
4 files changed, 109 insertions(+), 1 deletion(-)
13
create mode 100755 tests/qemu-iotests/255
14
create mode 100644 tests/qemu-iotests/255.out
15
16
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
17
new file mode 100755
15
new file mode 100755
18
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
19
--- /dev/null
17
--- /dev/null
20
+++ b/tests/qemu-iotests/255
18
+++ b/tests/qemu-iotests/274
21
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env python
20
+#!/usr/bin/env python3
23
+#
24
+# Test commit job graph modifications while requests are active
25
+#
21
+#
26
+# Copyright (C) 2019 Red Hat, Inc.
22
+# Copyright (C) 2019 Red Hat, Inc.
27
+#
28
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
29
+#
23
+#
30
+# This program is free software; you can redistribute it and/or modify
24
+# This program is free software; you can redistribute it and/or modify
31
+# it under the terms of the GNU General Public License as published by
25
+# it under the terms of the GNU General Public License as published by
32
+# the Free Software Foundation; either version 2 of the License, or
26
+# the Free Software Foundation; either version 2 of the License, or
33
+# (at your option) any later version.
27
+# (at your option) any later version.
...
...
38
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
39
+#
33
+#
40
+# You should have received a copy of the GNU General Public License
34
+# You should have received a copy of the GNU General Public License
41
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
42
+#
36
+#
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
38
+#
39
+# Some tests for short backing files and short overlays
43
+
40
+
44
+import iotests
41
+import iotests
45
+from iotests import imgfmt
46
+
42
+
47
+iotests.verify_image_format(supported_fmts=['qcow2'])
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
48
+
44
+iotests.verify_platform(['linux'])
49
+def blockdev_create(vm, options):
45
+
50
+ result = vm.qmp_log('blockdev-create',
46
+size_short = 1 * 1024 * 1024
51
+ filters=[iotests.filter_qmp_testfiles],
47
+size_long = 2 * 1024 * 1024
52
+ job_id='job0', options=options)
48
+size_diff = size_long - size_short
53
+
49
+
54
+ if 'return' in result:
50
+def create_chain() -> None:
55
+ assert result['return'] == {}
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
56
+ vm.run_job('job0')
52
+ str(size_long))
57
+ iotests.log("")
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
58
+
54
+ str(size_short))
59
+with iotests.FilePath('t.qcow2') as disk_path, \
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
60
+ iotests.FilePath('t.qcow2.mid') as mid_path, \
56
+ str(size_long))
61
+ iotests.FilePath('t.qcow2.base') as base_path, \
57
+
62
+ iotests.VM() as vm:
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
63
+
59
+
64
+ iotests.log("=== Create backing chain and start VM ===")
60
+def create_vm() -> iotests.VM:
65
+ iotests.log("")
61
+ vm = iotests.VM()
66
+
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
67
+ size = 128 * 1024 * 1024
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
68
+ size_str = str(size)
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
69
+
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
70
+ iotests.create_image(base_path, size)
66
+ % iotests.imgfmt)
71
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, mid_path, size_str)
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
72
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, disk_path, size_str)
68
+ return vm
73
+
69
+
74
+ # Create a backing chain like this:
70
+with iotests.FilePath('base') as base, \
75
+ # base <- [throttled: bps-read=4096] <- mid <- overlay
71
+ iotests.FilePath('mid') as mid, \
76
+
72
+ iotests.FilePath('top') as top:
77
+ vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
73
+
78
+ vm.add_blockdev('file,filename=%s,node-name=base' % (base_path))
74
+ iotests.log('== Commit tests ==')
79
+ vm.add_blockdev('throttle,throttle-group=throttle0,file=base,node-name=throttled')
75
+
80
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % (mid_path))
76
+ create_chain()
81
+ vm.add_blockdev('qcow2,file=mid-file,node-name=mid,backing=throttled')
77
+
82
+ vm.add_drive_raw('if=none,id=overlay,driver=qcow2,file=%s,backing=mid' % (disk_path))
78
+ iotests.log('=== Check visible data ===')
83
+
79
+
84
+ vm.launch()
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
85
+
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
86
+ iotests.log("=== Start background read requests ===")
82
+
87
+ iotests.log("")
83
+ iotests.log('=== Checking allocation status ===')
88
+
84
+
89
+ def start_requests():
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
90
+ vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
91
+ vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
87
+ base)
92
+
88
+
93
+ start_requests()
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
94
+
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
95
+ iotests.log("=== Run a commit job ===")
91
+ mid)
96
+ iotests.log("")
92
+
97
+
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
98
+ result = vm.qmp_log('block-commit', job_id='job0', auto_finalize=False,
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
99
+ device='overlay', top_node='mid')
95
+ top)
100
+
96
+
101
+ vm.run_job('job0', auto_finalize=False, pre_finalize=start_requests,
97
+ iotests.log('=== Checking map ===')
102
+ auto_dismiss=True)
98
+
103
+
99
+ iotests.qemu_img_log('map', '--output=json', base)
104
+ vm.shutdown()
100
+ iotests.qemu_img_log('map', '--output=human', base)
105
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
101
+ iotests.qemu_img_log('map', '--output=json', mid)
102
+ iotests.qemu_img_log('map', '--output=human', mid)
103
+ iotests.qemu_img_log('map', '--output=json', top)
104
+ iotests.qemu_img_log('map', '--output=human', top)
105
+
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
107
+
108
+ iotests.qemu_img_log('commit', top)
109
+ iotests.img_info_log(mid)
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
112
+
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
114
+
115
+ create_chain()
116
+ with create_vm() as vm:
117
+ vm.launch()
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
119
+
120
+ iotests.img_info_log(mid)
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
123
+
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
125
+
126
+ create_chain()
127
+ with create_vm() as vm:
128
+ vm.launch()
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
130
+ job_id='job0', auto_dismiss=False)
131
+ vm.run_job('job0', wait=5)
132
+
133
+ iotests.img_info_log(mid)
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
136
+
137
+
138
+ iotests.log('== Resize tests ==')
139
+
140
+ # Use different sizes for different allocation modes:
141
+ #
142
+ # We want to have at least one test where 32 bit truncation in the size of
143
+ # the overlapping area becomes visible. This is covered by the
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
145
+ #
146
+ # However, we can only do this for modes that don't preallocate data
147
+ # because otherwise we might run out of space on the test host.
148
+ #
149
+ # We also want to test some unaligned combinations.
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
151
+ ('off', '6G', '1G', '8G', '5G'),
152
+ ('metadata', '32G', '30G', '33G', '31G'),
153
+ ('falloc', '10M', '5M', '15M', '9M'),
154
+ ('full', '16M', '8M', '12M', '11M'),
155
+ ('off', '384k', '253k', '512k', '253k'),
156
+ ('off', '400k', '256k', '512k', '336k'),
157
+ ('off', '512k', '256k', '500k', '436k')]:
158
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
162
+ top_size_old)
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
164
+
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
166
+ #
167
+ # In theory, leaving base_size to top_size_new unallocated would be
168
+ # correct, but in practice, if we zero out anything, we zero out
169
+ # everything up to top_size_new.
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
171
+ '--preallocation', prealloc, top, top_size_new)
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
173
+ iotests.qemu_io_log('-c', 'map', top)
174
+ iotests.qemu_img_log('map', '--output=json', top)
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
106
new file mode 100644
176
new file mode 100644
107
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
108
--- /dev/null
178
--- /dev/null
109
+++ b/tests/qemu-iotests/255.out
179
+++ b/tests/qemu-iotests/274.out
110
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
111
+=== Create backing chain and start VM ===
181
+== Commit tests ==
112
+
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
113
+Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
183
+
114
+
184
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
115
+Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
185
+
116
+
186
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
117
+=== Start background read requests ===
187
+
118
+
188
+wrote 2097152/2097152 bytes at offset 0
119
+=== Run a commit job ===
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
120
+
190
+
121
+{"execute": "block-commit", "arguments": {"auto-finalize": false, "device": "overlay", "job-id": "job0", "top-node": "mid"}}
191
+=== Check visible data ===
192
+read 1048576/1048576 bytes at offset 0
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+
195
+read 1048576/1048576 bytes at offset 1048576
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
197
+
198
+=== Checking allocation status ===
199
+1048576/1048576 bytes allocated at offset 0 bytes
200
+1048576/1048576 bytes allocated at offset 1 MiB
201
+
202
+0/1048576 bytes allocated at offset 0 bytes
203
+0/0 bytes allocated at offset 1 MiB
204
+
205
+0/1048576 bytes allocated at offset 0 bytes
206
+0/1048576 bytes allocated at offset 1 MiB
207
+
208
+=== Checking map ===
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
211
+Offset Length Mapped to File
212
+0 0x200000 0x50000 TEST_DIR/PID-base
213
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
215
+
216
+Offset Length Mapped to File
217
+0 0x100000 0x50000 TEST_DIR/PID-base
218
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
222
+Offset Length Mapped to File
223
+0 0x100000 0x50000 TEST_DIR/PID-base
224
+
225
+=== Testing qemu-img commit (top -> mid) ===
226
+Image committed.
227
+
228
+image: TEST_IMG
229
+file format: IMGFMT
230
+virtual size: 2 MiB (2097152 bytes)
231
+cluster_size: 65536
232
+backing file: TEST_DIR/PID-base
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
239
+read 1048576/1048576 bytes at offset 0
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
242
+read 1048576/1048576 bytes at offset 1048576
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
244
+
245
+=== Testing HMP commit (top -> mid) ===
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
247
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
249
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
251
+
252
+wrote 2097152/2097152 bytes at offset 0
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
256
+{"return": ""}
257
+image: TEST_IMG
258
+file format: IMGFMT
259
+virtual size: 2 MiB (2097152 bytes)
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
268
+read 1048576/1048576 bytes at offset 0
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
+
271
+read 1048576/1048576 bytes at offset 1048576
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+
274
+=== Testing QMP active commit (top -> mid) ===
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
280
+
281
+wrote 2097152/2097152 bytes at offset 0
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
283
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
122
+{"return": {}}
285
+{"return": {}}
123
+{"execute": "job-finalize", "arguments": {"id": "job0"}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
124
+{"return": {}}
287
+{"return": {}}
125
+{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
126
+{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
333
+
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
448
+
127
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
128
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
129
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
130
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
131
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
132
252 rw auto backing quick
454
270 rw backing quick
133
253 rw auto quick
455
272 rw
134
254 rw auto backing quick
456
273 backing quick
135
+255 rw auto quick
457
+274 rw backing
136
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
458
277 rw quick
137
index XXXXXXX..XXXXXXX 100644
459
279 rw backing quick
138
--- a/tests/qemu-iotests/iotests.py
460
280 rw migration quick
139
+++ b/tests/qemu-iotests/iotests.py
140
@@ -XXX,XX +XXX,XX @@ def qemu_img_pipe(*args):
141
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
142
return subp.communicate()[0]
143
144
+def qemu_img_log(*args):
145
+ result = qemu_img_pipe(*args)
146
+ log(result, filters=[filter_testfiles])
147
+ return result
148
+
149
def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
150
args = [ 'info' ]
151
if imgopts:
152
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
153
return result
154
155
# Returns None on success, and an error string on failure
156
- def run_job(self, job, auto_finalize=True, auto_dismiss=False):
157
+ def run_job(self, job, auto_finalize=True, auto_dismiss=False,
158
+ pre_finalize=None):
159
error = None
160
while True:
161
for ev in self.get_qmp_events_filtered(wait=True):
162
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
163
error = j['error']
164
log('Job failed: %s' % (j['error']))
165
elif status == 'pending' and not auto_finalize:
166
+ if pre_finalize:
167
+ pre_finalize()
168
self.qmp_log('job-finalize', id=job)
169
elif status == 'concluded' and not auto_dismiss:
170
self.qmp_log('job-dismiss', id=job)
171
--
461
--
172
2.20.1
462
2.25.3
173
463
174
464
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
If the bitmap can't be used for whatever reason, we skip putting down
4
the reference. Fix that.
5
6
In practice, this means that if you attempt to gracefully exit QEMU
7
after a backup command being rejected, bdrv_close_all will fail and
8
tell you some unpleasant things via assert().
9
10
Reported-by: aihua liang <aliang@redhat.com>
11
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1703916
12
Signed-off-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
blockdev.c | 13 ++++++-------
17
1 file changed, 6 insertions(+), 7 deletions(-)
18
19
diff --git a/blockdev.c b/blockdev.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/blockdev.c
22
+++ b/blockdev.c
23
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
24
if (set_backing_hd) {
25
bdrv_set_backing_hd(target_bs, source, &local_err);
26
if (local_err) {
27
- bdrv_unref(target_bs);
28
- goto out;
29
+ goto unref;
30
}
31
}
32
33
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
34
bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap);
35
if (!bmap) {
36
error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap);
37
- bdrv_unref(target_bs);
38
- goto out;
39
+ goto unref;
40
}
41
if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) {
42
- goto out;
43
+ goto unref;
44
}
45
}
46
if (!backup->auto_finalize) {
47
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
48
backup->sync, bmap, backup->compress,
49
backup->on_source_error, backup->on_target_error,
50
job_flags, NULL, NULL, txn, &local_err);
51
- bdrv_unref(target_bs);
52
if (local_err != NULL) {
53
error_propagate(errp, local_err);
54
- goto out;
55
+ goto unref;
56
}
57
58
+unref:
59
+ bdrv_unref(target_bs);
60
out:
61
aio_context_release(aio_context);
62
return job;
63
--
64
2.20.1
65
66
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Block layer may recursively check block_status in file child of qcow2,
4
if qcow2 driver returned DATA. There are several test cases to check
5
influence of lseek on block_status performance. To see real difference
6
run on tmpfs.
7
8
Tests originally created by Kevin, I just refactored and put them
9
together into one executable file with simple output.
10
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
tests/perf/block/qcow2/convert-blockstatus | 71 ++++++++++++++++++++++
15
1 file changed, 71 insertions(+)
16
create mode 100755 tests/perf/block/qcow2/convert-blockstatus
17
18
diff --git a/tests/perf/block/qcow2/convert-blockstatus b/tests/perf/block/qcow2/convert-blockstatus
19
new file mode 100755
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/perf/block/qcow2/convert-blockstatus
23
@@ -XXX,XX +XXX,XX @@
24
+#!/bin/bash
25
+#
26
+# Test lseek influence on qcow2 block-status
27
+#
28
+# Block layer may recursively check block_status in file child of qcow2, if
29
+# qcow2 driver returned DATA. There are several test cases to check influence
30
+# of lseek on block_status performance. To see real difference run on tmpfs.
31
+#
32
+# Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
33
+#
34
+# Tests originally written by Kevin Wolf
35
+#
36
+# This program is free software; you can redistribute it and/or modify
37
+# it under the terms of the GNU General Public License as published by
38
+# the Free Software Foundation; either version 2 of the License, or
39
+# (at your option) any later version.
40
+#
41
+# This program is distributed in the hope that it will be useful,
42
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
43
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44
+# GNU General Public License for more details.
45
+#
46
+# You should have received a copy of the GNU General Public License
47
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
48
+#
49
+
50
+if [ "$#" -lt 1 ]; then
51
+ echo "Usage: $0 SOURCE_FILE"
52
+ exit 1
53
+fi
54
+
55
+ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../../.." >/dev/null 2>&1 && pwd )"
56
+QEMU_IMG="$ROOT_DIR/qemu-img"
57
+QEMU_IO="$ROOT_DIR/qemu-io"
58
+
59
+size=1G
60
+src="$1"
61
+
62
+# test-case plain
63
+
64
+(
65
+$QEMU_IMG create -f qcow2 "$src" $size
66
+for i in $(seq 16384 -1 0); do
67
+ echo "write $((i * 65536)) 64k"
68
+done | $QEMU_IO "$src"
69
+) > /dev/null
70
+
71
+echo -n "plain: "
72
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
73
+
74
+# test-case forward
75
+
76
+(
77
+$QEMU_IMG create -f qcow2 "$src" $size
78
+for i in $(seq 0 2 16384); do
79
+ echo "write $((i * 65536)) 64k"
80
+done | $QEMU_IO "$src"
81
+for i in $(seq 1 2 16384); do
82
+ echo "write $((i * 65536)) 64k"
83
+done | $QEMU_IO "$src"
84
+) > /dev/null
85
+
86
+echo -n "forward: "
87
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
88
+
89
+# test-case prealloc
90
+
91
+$QEMU_IMG create -f qcow2 -o preallocation=metadata "$src" $size > /dev/null
92
+
93
+echo -n "prealloc: "
94
+/usr/bin/time -f %e $QEMU_IMG convert -n "$src" null-co://
95
--
96
2.20.1
97
98
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This patch adds a test where we cancel a throttled mirror job and
4
immediately close the VM before it can be cancelled. Doing so will
5
invoke bdrv_drain_all() while the mirror job tries to drain the
6
throttled node. When bdrv_drain_all_end() tries to lift its drain on
7
the throttle node, the job will exit and replace the current root node
8
of the BB drive0 (which is the job's filter node) by the throttle node.
9
Before the previous patch, this replacement did not increase drive0's
10
quiesce_counter by a sufficient amount, so when
11
bdrv_parent_drained_end() (invoked by bdrv_do_drained_end(), invoked by
12
bdrv_drain_all_end()) tried to end the drain on all of the throttle
13
node's parents, it decreased drive0's quiesce_counter below 0 -- which
14
fails an assertion.
15
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
tests/qemu-iotests/255 | 52 ++++++++++++++++++++++++++++++++++++++
20
tests/qemu-iotests/255.out | 24 ++++++++++++++++++
21
2 files changed, 76 insertions(+)
22
23
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
24
index XXXXXXX..XXXXXXX 100755
25
--- a/tests/qemu-iotests/255
26
+++ b/tests/qemu-iotests/255
27
@@ -XXX,XX +XXX,XX @@ def blockdev_create(vm, options):
28
vm.run_job('job0')
29
iotests.log("")
30
31
+iotests.log('Finishing a commit job with background reads')
32
+iotests.log('============================================')
33
+iotests.log('')
34
+
35
with iotests.FilePath('t.qcow2') as disk_path, \
36
iotests.FilePath('t.qcow2.mid') as mid_path, \
37
iotests.FilePath('t.qcow2.base') as base_path, \
38
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.qcow2') as disk_path, \
39
auto_dismiss=True)
40
41
vm.shutdown()
42
+
43
+iotests.log('')
44
+iotests.log('Closing the VM while a job is being cancelled')
45
+iotests.log('=============================================')
46
+iotests.log('')
47
+
48
+with iotests.FilePath('src.qcow2') as src_path, \
49
+ iotests.FilePath('dst.qcow2') as dst_path, \
50
+ iotests.VM() as vm:
51
+
52
+ iotests.log('=== Create images and start VM ===')
53
+ iotests.log('')
54
+
55
+ size = 128 * 1024 * 1024
56
+ size_str = str(size)
57
+
58
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, src_path, size_str)
59
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, dst_path, size_str)
60
+
61
+ iotests.log(iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 1M',
62
+ src_path),
63
+ filters=[iotests.filter_test_dir, iotests.filter_qemu_io])
64
+
65
+ vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
66
+
67
+ vm.add_blockdev('file,node-name=src-file,filename=%s' % (src_path))
68
+ vm.add_blockdev('%s,node-name=src,file=src-file' % (iotests.imgfmt))
69
+
70
+ vm.add_blockdev('file,node-name=dst-file,filename=%s' % (dst_path))
71
+ vm.add_blockdev('%s,node-name=dst,file=dst-file' % (iotests.imgfmt))
72
+
73
+ vm.add_blockdev('throttle,node-name=src-throttled,' +
74
+ 'throttle-group=throttle0,file=src')
75
+
76
+ vm.add_device('virtio-blk,drive=src-throttled')
77
+
78
+ vm.launch()
79
+
80
+ iotests.log('=== Start a mirror job ===')
81
+ iotests.log('')
82
+
83
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='src-throttled',
84
+ target='dst', sync='full')
85
+
86
+ vm.qmp_log('block-job-cancel', device='job0')
87
+ vm.qmp_log('quit')
88
+
89
+ vm.shutdown()
90
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tests/qemu-iotests/255.out
93
+++ b/tests/qemu-iotests/255.out
94
@@ -XXX,XX +XXX,XX @@
95
+Finishing a commit job with background reads
96
+============================================
97
+
98
=== Create backing chain and start VM ===
99
100
Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
101
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 l
102
{"return": {}}
103
{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
104
{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
105
+
106
+Closing the VM while a job is being cancelled
107
+=============================================
108
+
109
+=== Create images and start VM ===
110
+
111
+Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
112
+
113
+Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
114
+
115
+wrote 1048576/1048576 bytes at offset 0
116
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
117
+
118
+=== Start a mirror job ===
119
+
120
+{"execute": "blockdev-mirror", "arguments": {"device": "src-throttled", "job-id": "job0", "sync": "full", "target": "dst"}}
121
+{"return": {}}
122
+{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
123
+{"return": {}}
124
+{"execute": "quit", "arguments": {}}
125
+{"return": {}}
126
--
127
2.20.1
128
129
diff view generated by jsdifflib
1
So far, we only made sure that updating the AioContext of a node
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
2
affected the whole subtree. However, if a node is newly attached to a
2
image is possibly preallocated and then the zero flag is added to all
3
new parent, we also need to make sure that both the subtree of the node
3
clusters. This means that a copy-on-write operation may be needed when
4
and the parent are in the same AioContext. This tries to move the new
4
writing to these clusters, despite having used preallocation, negating
5
child node to the parent AioContext and returns an error if this isn't
5
one of the major benefits of preallocation.
6
possible.
7
6
8
BlockBackends now actually apply their AioContext to their root node.
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
8
and if the protocol driver can ensure that the new area reads as zeros,
9
we can skip setting the zero flag in the qcow2 layer.
10
11
Unfortunately, the same approach doesn't work for metadata
12
preallocation, so we'll still set the zero flag there.
9
13
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
19
---
12
include/block/block_int.h | 1 +
20
block/qcow2.c | 22 +++++++++++++++++++---
13
block.c | 35 ++++++++++++++++++++++++++++++++++-
21
tests/qemu-iotests/274.out | 4 ++--
14
block/block-backend.c | 9 ++++-----
22
2 files changed, 21 insertions(+), 5 deletions(-)
15
blockjob.c | 10 ++++++++--
16
tests/test-bdrv-drain.c | 6 ++++--
17
5 files changed, 51 insertions(+), 10 deletions(-)
18
23
19
diff --git a/include/block/block_int.h b/include/block/block_int.h
24
diff --git a/block/qcow2.c b/block/qcow2.c
20
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block_int.h
26
--- a/block/qcow2.c
22
+++ b/include/block/block_int.h
27
+++ b/block/qcow2.c
23
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add_node(Monitor *mon, const char *optstr);
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
24
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
29
/* Allocate the data area */
25
const char *child_name,
30
new_file_size = allocation_start +
26
const BdrvChildRole *child_role,
31
nb_new_data_clusters * s->cluster_size;
27
+ AioContext *ctx,
32
- /* Image file grows, so @exact does not matter */
28
uint64_t perm, uint64_t shared_perm,
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
29
void *opaque, Error **errp);
34
- errp);
30
void bdrv_root_unref_child(BdrvChild *child);
35
+ /*
31
diff --git a/block.c b/block.c
36
+ * Image file grows, so @exact does not matter.
32
index XXXXXXX..XXXXXXX 100644
37
+ *
33
--- a/block.c
38
+ * If we need to zero out the new area, try first whether the protocol
34
+++ b/block.c
39
+ * driver can already take care of this.
35
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
40
+ */
36
*
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
37
* On failure NULL is returned, errp is set and the reference to
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
38
* child_bs is also dropped.
43
+ BDRV_REQ_ZERO_WRITE, NULL);
39
+ *
44
+ if (ret >= 0) {
40
+ * The caller must hold the AioContext lock @child_bs, but not that of @ctx
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
41
+ * (unless @child_bs is already in @ctx).
42
*/
43
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
44
const char *child_name,
45
const BdrvChildRole *child_role,
46
+ AioContext *ctx,
47
uint64_t perm, uint64_t shared_perm,
48
void *opaque, Error **errp)
49
{
50
BdrvChild *child;
51
+ Error *local_err = NULL;
52
int ret;
53
54
ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
55
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
56
.opaque = opaque,
57
};
58
59
+ /* If the AioContexts don't match, first try to move the subtree of
60
+ * child_bs into the AioContext of the new parent. If this doesn't work,
61
+ * try moving the parent into the AioContext of child_bs instead. */
62
+ if (bdrv_get_aio_context(child_bs) != ctx) {
63
+ ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
64
+ if (ret < 0 && child_role->can_set_aio_ctx) {
65
+ GSList *ignore = g_slist_prepend(NULL, child);;
66
+ ctx = bdrv_get_aio_context(child_bs);
67
+ if (child_role->can_set_aio_ctx(child, ctx, &ignore, NULL)) {
68
+ error_free(local_err);
69
+ ret = 0;
70
+ g_slist_free(ignore);
71
+ ignore = g_slist_prepend(NULL, child);;
72
+ child_role->set_aio_ctx(child, ctx, &ignore);
73
+ }
46
+ }
74
+ g_slist_free(ignore);
47
+ } else {
48
+ ret = -1;
75
+ }
49
+ }
76
+ if (ret < 0) {
50
+ if (ret < 0) {
77
+ error_propagate(errp, local_err);
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
78
+ g_free(child);
52
+ errp);
79
+ bdrv_abort_perm_update(child_bs);
80
+ return NULL;
81
+ }
53
+ }
82
+ }
54
if (ret < 0) {
83
+
55
error_prepend(errp, "Failed to resize underlying file: ");
84
/* This performs the matching bdrv_set_perm() for the above check. */
56
qcow2_free_clusters(bs, allocation_start,
85
bdrv_replace_child(child, child_bs);
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
86
87
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
88
*
89
* On failure NULL is returned, errp is set and the reference to
90
* child_bs is also dropped.
91
+ *
92
+ * If @parent_bs and @child_bs are in different AioContexts, the caller must
93
+ * hold the AioContext lock for @child_bs, but not for @parent_bs.
94
*/
95
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
96
BlockDriverState *child_bs,
97
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
98
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
99
100
assert(parent_bs->drv);
101
- assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs));
102
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
103
perm, shared_perm, &perm, &shared_perm);
104
105
child = bdrv_root_attach_child(child_bs, child_name, child_role,
106
+ bdrv_get_aio_context(parent_bs),
107
perm, shared_perm, parent_bs, errp);
108
if (child == NULL) {
109
return NULL;
110
diff --git a/block/block-backend.c b/block/block-backend.c
111
index XXXXXXX..XXXXXXX 100644
58
index XXXXXXX..XXXXXXX 100644
112
--- a/block/block-backend.c
59
--- a/tests/qemu-iotests/274.out
113
+++ b/block/block-backend.c
60
+++ b/tests/qemu-iotests/274.out
114
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
115
return NULL;
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
116
}
63
117
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
118
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
119
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
120
perm, BLK_PERM_ALL, blk, errp);
67
121
if (!blk->root) {
68
=== preallocation=full ===
122
blk_unref(blk);
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
123
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
124
{
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
125
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
72
126
bdrv_ref(bs);
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
127
- blk->root = bdrv_root_attach_child(bs, "root", &child_root,
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
128
+ blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
129
blk->perm, blk->shared_perm, blk, errp);
76
130
if (blk->root == NULL) {
77
=== preallocation=off ===
131
return -EPERM;
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
132
@@ -XXX,XX +XXX,XX @@ AioContext *blk_get_aio_context(BlockBackend *blk)
133
{
134
BlockDriverState *bs = blk_bs(blk);
135
136
- /* FIXME The AioContext of bs and blk can be inconsistent. For the moment,
137
- * we prefer the one of bs for compatibility. */
138
if (bs) {
139
- return bdrv_get_aio_context(blk_bs(blk));
140
+ AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
141
+ assert(ctx == blk->ctx);
142
}
143
144
return blk->ctx;
145
diff --git a/blockjob.c b/blockjob.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/blockjob.c
148
+++ b/blockjob.c
149
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
150
BdrvChild *c;
151
152
bdrv_ref(bs);
153
- c = bdrv_root_attach_child(bs, name, &child_job, perm, shared_perm,
154
- job, errp);
155
+ if (job->job.aio_context != qemu_get_aio_context()) {
156
+ aio_context_release(job->job.aio_context);
157
+ }
158
+ c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context,
159
+ perm, shared_perm, job, errp);
160
+ if (job->job.aio_context != qemu_get_aio_context()) {
161
+ aio_context_acquire(job->job.aio_context);
162
+ }
163
if (c == NULL) {
164
return -EPERM;
165
}
166
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/tests/test-bdrv-drain.c
169
+++ b/tests/test-bdrv-drain.c
170
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
171
&error_abort);
172
blk_target = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
173
blk_insert_bs(blk_target, target, &error_abort);
174
+ blk_set_allow_aio_context_change(blk_target, true);
175
176
aio_context_acquire(ctx);
177
tjob = block_job_create("job0", &test_job_driver, NULL, src,
178
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
179
g_assert_false(job->job.paused);
180
g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
181
182
- do_drain_begin(drain_type, target);
183
+ do_drain_begin_unlocked(drain_type, target);
184
185
if (drain_type == BDRV_DRAIN_ALL) {
186
/* bdrv_drain_all() drains both src and target */
187
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
188
g_assert_true(job->job.paused);
189
g_assert_false(job->job.busy); /* The job is paused */
190
191
- do_drain_end(drain_type, target);
192
+ do_drain_end_unlocked(drain_type, target);
193
194
if (use_iothread) {
195
/* paused is reset in the I/O thread, wait for it */
196
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
197
198
if (use_iothread) {
199
blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
200
+ blk_set_aio_context(blk_target, qemu_get_aio_context(), &error_abort);
201
}
202
aio_context_release(ctx);
203
204
--
79
--
205
2.20.1
80
2.25.3
206
81
207
82
diff view generated by jsdifflib
1
From: Kenneth Heitke <kenneth.heitke@intel.com>
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
2
3
Signed-off-by: Kenneth Heitke <kenneth.heitke@intel.com>
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
4
Reviewed-by: Klaus Birkelund Jensen <klaus.jensen@cnexlabs.com>
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
7
persistent across system reboot.
8
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
15
---
7
hw/block/nvme.h | 2 +
16
hw/block/nvme.h | 2 +
8
include/block/nvme.h | 2 +
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
9
hw/block/nvme.c | 106 +++++++++++++++++++++++++++++++++++++++++-
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
10
hw/block/trace-events | 2 +
19
hw/block/Makefile.objs | 2 +-
11
4 files changed, 110 insertions(+), 2 deletions(-)
20
hw/block/trace-events | 4 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
12
22
13
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/block/nvme.h
25
--- a/hw/block/nvme.h
16
+++ b/hw/block/nvme.h
26
+++ b/hw/block/nvme.h
17
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
18
uint32_t cmbloc;
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
19
uint8_t *cmbuf;
20
uint64_t irq_status;
21
+ uint64_t host_timestamp; /* Timestamp sent by the host */
22
+ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
23
29
24
char *serial;
30
char *serial;
31
+ HostMemoryBackend *pmrdev;
32
+
25
NvmeNamespace *namespaces;
33
NvmeNamespace *namespaces;
34
NvmeSQueue **sq;
35
NvmeCQueue **cq;
26
diff --git a/include/block/nvme.h b/include/block/nvme.h
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
27
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/nvme.h
38
--- a/include/block/nvme.h
29
+++ b/include/block/nvme.h
39
+++ b/include/block/nvme.h
30
@@ -XXX,XX +XXX,XX @@ enum NvmeIdCtrlOncs {
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
31
NVME_ONCS_WRITE_ZEROS = 1 << 3,
41
uint64_t acq;
32
NVME_ONCS_FEATURES = 1 << 4,
42
uint32_t cmbloc;
33
NVME_ONCS_RESRVATIONS = 1 << 5,
43
uint32_t cmbsz;
34
+ NVME_ONCS_TIMESTAMP = 1 << 6,
44
+ uint8_t padding[3520]; /* not used by QEMU */
45
+ uint32_t pmrcap;
46
+ uint32_t pmrctl;
47
+ uint32_t pmrsts;
48
+ uint32_t pmrebs;
49
+ uint32_t pmrswtp;
50
+ uint32_t pmrmsc;
51
} NvmeBar;
52
53
enum NvmeCapShift {
54
@@ -XXX,XX +XXX,XX @@ enum NvmeCapShift {
55
CAP_CSS_SHIFT = 37,
56
CAP_MPSMIN_SHIFT = 48,
57
CAP_MPSMAX_SHIFT = 52,
58
+ CAP_PMR_SHIFT = 56,
35
};
59
};
36
60
37
#define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
61
enum NvmeCapMask {
38
@@ -XXX,XX +XXX,XX @@ enum NvmeFeatureIds {
62
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
39
NVME_INTERRUPT_VECTOR_CONF = 0x9,
63
CAP_CSS_MASK = 0xff,
40
NVME_WRITE_ATOMICITY = 0xa,
64
CAP_MPSMIN_MASK = 0xf,
41
NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
65
CAP_MPSMAX_MASK = 0xf,
42
+ NVME_TIMESTAMP = 0xe,
66
+ CAP_PMR_MASK = 0x1,
43
NVME_SOFTWARE_PROGRESS_MARKER = 0x80
44
};
67
};
45
68
69
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
70
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
71
<< CAP_MPSMIN_SHIFT)
72
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
73
<< CAP_MPSMAX_SHIFT)
74
+#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
75
+ << CAP_PMR_SHIFT)
76
77
enum NvmeCcShift {
78
CC_EN_SHIFT = 0,
79
@@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask {
80
#define NVME_CMBSZ_GETSIZE(cmbsz) \
81
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
82
83
+enum NvmePmrcapShift {
84
+ PMRCAP_RDS_SHIFT = 3,
85
+ PMRCAP_WDS_SHIFT = 4,
86
+ PMRCAP_BIR_SHIFT = 5,
87
+ PMRCAP_PMRTU_SHIFT = 8,
88
+ PMRCAP_PMRWBM_SHIFT = 10,
89
+ PMRCAP_PMRTO_SHIFT = 16,
90
+ PMRCAP_CMSS_SHIFT = 24,
91
+};
92
+
93
+enum NvmePmrcapMask {
94
+ PMRCAP_RDS_MASK = 0x1,
95
+ PMRCAP_WDS_MASK = 0x1,
96
+ PMRCAP_BIR_MASK = 0x7,
97
+ PMRCAP_PMRTU_MASK = 0x3,
98
+ PMRCAP_PMRWBM_MASK = 0xf,
99
+ PMRCAP_PMRTO_MASK = 0xff,
100
+ PMRCAP_CMSS_MASK = 0x1,
101
+};
102
+
103
+#define NVME_PMRCAP_RDS(pmrcap) \
104
+ ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
105
+#define NVME_PMRCAP_WDS(pmrcap) \
106
+ ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
107
+#define NVME_PMRCAP_BIR(pmrcap) \
108
+ ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
109
+#define NVME_PMRCAP_PMRTU(pmrcap) \
110
+ ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
111
+#define NVME_PMRCAP_PMRWBM(pmrcap) \
112
+ ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
113
+#define NVME_PMRCAP_PMRTO(pmrcap) \
114
+ ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
115
+#define NVME_PMRCAP_CMSS(pmrcap) \
116
+ ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
117
+
118
+#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
119
+ (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
120
+#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
121
+ (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
122
+#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
123
+ (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
124
+#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
125
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
126
+#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
127
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
128
+#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
129
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
130
+#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
131
+ (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
132
+
133
+enum NvmePmrctlShift {
134
+ PMRCTL_EN_SHIFT = 0,
135
+};
136
+
137
+enum NvmePmrctlMask {
138
+ PMRCTL_EN_MASK = 0x1,
139
+};
140
+
141
+#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
142
+
143
+#define NVME_PMRCTL_SET_EN(pmrctl, val) \
144
+ (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
145
+
146
+enum NvmePmrstsShift {
147
+ PMRSTS_ERR_SHIFT = 0,
148
+ PMRSTS_NRDY_SHIFT = 8,
149
+ PMRSTS_HSTS_SHIFT = 9,
150
+ PMRSTS_CBAI_SHIFT = 12,
151
+};
152
+
153
+enum NvmePmrstsMask {
154
+ PMRSTS_ERR_MASK = 0xff,
155
+ PMRSTS_NRDY_MASK = 0x1,
156
+ PMRSTS_HSTS_MASK = 0x7,
157
+ PMRSTS_CBAI_MASK = 0x1,
158
+};
159
+
160
+#define NVME_PMRSTS_ERR(pmrsts) \
161
+ ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
162
+#define NVME_PMRSTS_NRDY(pmrsts) \
163
+ ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
164
+#define NVME_PMRSTS_HSTS(pmrsts) \
165
+ ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
166
+#define NVME_PMRSTS_CBAI(pmrsts) \
167
+ ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
168
+
169
+#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
170
+ (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
171
+#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
172
+ (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
173
+#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
174
+ (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
175
+#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
176
+ (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
177
+
178
+enum NvmePmrebsShift {
179
+ PMREBS_PMRSZU_SHIFT = 0,
180
+ PMREBS_RBB_SHIFT = 4,
181
+ PMREBS_PMRWBZ_SHIFT = 8,
182
+};
183
+
184
+enum NvmePmrebsMask {
185
+ PMREBS_PMRSZU_MASK = 0xf,
186
+ PMREBS_RBB_MASK = 0x1,
187
+ PMREBS_PMRWBZ_MASK = 0xffffff,
188
+};
189
+
190
+#define NVME_PMREBS_PMRSZU(pmrebs) \
191
+ ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
192
+#define NVME_PMREBS_RBB(pmrebs) \
193
+ ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
194
+#define NVME_PMREBS_PMRWBZ(pmrebs) \
195
+ ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
196
+
197
+#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
198
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
199
+#define NVME_PMREBS_SET_RBB(pmrebs, val) \
200
+ (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
201
+#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
202
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
203
+
204
+enum NvmePmrswtpShift {
205
+ PMRSWTP_PMRSWTU_SHIFT = 0,
206
+ PMRSWTP_PMRSWTV_SHIFT = 8,
207
+};
208
+
209
+enum NvmePmrswtpMask {
210
+ PMRSWTP_PMRSWTU_MASK = 0xf,
211
+ PMRSWTP_PMRSWTV_MASK = 0xffffff,
212
+};
213
+
214
+#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
215
+ ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
216
+#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
217
+ ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
218
+
219
+#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
220
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
221
+#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
222
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
223
+
224
+enum NvmePmrmscShift {
225
+ PMRMSC_CMSE_SHIFT = 1,
226
+ PMRMSC_CBA_SHIFT = 12,
227
+};
228
+
229
+enum NvmePmrmscMask {
230
+ PMRMSC_CMSE_MASK = 0x1,
231
+ PMRMSC_CBA_MASK = 0xfffffffffffff,
232
+};
233
+
234
+#define NVME_PMRMSC_CMSE(pmrmsc) \
235
+ ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
236
+#define NVME_PMRMSC_CBA(pmrmsc) \
237
+ ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
238
+
239
+#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
240
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
241
+#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
242
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
243
+
244
typedef struct NvmeCmd {
245
uint8_t opcode;
246
uint8_t fuse;
46
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
247
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
47
index XXXXXXX..XXXXXXX 100644
248
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/block/nvme.c
249
--- a/hw/block/nvme.c
49
+++ b/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
50
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
251
@@ -XXX,XX +XXX,XX @@
51
return NVME_INVALID_FIELD | NVME_DNR;
252
* -drive file=<file>,if=none,id=<drive_id>
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
255
+ * [pmrdev=<mem_backend_file_id>,] \
256
* num_queues=<N[optional]>
257
*
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
259
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
260
+ *
261
+ * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
262
+ * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
263
+ * both provided.
264
+ * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
265
+ * For example:
266
+ * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
267
+ * size=<size> .... -device nvme,...,pmrdev=<mem_id>
268
*/
269
270
#include "qemu/osdep.h"
271
@@ -XXX,XX +XXX,XX @@
272
#include "sysemu/sysemu.h"
273
#include "qapi/error.h"
274
#include "qapi/visitor.h"
275
+#include "sysemu/hostmem.h"
276
#include "sysemu/block-backend.h"
277
+#include "exec/ram_addr.h"
278
279
#include "qemu/log.h"
280
#include "qemu/module.h"
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
283
"invalid write to read only CMBSZ, ignored");
284
return;
285
+ case 0xE00: /* PMRCAP */
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
287
+ "invalid write to PMRCAP register, ignored");
288
+ return;
289
+ case 0xE04: /* TODO PMRCTL */
290
+ break;
291
+ case 0xE08: /* PMRSTS */
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
293
+ "invalid write to PMRSTS register, ignored");
294
+ return;
295
+ case 0xE0C: /* PMREBS */
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
297
+ "invalid write to PMREBS register, ignored");
298
+ return;
299
+ case 0xE10: /* PMRSWTP */
300
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
301
+ "invalid write to PMRSWTP register, ignored");
302
+ return;
303
+ case 0xE14: /* TODO PMRMSC */
304
+ break;
305
default:
306
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
307
"invalid MMIO write,"
308
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
309
}
310
311
if (addr < sizeof(n->bar)) {
312
+ /*
313
+ * When PMRWBM bit 1 is set then read from
314
+ * from PMRSTS should ensure prior writes
315
+ * made it to persistent media
316
+ */
317
+ if (addr == 0xE08 &&
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
320
+ 0, n->pmrdev->size);
321
+ }
322
memcpy(&val, ptr + addr, size);
323
} else {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
326
error_setg(errp, "serial property not set");
327
return;
328
}
329
+
330
+ if (!n->cmb_size_mb && n->pmrdev) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
334
+ g_free(path);
335
+ return;
336
+ }
337
+
338
+ if (!is_power_of_2(n->pmrdev->size)) {
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
340
+ return;
341
+ }
342
+
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
344
+ }
345
+
346
blkconf_blocksizes(&n->conf);
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
348
false, errp)) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
408
+ }
409
msix_uninit_exclusive_bar(pci_dev);
52
}
410
}
53
411
54
+static uint16_t nvme_dma_write_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
412
static Property nvme_props[] = {
55
+ uint64_t prp1, uint64_t prp2)
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
56
+{
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
57
+ QEMUSGList qsg;
415
+ HostMemoryBackend *),
58
+ QEMUIOVector iov;
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
59
+ uint16_t status = NVME_SUCCESS;
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
60
+
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
61
+ if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
62
+ return NVME_INVALID_FIELD | NVME_DNR;
420
index XXXXXXX..XXXXXXX 100644
63
+ }
421
--- a/hw/block/Makefile.objs
64
+ if (qsg.nsg > 0) {
422
+++ b/hw/block/Makefile.objs
65
+ if (dma_buf_write(ptr, len, &qsg)) {
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
66
+ status = NVME_INVALID_FIELD | NVME_DNR;
424
common-obj-$(CONFIG_XEN) += xen-block.o
67
+ }
425
common-obj-$(CONFIG_ECC) += ecc.o
68
+ qemu_sglist_destroy(&qsg);
426
common-obj-$(CONFIG_ONENAND) += onenand.o
69
+ } else {
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
70
+ if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
428
common-obj-$(CONFIG_SWIM) += swim.o
71
+ status = NVME_INVALID_FIELD | NVME_DNR;
429
72
+ }
430
common-obj-$(CONFIG_SH4) += tc58128.o
73
+ qemu_iovec_destroy(&iov);
431
74
+ }
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
75
+ return status;
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
76
+}
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
77
+
435
78
static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
436
obj-y += dataplane/
79
uint64_t prp1, uint64_t prp2)
80
{
81
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
82
return ret;
83
}
84
85
-
86
static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
87
{
88
NvmeIdentify *c = (NvmeIdentify *)cmd;
89
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
90
}
91
}
92
93
+static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts)
94
+{
95
+ trace_nvme_setfeat_timestamp(ts);
96
+
97
+ n->host_timestamp = le64_to_cpu(ts);
98
+ n->timestamp_set_qemu_clock_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
99
+}
100
+
101
+static inline uint64_t nvme_get_timestamp(const NvmeCtrl *n)
102
+{
103
+ uint64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
104
+ uint64_t elapsed_time = current_time - n->timestamp_set_qemu_clock_ms;
105
+
106
+ union nvme_timestamp {
107
+ struct {
108
+ uint64_t timestamp:48;
109
+ uint64_t sync:1;
110
+ uint64_t origin:3;
111
+ uint64_t rsvd1:12;
112
+ };
113
+ uint64_t all;
114
+ };
115
+
116
+ union nvme_timestamp ts;
117
+ ts.all = 0;
118
+
119
+ /*
120
+ * If the sum of the Timestamp value set by the host and the elapsed
121
+ * time exceeds 2^48, the value returned should be reduced modulo 2^48.
122
+ */
123
+ ts.timestamp = (n->host_timestamp + elapsed_time) & 0xffffffffffff;
124
+
125
+ /* If the host timestamp is non-zero, set the timestamp origin */
126
+ ts.origin = n->host_timestamp ? 0x01 : 0x00;
127
+
128
+ trace_nvme_getfeat_timestamp(ts.all);
129
+
130
+ return cpu_to_le64(ts.all);
131
+}
132
+
133
+static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
134
+{
135
+ uint64_t prp1 = le64_to_cpu(cmd->prp1);
136
+ uint64_t prp2 = le64_to_cpu(cmd->prp2);
137
+
138
+ uint64_t timestamp = nvme_get_timestamp(n);
139
+
140
+ return nvme_dma_read_prp(n, (uint8_t *)&timestamp,
141
+ sizeof(timestamp), prp1, prp2);
142
+}
143
+
144
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
145
{
146
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
147
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
148
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
149
trace_nvme_getfeat_numq(result);
150
break;
151
+ case NVME_TIMESTAMP:
152
+ return nvme_get_feature_timestamp(n, cmd);
153
+ break;
154
default:
155
trace_nvme_err_invalid_getfeat(dw10);
156
return NVME_INVALID_FIELD | NVME_DNR;
157
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
158
return NVME_SUCCESS;
159
}
160
161
+static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
162
+{
163
+ uint16_t ret;
164
+ uint64_t timestamp;
165
+ uint64_t prp1 = le64_to_cpu(cmd->prp1);
166
+ uint64_t prp2 = le64_to_cpu(cmd->prp2);
167
+
168
+ ret = nvme_dma_write_prp(n, (uint8_t *)&timestamp,
169
+ sizeof(timestamp), prp1, prp2);
170
+ if (ret != NVME_SUCCESS) {
171
+ return ret;
172
+ }
173
+
174
+ nvme_set_timestamp(n, timestamp);
175
+
176
+ return NVME_SUCCESS;
177
+}
178
+
179
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
180
{
181
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
182
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
183
req->cqe.result =
184
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
185
break;
186
+
187
+ case NVME_TIMESTAMP:
188
+ return nvme_set_feature_timestamp(n, cmd);
189
+ break;
190
+
191
default:
192
trace_nvme_err_invalid_setfeat(dw10);
193
return NVME_INVALID_FIELD | NVME_DNR;
194
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
195
nvme_init_sq(&n->admin_sq, n, n->bar.asq, 0, 0,
196
NVME_AQA_ASQS(n->bar.aqa) + 1);
197
198
+ nvme_set_timestamp(n, 0ULL);
199
+
200
return 0;
201
}
202
203
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
204
id->sqes = (0x6 << 4) | 0x6;
205
id->cqes = (0x4 << 4) | 0x4;
206
id->nn = cpu_to_le32(n->num_namespaces);
207
- id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS);
208
+ id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP);
209
id->psd[0].mp = cpu_to_le16(0x9c4);
210
id->psd[0].enlat = cpu_to_le32(0x10);
211
id->psd[0].exlat = cpu_to_le32(0x4);
212
diff --git a/hw/block/trace-events b/hw/block/trace-events
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
213
index XXXXXXX..XXXXXXX 100644
438
index XXXXXXX..XXXXXXX 100644
214
--- a/hw/block/trace-events
439
--- a/hw/block/trace-events
215
+++ b/hw/block/trace-events
440
+++ b/hw/block/trace-events
216
@@ -XXX,XX +XXX,XX @@ nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
217
nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
218
nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
219
nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
220
+nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
221
+nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
222
nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
223
nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
224
nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
225
--
452
--
226
2.20.1
453
2.25.3
227
454
228
455
diff view generated by jsdifflib
1
From: Julia Suvorova <jusual@mail.ru>
1
The QMP handler qmp_object_add() and the implementation of --object in
2
qemu-storage-daemon can share most of the code. Currently,
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
2
5
3
Callback-based laio_submit() and laio_cancel() were left after
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
4
rewriting Linux AIO backend to coroutines in hope that they would be
7
new function user_creatable_add_dict() that can get an additional
5
used in other code that could bypass coroutines. They can be safely
8
parameter. The handling of "props" is only required for compatibility
6
removed because they have not been used since that time.
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
7
11
8
Signed-off-by: Julia Suvorova <jusual@mail.ru>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
13
---
12
include/block/raw-aio.h | 3 --
14
include/qom/object_interfaces.h | 12 ++++++++++++
13
block/linux-aio.c | 72 ++++++-----------------------------------
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
14
2 files changed, 10 insertions(+), 65 deletions(-)
16
qom/qom-qmp-cmds.c | 24 +-----------------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
15
18
16
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/raw-aio.h
21
--- a/include/qom/object_interfaces.h
19
+++ b/include/block/raw-aio.h
22
+++ b/include/qom/object_interfaces.h
20
@@ -XXX,XX +XXX,XX @@ LinuxAioState *laio_init(Error **errp);
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
21
void laio_cleanup(LinuxAioState *s);
24
const QDict *qdict,
22
int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
25
Visitor *v, Error **errp);
23
uint64_t offset, QEMUIOVector *qiov, int type);
26
24
-BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
27
+/**
25
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
28
+ * user_creatable_add_dict:
26
- BlockCompletionFunc *cb, void *opaque, int type);
29
+ * @qdict: the object definition
27
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
30
+ * @errp: if an error occurs, a pointer to an area to store the error
28
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
31
+ *
29
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
32
+ * Create an instance of the user creatable object that is defined by
30
diff --git a/block/linux-aio.c b/block/linux-aio.c
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
35
+ * initialize the object properties.
36
+ */
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
38
+
39
/**
40
* user_creatable_add_opts:
41
* @opts: the object definition
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
31
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
32
--- a/block/linux-aio.c
44
--- a/qom/object_interfaces.c
33
+++ b/block/linux-aio.c
45
+++ b/qom/object_interfaces.c
34
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
35
#define MAX_EVENTS 128
47
#include "qapi/qmp/qerror.h"
36
48
#include "qapi/qmp/qjson.h"
37
struct qemu_laiocb {
49
#include "qapi/qmp/qstring.h"
38
- BlockAIOCB common;
50
+#include "qapi/qobject-input-visitor.h"
39
Coroutine *co;
51
#include "qom/object_interfaces.h"
40
LinuxAioState *ctx;
52
#include "qemu/help_option.h"
41
struct iocb iocb;
53
#include "qemu/module.h"
42
@@ -XXX,XX +XXX,XX @@ static inline ssize_t io_event_ret(struct io_event *ev)
54
@@ -XXX,XX +XXX,XX @@ out:
55
return obj;
43
}
56
}
44
57
45
/*
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
46
- * Completes an AIO request (calls the callback and frees the ACB).
59
+{
47
+ * Completes an AIO request.
60
+ Visitor *v;
48
*/
61
+ Object *obj;
49
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
64
+
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
66
+ if (!type) {
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
50
{
86
{
51
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
52
}
88
index XXXXXXX..XXXXXXX 100644
53
89
--- a/qom/qom-qmp-cmds.c
54
laiocb->ret = ret;
90
+++ b/qom/qom-qmp-cmds.c
55
- if (laiocb->co) {
91
@@ -XXX,XX +XXX,XX @@
56
- /* If the coroutine is already entered it must be in ioq_submit() and
92
#include "qapi/qapi-commands-qom.h"
57
- * will notice laio->ret has been filled in when it eventually runs
93
#include "qapi/qmp/qdict.h"
58
- * later. Coroutines cannot be entered recursively so avoid doing
94
#include "qapi/qmp/qerror.h"
59
- * that!
95
-#include "qapi/qobject-input-visitor.h"
60
- */
96
#include "qemu/cutils.h"
61
- if (!qemu_coroutine_entered(laiocb->co)) {
97
#include "qom/object_interfaces.h"
62
- aio_co_wake(laiocb->co);
98
#include "qom/qom-qobject.h"
63
- }
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
64
- } else {
100
{
65
- laiocb->common.cb(laiocb->common.opaque, ret);
101
QObject *props;
66
- qemu_aio_unref(laiocb);
102
QDict *pdict;
67
+
103
- Visitor *v;
68
+ /*
104
- Object *obj;
69
+ * If the coroutine is already entered it must be in ioq_submit() and
105
- g_autofree char *type = NULL;
70
+ * will notice laio->ret has been filled in when it eventually runs
106
- g_autofree char *id = NULL;
71
+ * later. Coroutines cannot be entered recursively so avoid doing
72
+ * that!
73
+ */
74
+ if (!qemu_coroutine_entered(laiocb->co)) {
75
+ aio_co_wake(laiocb->co);
76
}
77
}
78
79
@@ -XXX,XX +XXX,XX @@ static bool qemu_laio_poll_cb(void *opaque)
80
return true;
81
}
82
83
-static void laio_cancel(BlockAIOCB *blockacb)
84
-{
85
- struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
86
- struct io_event event;
87
- int ret;
88
-
107
-
89
- if (laiocb->ret != -EINPROGRESS) {
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
109
- if (!type) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
90
- return;
111
- return;
91
- }
112
- }
92
- ret = io_cancel(laiocb->ctx->ctx, &laiocb->iocb, &event);
113
- qdict_del(qdict, "qom-type");
93
- laiocb->ret = -ECANCELED;
114
-
94
- if (ret != 0) {
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
95
- /* iocb is not cancelled, cb will be called by the event loop later */
116
- if (!id) {
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
96
- return;
118
- return;
97
- }
119
- }
98
-
120
- qdict_del(qdict, "id");
99
- laiocb->common.cb(laiocb->common.opaque, laiocb->ret);
121
100
-}
122
props = qdict_get(qdict, "props");
101
-
123
if (props) {
102
-static const AIOCBInfo laio_aiocb_info = {
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
103
- .aiocb_size = sizeof(struct qemu_laiocb),
125
qobject_unref(pdict);
104
- .cancel_async = laio_cancel,
126
}
105
-};
127
106
-
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
107
static void ioq_init(LaioQueue *io_q)
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
108
{
130
- visit_free(v);
109
QSIMPLEQ_INIT(&io_q->pending);
131
- object_unref(obj);
110
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
132
+ user_creatable_add_dict(qdict, errp);
111
return laiocb.ret;
112
}
133
}
113
134
114
-BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
135
void qmp_object_del(const char *id, Error **errp)
115
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
116
- BlockCompletionFunc *cb, void *opaque, int type)
117
-{
118
- struct qemu_laiocb *laiocb;
119
- off_t offset = sector_num * BDRV_SECTOR_SIZE;
120
- int ret;
121
-
122
- laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque);
123
- laiocb->nbytes = nb_sectors * BDRV_SECTOR_SIZE;
124
- laiocb->ctx = s;
125
- laiocb->ret = -EINPROGRESS;
126
- laiocb->is_read = (type == QEMU_AIO_READ);
127
- laiocb->qiov = qiov;
128
-
129
- ret = laio_do_submit(fd, laiocb, offset, type);
130
- if (ret < 0) {
131
- qemu_aio_unref(laiocb);
132
- return NULL;
133
- }
134
-
135
- return &laiocb->common;
136
-}
137
-
138
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
139
{
140
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
141
--
136
--
142
2.20.1
137
2.25.3
143
138
144
139
diff view generated by jsdifflib
Deleted patch
1
Just make the test cover the AioContext of the filter node as well.
2
1
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
---
6
tests/test-block-iothread.c | 7 ++++++-
7
1 file changed, 6 insertions(+), 1 deletion(-)
8
9
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/test-block-iothread.c
12
+++ b/tests/test-block-iothread.c
13
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
14
IOThread *iothread = iothread_new();
15
AioContext *ctx = iothread_get_aio_context(iothread);
16
AioContext *main_ctx = qemu_get_aio_context();
17
- BlockDriverState *src, *target;
18
+ BlockDriverState *src, *target, *filter;
19
BlockBackend *blk;
20
Job *job;
21
Error *local_err = NULL;
22
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
23
false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
24
&error_abort);
25
job = job_get("job0");
26
+ filter = bdrv_find_node("filter_node");
27
28
/* Change the AioContext of src */
29
bdrv_try_set_aio_context(src, ctx, &error_abort);
30
g_assert(bdrv_get_aio_context(src) == ctx);
31
g_assert(bdrv_get_aio_context(target) == ctx);
32
+ g_assert(bdrv_get_aio_context(filter) == ctx);
33
g_assert(job->aio_context == ctx);
34
35
/* Change the AioContext of target */
36
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
37
aio_context_release(ctx);
38
g_assert(bdrv_get_aio_context(src) == main_ctx);
39
g_assert(bdrv_get_aio_context(target) == main_ctx);
40
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
41
42
/* With a BlockBackend on src, changing target must fail */
43
blk = blk_new(0, BLK_PERM_ALL);
44
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
45
g_assert(blk_get_aio_context(blk) == main_ctx);
46
g_assert(bdrv_get_aio_context(src) == main_ctx);
47
g_assert(bdrv_get_aio_context(target) == main_ctx);
48
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
49
50
/* ...unless we explicitly allow it */
51
aio_context_acquire(ctx);
52
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
53
g_assert(blk_get_aio_context(blk) == ctx);
54
g_assert(bdrv_get_aio_context(src) == ctx);
55
g_assert(bdrv_get_aio_context(target) == ctx);
56
+ g_assert(bdrv_get_aio_context(filter) == ctx);
57
58
job_cancel_sync_all();
59
60
--
61
2.20.1
62
63
diff view generated by jsdifflib
Deleted patch
1
The NBD server uses an AioContext notifier, so it can tolerate that its
2
BlockBackend is switched to a different AioContext. Before we start
3
actually calling bdrv_try_set_aio_context(), which checks for
4
consistency, outside of test cases, we need to make sure that the NBD
5
server actually allows this.
6
1
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
---
10
nbd/server.c | 1 +
11
tests/qemu-iotests/240 | 21 +++++++++++++++++++++
12
tests/qemu-iotests/240.out | 13 +++++++++++++
13
3 files changed, 35 insertions(+)
14
15
diff --git a/nbd/server.c b/nbd/server.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/nbd/server.c
18
+++ b/nbd/server.c
19
@@ -XXX,XX +XXX,XX @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
20
goto fail;
21
}
22
blk_set_enable_write_cache(blk, !writethrough);
23
+ blk_set_allow_aio_context_change(blk, true);
24
25
exp->refcount = 1;
26
QTAILQ_INIT(&exp->clients);
27
diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/240
30
+++ b/tests/qemu-iotests/240
31
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
32
33
status=1    # failure is the default!
34
35
+_cleanup()
36
+{
37
+ rm -f "$TEST_DIR/nbd"
38
+}
39
+trap "_cleanup; exit \$status" 0 1 2 3 15
40
+
41
# get standard environment, filters and checks
42
. ./common.rc
43
. ./common.filter
44
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
45
{ "execute": "quit"}
46
EOF
47
48
+echo
49
+echo === Attach a SCSI disks using the same block device as a NBD server ===
50
+echo
51
+
52
+run_qemu <<EOF
53
+{ "execute": "qmp_capabilities" }
54
+{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}}
55
+{ "execute": "nbd-server-start", "arguments": {"addr":{"type":"unix","data":{"path":"$TEST_DIR/nbd"}}}}
56
+{ "execute": "nbd-server-add", "arguments": {"device":"hd0"}}
57
+{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}}
58
+{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}}
59
+{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}}
60
+{ "execute": "quit"}
61
+EOF
62
+
63
# success, all done
64
echo "*** done"
65
rm -f $seq.full
66
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
67
index XXXXXXX..XXXXXXX 100644
68
--- a/tests/qemu-iotests/240.out
69
+++ b/tests/qemu-iotests/240.out
70
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
71
{"return": {}}
72
{"return": {}}
73
{"return": {}}
74
+
75
+=== Attach a SCSI disks using the same block device as a NBD server ===
76
+
77
+Testing:
78
+QMP_VERSION
79
+{"return": {}}
80
+{"return": {}}
81
+{"return": {}}
82
+{"return": {}}
83
+{"return": {}}
84
+{"return": {}}
85
+{"return": {}}
86
+{"return": {}}
87
*** done
88
--
89
2.20.1
90
91
diff view generated by jsdifflib
Deleted patch
1
Add an Error parameter to blk_set_aio_context() and use
2
bdrv_child_try_set_aio_context() internally to check whether all
3
involved nodes can actually support the AioContext switch.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
include/sysemu/block-backend.h | 3 ++-
8
block/block-backend.c | 26 ++++++++++++++++----------
9
hw/block/dataplane/virtio-blk.c | 12 +++++++++---
10
hw/block/dataplane/xen-block.c | 6 ++++--
11
hw/scsi/virtio-scsi.c | 10 +++++++---
12
tests/test-bdrv-drain.c | 8 ++++----
13
tests/test-block-iothread.c | 22 +++++++++++-----------
14
7 files changed, 53 insertions(+), 34 deletions(-)
15
16
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/sysemu/block-backend.h
19
+++ b/include/sysemu/block-backend.h
20
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason);
21
void blk_op_block_all(BlockBackend *blk, Error *reason);
22
void blk_op_unblock_all(BlockBackend *blk, Error *reason);
23
AioContext *blk_get_aio_context(BlockBackend *blk);
24
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context);
25
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
26
+ Error **errp);
27
void blk_add_aio_context_notifier(BlockBackend *blk,
28
void (*attached_aio_context)(AioContext *new_context, void *opaque),
29
void (*detach_aio_context)(void *opaque), void *opaque);
30
diff --git a/block/block-backend.c b/block/block-backend.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/block-backend.c
33
+++ b/block/block-backend.c
34
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
35
return blk_get_aio_context(blk_acb->blk);
36
}
37
38
-static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
39
- bool update_root_node)
40
+static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
41
+ bool update_root_node, Error **errp)
42
{
43
BlockDriverState *bs = blk_bs(blk);
44
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
45
+ int ret;
46
47
if (bs) {
48
+ if (update_root_node) {
49
+ ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
50
+ errp);
51
+ if (ret < 0) {
52
+ return ret;
53
+ }
54
+ }
55
if (tgm->throttle_state) {
56
bdrv_drained_begin(bs);
57
throttle_group_detach_aio_context(tgm);
58
throttle_group_attach_aio_context(tgm, new_context);
59
bdrv_drained_end(bs);
60
}
61
- if (update_root_node) {
62
- GSList *ignore = g_slist_prepend(NULL, blk->root);
63
- bdrv_set_aio_context_ignore(bs, new_context, &ignore);
64
- g_slist_free(ignore);
65
- }
66
}
67
+
68
+ return 0;
69
}
70
71
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
72
+int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
73
+ Error **errp)
74
{
75
- blk_do_set_aio_context(blk, new_context, true);
76
+ return blk_do_set_aio_context(blk, new_context, true, errp);
77
}
78
79
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
80
@@ -XXX,XX +XXX,XX @@ static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
81
GSList **ignore)
82
{
83
BlockBackend *blk = child->opaque;
84
- blk_do_set_aio_context(blk, ctx, false);
85
+ blk_do_set_aio_context(blk, ctx, false, &error_abort);
86
}
87
88
void blk_add_aio_context_notifier(BlockBackend *blk,
89
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/hw/block/dataplane/virtio-blk.c
92
+++ b/hw/block/dataplane/virtio-blk.c
93
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
94
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
95
unsigned i;
96
unsigned nvqs = s->conf->num_queues;
97
+ Error *local_err = NULL;
98
int r;
99
100
if (vblk->dataplane_started || s->starting) {
101
@@ -XXX,XX +XXX,XX @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
102
vblk->dataplane_started = true;
103
trace_virtio_blk_data_plane_start(s);
104
105
- blk_set_aio_context(s->conf->conf.blk, s->ctx);
106
+ r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err);
107
+ if (r < 0) {
108
+ error_report_err(local_err);
109
+ goto fail_guest_notifiers;
110
+ }
111
112
/* Kick right away to begin processing requests already in vring */
113
for (i = 0; i < nvqs; i++) {
114
@@ -XXX,XX +XXX,XX @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
115
aio_context_acquire(s->ctx);
116
aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s);
117
118
- /* Drain and switch bs back to the QEMU main loop */
119
- blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
120
+ /* Drain and try to switch bs back to the QEMU main loop. If other users
121
+ * keep the BlockBackend in the iothread, that's ok */
122
+ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context(), NULL);
123
124
aio_context_release(s->ctx);
125
126
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/hw/block/dataplane/xen-block.c
129
+++ b/hw/block/dataplane/xen-block.c
130
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
131
}
132
133
aio_context_acquire(dataplane->ctx);
134
- blk_set_aio_context(dataplane->blk, qemu_get_aio_context());
135
+ /* Xen doesn't have multiple users for nodes, so this can't fail */
136
+ blk_set_aio_context(dataplane->blk, qemu_get_aio_context(), &error_abort);
137
aio_context_release(dataplane->ctx);
138
139
xendev = dataplane->xendev;
140
@@ -XXX,XX +XXX,XX @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
141
}
142
143
aio_context_acquire(dataplane->ctx);
144
- blk_set_aio_context(dataplane->blk, dataplane->ctx);
145
+ /* If other users keep the BlockBackend in the iothread, that's ok */
146
+ blk_set_aio_context(dataplane->blk, dataplane->ctx, NULL);
147
aio_context_release(dataplane->ctx);
148
return;
149
150
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
151
index XXXXXXX..XXXXXXX 100644
152
--- a/hw/scsi/virtio-scsi.c
153
+++ b/hw/scsi/virtio-scsi.c
154
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
155
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
156
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
157
SCSIDevice *sd = SCSI_DEVICE(dev);
158
+ int ret;
159
160
if (s->ctx && !s->dataplane_fenced) {
161
AioContext *ctx;
162
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
163
return;
164
}
165
virtio_scsi_acquire(s);
166
- blk_set_aio_context(sd->conf.blk, s->ctx);
167
+ ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
168
virtio_scsi_release(s);
169
-
170
+ if (ret < 0) {
171
+ return;
172
+ }
173
}
174
175
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
176
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
177
178
if (s->ctx) {
179
virtio_scsi_acquire(s);
180
- blk_set_aio_context(sd->conf.blk, qemu_get_aio_context());
181
+ /* If other users keep the BlockBackend in the iothread, that's ok */
182
+ blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL);
183
virtio_scsi_release(s);
184
}
185
186
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/tests/test-bdrv-drain.c
189
+++ b/tests/test-bdrv-drain.c
190
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
191
s = bs->opaque;
192
blk_insert_bs(blk, bs, &error_abort);
193
194
- blk_set_aio_context(blk, ctx_a);
195
+ blk_set_aio_context(blk, ctx_a, &error_abort);
196
aio_context_acquire(ctx_a);
197
198
s->bh_indirection_ctx = ctx_b;
199
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
200
}
201
202
aio_context_acquire(ctx_a);
203
- blk_set_aio_context(blk, qemu_get_aio_context());
204
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
205
aio_context_release(ctx_a);
206
207
bdrv_unref(bs);
208
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
209
if (use_iothread) {
210
iothread = iothread_new();
211
ctx = iothread_get_aio_context(iothread);
212
- blk_set_aio_context(blk_src, ctx);
213
+ blk_set_aio_context(blk_src, ctx, &error_abort);
214
} else {
215
ctx = qemu_get_aio_context();
216
}
217
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
218
g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO));
219
220
if (use_iothread) {
221
- blk_set_aio_context(blk_src, qemu_get_aio_context());
222
+ blk_set_aio_context(blk_src, qemu_get_aio_context(), &error_abort);
223
}
224
aio_context_release(ctx);
225
226
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/tests/test-block-iothread.c
229
+++ b/tests/test-block-iothread.c
230
@@ -XXX,XX +XXX,XX @@ static void test_sync_op(const void *opaque)
231
blk_insert_bs(blk, bs, &error_abort);
232
c = QLIST_FIRST(&bs->parents);
233
234
- blk_set_aio_context(blk, ctx);
235
+ blk_set_aio_context(blk, ctx, &error_abort);
236
aio_context_acquire(ctx);
237
t->fn(c);
238
if (t->blkfn) {
239
t->blkfn(blk);
240
}
241
aio_context_release(ctx);
242
- blk_set_aio_context(blk, qemu_get_aio_context());
243
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
244
245
bdrv_unref(bs);
246
blk_unref(blk);
247
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
248
aio_poll(qemu_get_aio_context(), false);
249
}
250
251
- blk_set_aio_context(blk, ctx);
252
+ blk_set_aio_context(blk, ctx, &error_abort);
253
254
tjob->n = 0;
255
while (tjob->n == 0) {
256
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
257
}
258
259
aio_context_acquire(ctx);
260
- blk_set_aio_context(blk, qemu_get_aio_context());
261
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
262
aio_context_release(ctx);
263
264
tjob->n = 0;
265
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
266
aio_poll(qemu_get_aio_context(), false);
267
}
268
269
- blk_set_aio_context(blk, ctx);
270
+ blk_set_aio_context(blk, ctx, &error_abort);
271
272
tjob->n = 0;
273
while (tjob->n == 0) {
274
@@ -XXX,XX +XXX,XX @@ static void test_attach_blockjob(void)
275
276
aio_context_acquire(ctx);
277
job_complete_sync(&tjob->common.job, &error_abort);
278
- blk_set_aio_context(blk, qemu_get_aio_context());
279
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
280
aio_context_release(ctx);
281
282
bdrv_unref(bs);
283
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
284
bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
285
286
/* Switch the AioContext */
287
- blk_set_aio_context(blk, ctx);
288
+ blk_set_aio_context(blk, ctx, &error_abort);
289
g_assert(blk_get_aio_context(blk) == ctx);
290
g_assert(bdrv_get_aio_context(bs_a) == ctx);
291
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
292
@@ -XXX,XX +XXX,XX @@ static void test_propagate_basic(void)
293
294
/* Switch the AioContext back */
295
ctx = qemu_get_aio_context();
296
- blk_set_aio_context(blk, ctx);
297
+ blk_set_aio_context(blk, ctx, &error_abort);
298
g_assert(blk_get_aio_context(blk) == ctx);
299
g_assert(bdrv_get_aio_context(bs_a) == ctx);
300
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
301
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
302
blk_insert_bs(blk, bs_verify, &error_abort);
303
304
/* Switch the AioContext */
305
- blk_set_aio_context(blk, ctx);
306
+ blk_set_aio_context(blk, ctx, &error_abort);
307
g_assert(blk_get_aio_context(blk) == ctx);
308
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
309
g_assert(bdrv_get_aio_context(bs_a) == ctx);
310
@@ -XXX,XX +XXX,XX @@ static void test_propagate_diamond(void)
311
312
/* Switch the AioContext back */
313
ctx = qemu_get_aio_context();
314
- blk_set_aio_context(blk, ctx);
315
+ blk_set_aio_context(blk, ctx, &error_abort);
316
g_assert(blk_get_aio_context(blk) == ctx);
317
g_assert(bdrv_get_aio_context(bs_verify) == ctx);
318
g_assert(bdrv_get_aio_context(bs_a) == ctx);
319
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
320
job_cancel_sync_all();
321
322
aio_context_acquire(ctx);
323
- blk_set_aio_context(blk, main_ctx);
324
+ blk_set_aio_context(blk, main_ctx, &error_abort);
325
bdrv_try_set_aio_context(target, main_ctx, &error_abort);
326
aio_context_release(ctx);
327
328
--
329
2.20.1
330
331
diff view generated by jsdifflib
Deleted patch
1
Some qdev block devices have support for iothreads and take care of the
2
AioContext they are running in, but most devices don't know about any of
3
this. For the latter category, the qdev drive property must make sure
4
that their BlockBackend is in the main AioContext.
5
1
6
Unfortunately, while the current code just does the same thing for
7
devices that do support iothreads, this is not correct and it would show
8
as soon as we actually try to keep a consistent AioContext assignment
9
across all nodes and users of a block graph subtree: If a node is
10
already in a non-default AioContext because of one of its users,
11
attaching a new device should still be possible if that device can work
12
in the same AioContext. Switching the node back to the main context
13
first and only then into the device AioContext causes failure (because
14
the existing user wouldn't allow the switch to the main context).
15
16
So devices that support iothreads need a different kind of drive
17
property that leaves the node in its current AioContext, but by using
18
this type, the device promises to check later that it can work with this
19
context.
20
21
This patch adds the qdev infrastructure that allows devices to signal
22
that they handle iothreads and qdev should leave the AioContext alone.
23
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
26
include/hw/block/block.h | 7 ++++--
27
include/hw/qdev-properties.h | 3 +++
28
hw/core/qdev-properties-system.c | 43 ++++++++++++++++++++++++++++----
29
3 files changed, 46 insertions(+), 7 deletions(-)
30
31
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/block/block.h
34
+++ b/include/hw/block/block.h
35
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
36
return exp;
37
}
38
39
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
40
- DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
41
+#define DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf) \
42
DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
43
_conf.logical_block_size), \
44
DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
45
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
46
ON_OFF_AUTO_AUTO), \
47
DEFINE_PROP_BOOL("share-rw", _state, _conf.share_rw, false)
48
49
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
50
+ DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
51
+ DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf)
52
+
53
#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \
54
DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \
55
DEFINE_PROP_UINT32("heads", _state, _conf.heads, 0), \
56
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
57
index XXXXXXX..XXXXXXX 100644
58
--- a/include/hw/qdev-properties.h
59
+++ b/include/hw/qdev-properties.h
60
@@ -XXX,XX +XXX,XX @@ extern const PropertyInfo qdev_prop_blockdev_on_error;
61
extern const PropertyInfo qdev_prop_bios_chs_trans;
62
extern const PropertyInfo qdev_prop_fdc_drive_type;
63
extern const PropertyInfo qdev_prop_drive;
64
+extern const PropertyInfo qdev_prop_drive_iothread;
65
extern const PropertyInfo qdev_prop_netdev;
66
extern const PropertyInfo qdev_prop_pci_devfn;
67
extern const PropertyInfo qdev_prop_blocksize;
68
@@ -XXX,XX +XXX,XX @@ extern const PropertyInfo qdev_prop_pcie_link_width;
69
DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
70
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
71
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockBackend *)
72
+#define DEFINE_PROP_DRIVE_IOTHREAD(_n, _s, _f) \
73
+ DEFINE_PROP(_n, _s, _f, qdev_prop_drive_iothread, BlockBackend *)
74
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
75
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
76
#define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \
77
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/hw/core/qdev-properties-system.c
80
+++ b/hw/core/qdev-properties-system.c
81
@@ -XXX,XX +XXX,XX @@ static void set_pointer(Object *obj, Visitor *v, Property *prop,
82
83
/* --- drive --- */
84
85
-static void parse_drive(DeviceState *dev, const char *str, void **ptr,
86
- const char *propname, Error **errp)
87
+static void do_parse_drive(DeviceState *dev, const char *str, void **ptr,
88
+ const char *propname, bool iothread, Error **errp)
89
{
90
BlockBackend *blk;
91
bool blk_created = false;
92
@@ -XXX,XX +XXX,XX @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr,
93
if (!blk) {
94
BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
95
if (bs) {
96
- /* BlockBackends of devices start in the main context and are only
97
- * later moved into another context if the device supports that. */
98
- blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
99
+ /*
100
+ * If the device supports iothreads, it will make sure to move the
101
+ * block node to the right AioContext if necessary (or fail if this
102
+ * isn't possible because of other users). Devices that are not
103
+ * aware of iothreads require their BlockBackends to be in the main
104
+ * AioContext.
105
+ */
106
+ AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
107
+ qemu_get_aio_context();
108
+ blk = blk_new(ctx, 0, BLK_PERM_ALL);
109
blk_created = true;
110
111
ret = blk_insert_bs(blk, bs, errp);
112
@@ -XXX,XX +XXX,XX @@ fail:
113
}
114
}
115
116
+static void parse_drive(DeviceState *dev, const char *str, void **ptr,
117
+ const char *propname, Error **errp)
118
+{
119
+ do_parse_drive(dev, str, ptr, propname, false, errp);
120
+}
121
+
122
+static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr,
123
+ const char *propname, Error **errp)
124
+{
125
+ do_parse_drive(dev, str, ptr, propname, true, errp);
126
+}
127
+
128
static void release_drive(Object *obj, const char *name, void *opaque)
129
{
130
DeviceState *dev = DEVICE(obj);
131
@@ -XXX,XX +XXX,XX @@ static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
132
set_pointer(obj, v, opaque, parse_drive, name, errp);
133
}
134
135
+static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
136
+ void *opaque, Error **errp)
137
+{
138
+ set_pointer(obj, v, opaque, parse_drive_iothread, name, errp);
139
+}
140
+
141
const PropertyInfo qdev_prop_drive = {
142
.name = "str",
143
.description = "Node name or ID of a block device to use as a backend",
144
@@ -XXX,XX +XXX,XX @@ const PropertyInfo qdev_prop_drive = {
145
.release = release_drive,
146
};
147
148
+const PropertyInfo qdev_prop_drive_iothread = {
149
+ .name = "str",
150
+ .description = "Node name or ID of a block device to use as a backend",
151
+ .get = get_drive,
152
+ .set = set_drive_iothread,
153
+ .release = release_drive,
154
+};
155
+
156
/* --- character device --- */
157
158
static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
159
--
160
2.20.1
161
162
diff view generated by jsdifflib
Deleted patch
1
Opening a new parent node for a node that has already been moved into a
2
different AioContext must cause the new parent to move into the same
3
context.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-block-iothread.c | 33 +++++++++++++++++++++++++++++++++
8
1 file changed, 33 insertions(+)
9
10
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-block-iothread.c
13
+++ b/tests/test-block-iothread.c
14
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
15
bdrv_unref(target);
16
}
17
18
+static void test_attach_second_node(void)
19
+{
20
+ IOThread *iothread = iothread_new();
21
+ AioContext *ctx = iothread_get_aio_context(iothread);
22
+ AioContext *main_ctx = qemu_get_aio_context();
23
+ BlockBackend *blk;
24
+ BlockDriverState *bs, *filter;
25
+ QDict *options;
26
+
27
+ blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
28
+ bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
29
+ blk_insert_bs(blk, bs, &error_abort);
30
+
31
+ options = qdict_new();
32
+ qdict_put_str(options, "driver", "raw");
33
+ qdict_put_str(options, "file", "base");
34
+
35
+ filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
36
+ g_assert(blk_get_aio_context(blk) == ctx);
37
+ g_assert(bdrv_get_aio_context(bs) == ctx);
38
+ g_assert(bdrv_get_aio_context(filter) == ctx);
39
+
40
+ blk_set_aio_context(blk, main_ctx, &error_abort);
41
+ g_assert(blk_get_aio_context(blk) == main_ctx);
42
+ g_assert(bdrv_get_aio_context(bs) == main_ctx);
43
+ g_assert(bdrv_get_aio_context(filter) == main_ctx);
44
+
45
+ bdrv_unref(filter);
46
+ bdrv_unref(bs);
47
+ blk_unref(blk);
48
+}
49
+
50
int main(int argc, char **argv)
51
{
52
int i;
53
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
54
}
55
56
g_test_add_func("/attach/blockjob", test_attach_blockjob);
57
+ g_test_add_func("/attach/second_node", test_attach_second_node);
58
g_test_add_func("/propagate/basic", test_propagate_basic);
59
g_test_add_func("/propagate/diamond", test_propagate_diamond);
60
g_test_add_func("/propagate/mirror", test_propagate_mirror);
61
--
62
2.20.1
63
64
diff view generated by jsdifflib
Deleted patch
1
Test that BlockBackends preserve their assigned AioContext even when the
2
root node goes away. Inserting a new root node will move it to the right
3
AioContext.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/test-block-iothread.c | 33 +++++++++++++++++++++++++++++++++
8
1 file changed, 33 insertions(+)
9
10
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-block-iothread.c
13
+++ b/tests/test-block-iothread.c
14
@@ -XXX,XX +XXX,XX @@ static void test_attach_second_node(void)
15
blk_unref(blk);
16
}
17
18
+static void test_attach_preserve_blk_ctx(void)
19
+{
20
+ IOThread *iothread = iothread_new();
21
+ AioContext *ctx = iothread_get_aio_context(iothread);
22
+ BlockBackend *blk;
23
+ BlockDriverState *bs;
24
+
25
+ blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
26
+ bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
27
+ bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
28
+
29
+ /* Add node to BlockBackend that has an iothread context assigned */
30
+ blk_insert_bs(blk, bs, &error_abort);
31
+ g_assert(blk_get_aio_context(blk) == ctx);
32
+ g_assert(bdrv_get_aio_context(bs) == ctx);
33
+
34
+ /* Remove the node again */
35
+ blk_remove_bs(blk);
36
+ /* TODO bs should move back to main context here */
37
+ g_assert(blk_get_aio_context(blk) == ctx);
38
+ g_assert(bdrv_get_aio_context(bs) == ctx);
39
+
40
+ /* Re-attach the node */
41
+ blk_insert_bs(blk, bs, &error_abort);
42
+ g_assert(blk_get_aio_context(blk) == ctx);
43
+ g_assert(bdrv_get_aio_context(bs) == ctx);
44
+
45
+ blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
46
+ bdrv_unref(bs);
47
+ blk_unref(blk);
48
+}
49
+
50
int main(int argc, char **argv)
51
{
52
int i;
53
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
54
55
g_test_add_func("/attach/blockjob", test_attach_blockjob);
56
g_test_add_func("/attach/second_node", test_attach_second_node);
57
+ g_test_add_func("/attach/preserve_blk_ctx", test_attach_preserve_blk_ctx);
58
g_test_add_func("/propagate/basic", test_propagate_basic);
59
g_test_add_func("/propagate/diamond", test_propagate_diamond);
60
g_test_add_func("/propagate/mirror", test_propagate_mirror);
61
--
62
2.20.1
63
64
diff view generated by jsdifflib
Deleted patch
1
Monitor commands can handle errors, so they can easily be converted to
2
using the safer bdrv_try_set_aio_context() function.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
blockdev.c | 44 ++++++++++++++++++++++++++++----------------
7
1 file changed, 28 insertions(+), 16 deletions(-)
8
9
diff --git a/blockdev.c b/blockdev.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/blockdev.c
12
+++ b/blockdev.c
13
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
14
DO_UPCAST(ExternalSnapshotState, common, common);
15
TransactionAction *action = common->action;
16
AioContext *aio_context;
17
+ int ret;
18
19
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
20
* purpose but a different set of parameters */
21
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
22
goto out;
23
}
24
25
- bdrv_set_aio_context(state->new_bs, aio_context);
26
+ ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
27
+ if (ret < 0) {
28
+ goto out;
29
+ }
30
31
/* This removes our old bs and adds the new bs. This is an operation that
32
* can fail, so we need to do it in .prepare; undoing it for abort is
33
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
34
int flags, job_flags = JOB_DEFAULT;
35
int64_t size;
36
bool set_backing_hd = false;
37
+ int ret;
38
39
if (!backup->has_speed) {
40
backup->speed = 0;
41
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
42
goto out;
43
}
44
45
- bdrv_set_aio_context(target_bs, aio_context);
46
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
47
+ if (ret < 0) {
48
+ bdrv_unref(target_bs);
49
+ goto out;
50
+ }
51
52
if (set_backing_hd) {
53
bdrv_set_backing_hd(target_bs, source, &local_err);
54
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
55
AioContext *aio_context;
56
BlockJob *job = NULL;
57
int job_flags = JOB_DEFAULT;
58
+ int ret;
59
60
if (!backup->has_speed) {
61
backup->speed = 0;
62
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
63
goto out;
64
}
65
66
- if (bdrv_get_aio_context(target_bs) != aio_context) {
67
- if (!bdrv_has_blk(target_bs)) {
68
- /* The target BDS is not attached, we can safely move it to another
69
- * AioContext. */
70
- bdrv_set_aio_context(target_bs, aio_context);
71
- } else {
72
- error_setg(errp, "Target is attached to a different thread from "
73
- "source.");
74
- goto out;
75
- }
76
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
77
+ if (ret < 0) {
78
+ goto out;
79
}
80
81
if (backup->has_bitmap) {
82
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
83
int flags;
84
int64_t size;
85
const char *format = arg->format;
86
+ int ret;
87
88
bs = qmp_get_root_bs(arg->device, errp);
89
if (!bs) {
90
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
91
goto out;
92
}
93
94
- bdrv_set_aio_context(target_bs, aio_context);
95
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
96
+ if (ret < 0) {
97
+ bdrv_unref(target_bs);
98
+ goto out;
99
+ }
100
101
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
102
arg->has_replaces, arg->replaces, arg->sync,
103
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
104
AioContext *aio_context;
105
BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
106
Error *local_err = NULL;
107
+ int ret;
108
109
bs = qmp_get_root_bs(device, errp);
110
if (!bs) {
111
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
112
aio_context = bdrv_get_aio_context(bs);
113
aio_context_acquire(aio_context);
114
115
- bdrv_set_aio_context(target_bs, aio_context);
116
+ ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
117
+ if (ret < 0) {
118
+ goto out;
119
+ }
120
121
blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
122
has_replaces, replaces, sync, backing_mode,
123
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
124
has_auto_dismiss, auto_dismiss,
125
&local_err);
126
error_propagate(errp, local_err);
127
-
128
+out:
129
aio_context_release(aio_context);
130
}
131
132
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
133
old_context = bdrv_get_aio_context(bs);
134
aio_context_acquire(old_context);
135
136
- bdrv_set_aio_context(bs, new_context);
137
+ bdrv_try_set_aio_context(bs, new_context, errp);
138
139
aio_context_release(old_context);
140
}
141
--
142
2.20.1
143
144
diff view generated by jsdifflib
Deleted patch
1
The mirror and commit block jobs use bdrv_set_aio_context() to move
2
their filter node into the right AioContext before hooking it up in the
3
graph. Similarly, bdrv_open_backing_file() explicitly moves the backing
4
file node into the right AioContext first.
5
1
6
This isn't necessary any more, they get automatically moved into the
7
right context now when attaching them.
8
9
However, in the case of bdrv_open_backing_file() with a node reference,
10
it's actually not only unnecessary, but even wrong: The unchecked
11
bdrv_set_aio_context() changes the AioContext of the child node even if
12
other parents require it to retain the old context. So this is not only
13
a simplification, but a bug fix, too.
14
15
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1684342
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
block.c | 1 -
19
block/commit.c | 2 --
20
block/mirror.c | 1 -
21
3 files changed, 4 deletions(-)
22
23
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
26
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
28
ret = -EINVAL;
29
goto free_exit;
30
}
31
- bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
32
33
if (implicit_backing) {
34
bdrv_refresh_filename(backing_hd);
35
diff --git a/block/commit.c b/block/commit.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/commit.c
38
+++ b/block/commit.c
39
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
40
commit_top_bs->implicit = true;
41
}
42
commit_top_bs->total_sectors = top->total_sectors;
43
- bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
44
45
bdrv_append(commit_top_bs, top, &local_err);
46
if (local_err) {
47
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
48
error_report_err(local_err);
49
goto ro_cleanup;
50
}
51
- bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(backing_file_bs));
52
53
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
54
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
55
diff --git a/block/mirror.c b/block/mirror.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/mirror.c
58
+++ b/block/mirror.c
59
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
60
BDRV_REQ_NO_FALLBACK;
61
bs_opaque = g_new0(MirrorBDSOpaque, 1);
62
mirror_top_bs->opaque = bs_opaque;
63
- bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
64
65
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
66
* it alive until block_job_create() succeeds even if bs has no parent. */
67
--
68
2.20.1
69
70
diff view generated by jsdifflib
Deleted patch
1
This tests that devices refuse to be attached to a node that has already
2
been moved to a different iothread if they can't be or aren't configured
3
to work in the same iothread.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/qemu-iotests/051 | 24 ++++++++++++++++++++++++
8
tests/qemu-iotests/051.out | 3 +++
9
tests/qemu-iotests/051.pc.out | 27 +++++++++++++++++++++++++++
10
3 files changed, 54 insertions(+)
11
12
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/051
15
+++ b/tests/qemu-iotests/051
16
@@ -XXX,XX +XXX,XX @@ case "$QEMU_DEFAULT_MACHINE" in
17
;;
18
esac
19
20
+echo
21
+echo === Attach to node in non-default iothread ===
22
+echo
23
+
24
+case "$QEMU_DEFAULT_MACHINE" in
25
+ pc)
26
+ iothread="-drive file=$TEST_IMG,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on"
27
+
28
+ # Can't add a device in the main thread while virtio-scsi0 uses the node
29
+ run_qemu $iothread -device ide-hd,drive=disk,share-rw=on
30
+ run_qemu $iothread -device virtio-blk-pci,drive=disk,share-rw=on
31
+ run_qemu $iothread -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on
32
+ run_qemu $iothread -device virtio-scsi,id=virtio-scsi1 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
33
+
34
+ # virtio-blk enables the iothread only when the driver initialises the
35
+ # device, so a second virtio-blk device can't be added even with the
36
+ # same iothread. virtio-scsi allows this.
37
+ run_qemu $iothread -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on
38
+ run_qemu $iothread -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
39
+ ;;
40
+ *)
41
+ ;;
42
+esac
43
+
44
echo
45
echo === Read-only ===
46
echo
47
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
48
index XXXXXXX..XXXXXXX 100644
49
--- a/tests/qemu-iotests/051.out
50
+++ b/tests/qemu-iotests/051.out
51
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
52
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
53
54
55
+=== Attach to node in non-default iothread ===
56
+
57
+
58
=== Read-only ===
59
60
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
61
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
62
index XXXXXXX..XXXXXXX 100644
63
--- a/tests/qemu-iotests/051.pc.out
64
+++ b/tests/qemu-iotests/051.pc.out
65
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
66
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
67
68
69
+=== Attach to node in non-default iothread ===
70
+
71
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device ide-hd,drive=disk,share-rw=on
72
+QEMU X.Y.Z monitor - type 'help' for more information
73
+(qemu) QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend
74
+
75
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,share-rw=on
76
+QEMU X.Y.Z monitor - type 'help' for more information
77
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend
78
+
79
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on
80
+QEMU X.Y.Z monitor - type 'help' for more information
81
+(qemu) QEMU_PROG: -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on: HBA does not support iothreads
82
+
83
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
84
+QEMU X.Y.Z monitor - type 'help' for more information
85
+(qemu) QEMU_PROG: -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on: Cannot change iothread of active block backend
86
+
87
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on
88
+QEMU X.Y.Z monitor - type 'help' for more information
89
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on: Cannot change iothread of active block backend
90
+
91
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
92
+QEMU X.Y.Z monitor - type 'help' for more information
93
+(qemu) quit
94
+
95
+
96
=== Read-only ===
97
98
Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
99
--
100
2.20.1
101
102
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
After processing the option string with the keyval parser, we get a
2
QDict that contains only strings. This QDict must be fed to a keyval
3
visitor which converts the strings into the right data types.
2
4
3
This fixes at least one overflow in qcow2_process_discards, which
5
qmp_object_add(), however, uses the normal QObject input visitor, which
4
passes 64bit region length to bdrv_pdiscard where bytes (or sectors in
6
expects a QDict where all properties already have the QType that matches
5
the past) parameter is int since its introduction in 0b919fae.
7
the data type required by the QOM object type.
6
8
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Change the --object implementation in qemu-storage-daemon so that it
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
11
directly instead and pass it a new keyval boolean that decides which
12
visitor must be used.
13
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
16
---
10
include/block/block.h | 4 ++--
17
include/qom/object_interfaces.h | 6 +++++-
11
block/io.c | 16 ++++++++--------
18
qemu-storage-daemon.c | 4 +---
12
2 files changed, 10 insertions(+), 10 deletions(-)
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
13
22
14
diff --git a/include/block/block.h b/include/block/block.h
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
15
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
25
--- a/include/qom/object_interfaces.h
17
+++ b/include/block/block.h
26
+++ b/include/qom/object_interfaces.h
18
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all(void);
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
19
AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \
28
/**
20
cond); })
29
* user_creatable_add_dict:
21
30
* @qdict: the object definition
22
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes);
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
23
-int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes);
32
+ * assume that all @qdict values are strings); otherwise, use
24
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
33
+ * the normal QObject visitor (i.e. assume all @qdict values
25
+int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
34
+ * have the QType expected by the QOM object type)
26
int bdrv_has_zero_init_1(BlockDriverState *bs);
35
* @errp: if an error occurs, a pointer to an area to store the error
27
int bdrv_has_zero_init(BlockDriverState *bs);
36
*
28
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
37
* Create an instance of the user creatable object that is defined by
29
diff --git a/block/io.c b/block/io.c
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
39
* ID from the key 'id'. The remaining entries in @qdict are used to
40
* initialize the object properties.
41
*/
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
44
45
/**
46
* user_creatable_add_opts:
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
30
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
31
--- a/block/io.c
49
--- a/qemu-storage-daemon.c
32
+++ b/block/io.c
50
+++ b/qemu-storage-daemon.c
33
@@ -XXX,XX +XXX,XX @@ int bdrv_flush(BlockDriverState *bs)
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
34
typedef struct DiscardCo {
52
QemuOpts *opts;
35
BdrvChild *child;
53
const char *type;
36
int64_t offset;
54
QDict *args;
37
- int bytes;
55
- QObject *ret_data = NULL;
38
+ int64_t bytes;
56
39
int ret;
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
40
} DiscardCo;
58
* unconditionall try QemuOpts first. */
41
static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
60
qemu_opts_del(opts);
43
aio_wait_kick();
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
44
}
76
}
45
77
46
-int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
47
+int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
48
+ int64_t bytes)
49
{
80
{
50
BdrvTrackedRequest req;
81
Visitor *v;
51
int max_pdiscard, ret;
82
Object *obj;
52
int head, tail, align;
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
53
BlockDriverState *bs = child->bs;
54
55
- if (!bs || !bs->drv) {
56
+ if (!bs || !bs->drv || !bdrv_is_inserted(bs)) {
57
return -ENOMEDIUM;
58
}
84
}
59
85
qdict_del(qdict, "id");
60
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
86
61
return -EPERM;
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
88
+ if (keyval) {
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
90
+ } else {
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
92
+ }
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
94
visit_free(v);
95
object_unref(obj);
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/qom/qom-qmp-cmds.c
99
+++ b/qom/qom-qmp-cmds.c
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
101
qobject_unref(pdict);
62
}
102
}
63
103
64
- ret = bdrv_check_byte_request(bs, offset, bytes);
104
- user_creatable_add_dict(qdict, errp);
65
- if (ret < 0) {
105
+ user_creatable_add_dict(qdict, false, errp);
66
- return ret;
67
+ if (offset < 0 || bytes < 0 || bytes > INT64_MAX - offset) {
68
+ return -EIO;
69
}
70
71
/* Do nothing if disabled. */
72
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
73
assert(max_pdiscard >= bs->bl.request_alignment);
74
75
while (bytes > 0) {
76
- int num = bytes;
77
+ int64_t num = bytes;
78
79
if (head) {
80
/* Make small requests to get to alignment boundaries. */
81
@@ -XXX,XX +XXX,XX @@ out:
82
return ret;
83
}
106
}
84
107
85
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes)
108
void qmp_object_del(const char *id, Error **errp)
86
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
87
{
88
Coroutine *co;
89
DiscardCo rwco = {
90
--
109
--
91
2.20.1
110
2.25.3
92
111
93
112
diff view generated by jsdifflib