1
The following changes since commit b150cb8f67bf491a49a1cb1c7da151eeacbdbcc9:
1
The following changes since commit 9d662a6b22a0838a85c5432385f35db2488a33a5:
2
2
3
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging (2020-09-29 13:18:54 +0100)
3
Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220305' into staging (2022-03-05 18:03:15 +0000)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/hreitz/qemu.git tags/pull-block-2022-03-07
8
8
9
for you to fetch changes up to bc47831ff28d6f5830c9c8d74220131dc54c5253:
9
for you to fetch changes up to 743da0b401cdc3ee94bc519975e339a3cdbe0ad1:
10
10
11
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved regions (2020-09-30 10:23:05 +0100)
11
iotests/image-fleecing: test push backup with fleecing (2022-03-07 09:33:31 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Block patches for 7.0-rc0:
15
15
- New fleecing backup scheme
16
Note I have switched from GitHub to GitLab.
16
- iotest fixes
17
- Fixes for the curl block driver
18
- Fix for the preallocate block driver
19
- IDE fix for zero-length TRIM requests
17
20
18
----------------------------------------------------------------
21
----------------------------------------------------------------
22
Hanna Reitz (2):
23
ide: Increment BB in-flight counter for TRIM BH
24
iotests: Write test output to TEST_DIR
19
25
20
Eric Auger (2):
26
Peter Maydell (2):
21
util/vfio-helpers: Collect IOVA reserved regions
27
block/curl.c: Set error message string if curl_init_state() fails
22
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved
28
block/curl.c: Check error return from curl_easy_setopt()
23
regions
24
29
25
Philippe Mathieu-Daudé (6):
30
Thomas Huth (2):
26
util/vfio-helpers: Pass page protections to qemu_vfio_pci_map_bar()
31
tests/qemu-iotests/040: Skip TestCommitWithFilters without 'throttle'
27
block/nvme: Map doorbells pages write-only
32
tests/qemu-iotests/testrunner: Quote "case not run" lines in TAP mode
28
block/nvme: Reduce I/O registers scope
29
block/nvme: Drop NVMeRegs structure, directly use NvmeBar
30
block/nvme: Use register definitions from 'block/nvme.h'
31
block/nvme: Replace magic value by SCALE_MS definition
32
33
33
Stefano Garzarella (1):
34
Vladimir Sementsov-Ogievskiy (17):
34
docs: add 'io_uring' option to 'aio' param in qemu-options.hx
35
block: fix preallocate filter: don't do unaligned preallocate requests
36
block/block-copy: move copy_bitmap initialization to
37
block_copy_state_new()
38
block/dirty-bitmap: bdrv_merge_dirty_bitmap(): add return value
39
block/block-copy: block_copy_state_new(): add bitmap parameter
40
block/copy-before-write: add bitmap open parameter
41
block/block-copy: add block_copy_reset()
42
block: intoduce reqlist
43
block/reqlist: reqlist_find_conflict(): use ranges_overlap()
44
block/dirty-bitmap: introduce bdrv_dirty_bitmap_status()
45
block/reqlist: add reqlist_wait_all()
46
block/io: introduce block driver snapshot-access API
47
block: introduce snapshot-access block driver
48
block: copy-before-write: realize snapshot-access API
49
iotests/image-fleecing: add test-case for fleecing format node
50
iotests.py: add qemu_io_pipe_and_status()
51
iotests/image-fleecing: add test case with bitmap
52
iotests/image-fleecing: test push backup with fleecing
35
53
36
Vladimir Sementsov-Ogievskiy (8):
54
qapi/block-core.json | 14 +-
37
block: return error-code from bdrv_invalidate_cache
55
include/block/block-common.h | 3 +-
38
block/io: refactor coroutine wrappers
56
include/block/block-copy.h | 2 +
39
block: declare some coroutine functions in block/coroutines.h
57
include/block/block_int-common.h | 24 ++
40
scripts: add block-coroutine-wrapper.py
58
include/block/block_int-io.h | 9 +
41
block: generate coroutine-wrapper code
59
include/block/dirty-bitmap.h | 4 +-
42
block: drop bdrv_prwv
60
include/block/reqlist.h | 75 ++++++
43
block/io: refactor save/load vmstate
61
include/qemu/hbitmap.h | 12 +
44
include/block/block.h: drop non-ascii quotation mark
62
block/block-copy.c | 150 +++++------
45
63
block/copy-before-write.c | 265 +++++++++++++++++++-
46
block/block-gen.h | 49 ++++
64
block/curl.c | 92 ++++---
47
block/coroutines.h | 65 +++++
65
block/dirty-bitmap.c | 15 +-
48
include/block/block.h | 36 ++-
66
block/io.c | 76 ++++++
49
include/qemu/vfio-helpers.h | 2 +-
67
block/monitor/bitmap-qmp-cmds.c | 5 +-
50
block.c | 97 +------
68
block/preallocate.c | 15 +-
51
block/io.c | 339 ++++---------------------
69
block/reqlist.c | 85 +++++++
52
block/nvme.c | 73 +++---
70
block/snapshot-access.c | 132 ++++++++++
53
tests/test-bdrv-drain.c | 2 +-
71
hw/ide/core.c | 7 +
54
util/vfio-helpers.c | 133 +++++++++-
72
util/hbitmap.c | 33 +++
55
block/meson.build | 8 +
73
MAINTAINERS | 5 +-
56
docs/devel/block-coroutine-wrapper.rst | 54 ++++
74
block/meson.build | 2 +
57
docs/devel/index.rst | 1 +
75
tests/qemu-iotests/040 | 1 +
58
qemu-options.hx | 10 +-
76
tests/qemu-iotests/257.out | 224 +++++++++++++++++
59
scripts/block-coroutine-wrapper.py | 188 ++++++++++++++
77
tests/qemu-iotests/common.rc | 6 +-
60
14 files changed, 629 insertions(+), 428 deletions(-)
78
tests/qemu-iotests/iotests.py | 8 +-
61
create mode 100644 block/block-gen.h
79
tests/qemu-iotests/testenv.py | 5 +-
62
create mode 100644 block/coroutines.h
80
tests/qemu-iotests/testrunner.py | 19 +-
63
create mode 100644 docs/devel/block-coroutine-wrapper.rst
81
tests/qemu-iotests/tests/image-fleecing | 185 +++++++++++---
64
create mode 100644 scripts/block-coroutine-wrapper.py
82
tests/qemu-iotests/tests/image-fleecing.out | 221 +++++++++++++++-
83
29 files changed, 1499 insertions(+), 195 deletions(-)
84
create mode 100644 include/block/reqlist.h
85
create mode 100644 block/reqlist.c
86
create mode 100644 block/snapshot-access.c
65
87
66
--
88
--
67
2.26.2
89
2.34.1
68
diff view generated by jsdifflib
New patch
1
When we still have an AIOCB registered for DMA operations, we try to
2
settle the respective operation by draining the BlockBackend associated
3
with the IDE device.
1
4
5
However, this assumes that every DMA operation is associated with an
6
increment of the BlockBackend’s in-flight counter (e.g. through some
7
ongoing I/O operation), so that draining the BB until its in-flight
8
counter reaches 0 will settle all DMA operations. That is not the case:
9
For TRIM, the guest can issue a zero-length operation that will not
10
result in any I/O operation forwarded to the BlockBackend, and also not
11
increment the in-flight counter in any other way. In such a case,
12
blk_drain() will be a no-op if no other operations are in flight.
13
14
It is clear that if blk_drain() is a no-op, the value of
15
s->bus->dma->aiocb will not change between checking it in the `if`
16
condition and asserting that it is NULL after blk_drain().
17
18
The particular problem is that ide_issue_trim() creates a BH
19
(ide_trim_bh_cb()) to settle the TRIM request: iocb->common.cb() is
20
ide_dma_cb(), which will either create a new request, or find the
21
transfer to be done and call ide_set_inactive(), which clears
22
s->bus->dma->aiocb. Therefore, the blk_drain() must wait for
23
ide_trim_bh_cb() to run, which currently it will not always do.
24
25
To fix this issue, we increment the BlockBackend's in-flight counter
26
when the TRIM operation begins (in ide_issue_trim(), when the
27
ide_trim_bh_cb() BH is created) and decrement it when ide_trim_bh_cb()
28
is done.
29
30
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2029980
31
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
32
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
33
Message-Id: <20220120142259.120189-1-hreitz@redhat.com>
34
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
35
Reviewed-by: John Snow <jsnow@redhat.com>
36
Tested-by: John Snow <jsnow@redhat.com>
37
---
38
hw/ide/core.c | 7 +++++++
39
1 file changed, 7 insertions(+)
40
41
diff --git a/hw/ide/core.c b/hw/ide/core.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/hw/ide/core.c
44
+++ b/hw/ide/core.c
45
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo trim_aiocb_info = {
46
static void ide_trim_bh_cb(void *opaque)
47
{
48
TrimAIOCB *iocb = opaque;
49
+ BlockBackend *blk = iocb->s->blk;
50
51
iocb->common.cb(iocb->common.opaque, iocb->ret);
52
53
qemu_bh_delete(iocb->bh);
54
iocb->bh = NULL;
55
qemu_aio_unref(iocb);
56
+
57
+ /* Paired with an increment in ide_issue_trim() */
58
+ blk_dec_in_flight(blk);
59
}
60
61
static void ide_issue_trim_cb(void *opaque, int ret)
62
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *ide_issue_trim(
63
IDEState *s = opaque;
64
TrimAIOCB *iocb;
65
66
+ /* Paired with a decrement in ide_trim_bh_cb() */
67
+ blk_inc_in_flight(s->blk);
68
+
69
iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
70
iocb->s = s;
71
iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
72
--
73
2.34.1
74
75
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Peter Maydell <peter.maydell@linaro.org>
2
2
3
Use the NVMe register definitions from "block/nvme.h" which
3
In curl_open(), the 'out' label assumes that the state->errmsg string
4
ease a bit reviewing the code while matching the datasheet.
4
has been set (either by curl_easy_perform() or by manually copying a
5
string into it); however if curl_init_state() fails we will jump to
6
that label without setting the string. Add the missing error string
7
setup.
5
8
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
(We can't be specific about the cause of failure: the documentation
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
of curl_easy_init() just says "If this function returns NULL,
8
Message-Id: <20200922083821.578519-6-philmd@redhat.com>
11
something went wrong".)
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-Id: <20220222152341.850419-2-peter.maydell@linaro.org>
15
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
17
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
18
---
10
block/nvme.c | 21 +++++++++++----------
19
block/curl.c | 2 ++
11
1 file changed, 11 insertions(+), 10 deletions(-)
20
1 file changed, 2 insertions(+)
12
21
13
diff --git a/block/nvme.c b/block/nvme.c
22
diff --git a/block/curl.c b/block/curl.c
14
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
24
--- a/block/curl.c
16
+++ b/block/nvme.c
25
+++ b/block/curl.c
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
26
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
18
* Initialization". */
27
// Get file size
19
28
20
cap = le64_to_cpu(regs->cap);
29
if (curl_init_state(s, state) < 0) {
21
- if (!(cap & (1ULL << 37))) {
30
+ pstrcpy(state->errmsg, CURL_ERROR_SIZE,
22
+ if (!NVME_CAP_CSS(cap)) {
31
+ "curl library initialization failed.");
23
error_setg(errp, "Device doesn't support NVMe command set");
24
ret = -EINVAL;
25
goto out;
32
goto out;
26
}
33
}
27
34
28
- s->page_size = MAX(4096, 1 << (12 + ((cap >> 48) & 0xF)));
29
- s->doorbell_scale = (4 << (((cap >> 32) & 0xF))) / sizeof(uint32_t);
30
+ s->page_size = MAX(4096, 1 << NVME_CAP_MPSMIN(cap));
31
+ s->doorbell_scale = (4 << NVME_CAP_DSTRD(cap)) / sizeof(uint32_t);
32
bs->bl.opt_mem_alignment = s->page_size;
33
- timeout_ms = MIN(500 * ((cap >> 24) & 0xFF), 30000);
34
+ timeout_ms = MIN(500 * NVME_CAP_TO(cap), 30000);
35
36
/* Reset device to get a clean state. */
37
regs->cc = cpu_to_le32(le32_to_cpu(regs->cc) & 0xFE);
38
/* Wait for CSTS.RDY = 0. */
39
deadline = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ms * SCALE_MS;
40
- while (le32_to_cpu(regs->csts) & 0x1) {
41
+ while (NVME_CSTS_RDY(le32_to_cpu(regs->csts))) {
42
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
43
error_setg(errp, "Timeout while waiting for device to reset (%"
44
PRId64 " ms)",
45
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
46
}
47
s->nr_queues = 1;
48
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
49
- regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
50
+ regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << AQA_ACQS_SHIFT) |
51
+ (NVME_QUEUE_SIZE << AQA_ASQS_SHIFT));
52
regs->asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
53
regs->acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
54
55
/* After setting up all control registers we can enable device now. */
56
- regs->cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
57
- (ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
58
- 0x1);
59
+ regs->cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << CC_IOCQES_SHIFT) |
60
+ (ctz32(NVME_SQ_ENTRY_BYTES) << CC_IOSQES_SHIFT) |
61
+ CC_EN_MASK);
62
/* Wait for CSTS.RDY = 1. */
63
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
64
deadline = now + timeout_ms * 1000000;
65
- while (!(le32_to_cpu(regs->csts) & 0x1)) {
66
+ while (!NVME_CSTS_RDY(le32_to_cpu(regs->csts))) {
67
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
68
error_setg(errp, "Timeout while waiting for device to start (%"
69
PRId64 " ms)",
70
--
35
--
71
2.26.2
36
2.34.1
72
37
38
diff view generated by jsdifflib
New patch
1
From: Peter Maydell <peter.maydell@linaro.org>
1
2
3
Coverity points out that we aren't checking the return value
4
from curl_easy_setopt() for any of the calls to it we make
5
in block/curl.c.
6
7
Some of these options are documented as always succeeding (e.g.
8
CURLOPT_VERBOSE) but others have documented failure cases (e.g.
9
CURLOPT_URL). For consistency we check every call, even the ones
10
that theoretically cannot fail.
11
12
Fixes: Coverity CID 1459336, 1459482, 1460331
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-Id: <20220222152341.850419-3-peter.maydell@linaro.org>
15
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
16
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
17
---
18
block/curl.c | 90 +++++++++++++++++++++++++++++++++-------------------
19
1 file changed, 57 insertions(+), 33 deletions(-)
20
21
diff --git a/block/curl.c b/block/curl.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/curl.c
24
+++ b/block/curl.c
25
@@ -XXX,XX +XXX,XX @@ static int curl_init_state(BDRVCURLState *s, CURLState *state)
26
if (!state->curl) {
27
return -EIO;
28
}
29
- curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
30
- curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
31
- (long) s->sslverify);
32
- curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYHOST,
33
- s->sslverify ? 2L : 0L);
34
+ if (curl_easy_setopt(state->curl, CURLOPT_URL, s->url) ||
35
+ curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
36
+ (long) s->sslverify) ||
37
+ curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYHOST,
38
+ s->sslverify ? 2L : 0L)) {
39
+ goto err;
40
+ }
41
if (s->cookie) {
42
- curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie);
43
+ if (curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie)) {
44
+ goto err;
45
+ }
46
+ }
47
+ if (curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout) ||
48
+ curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
49
+ (void *)curl_read_cb) ||
50
+ curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state) ||
51
+ curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state) ||
52
+ curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1) ||
53
+ curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1) ||
54
+ curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1) ||
55
+ curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg) ||
56
+ curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1)) {
57
+ goto err;
58
}
59
- curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout);
60
- curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
61
- (void *)curl_read_cb);
62
- curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
63
- curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
64
- curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
65
- curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
66
- curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
67
- curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
68
- curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
69
-
70
if (s->username) {
71
- curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username);
72
+ if (curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username)) {
73
+ goto err;
74
+ }
75
}
76
if (s->password) {
77
- curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password);
78
+ if (curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password)) {
79
+ goto err;
80
+ }
81
}
82
if (s->proxyusername) {
83
- curl_easy_setopt(state->curl,
84
- CURLOPT_PROXYUSERNAME, s->proxyusername);
85
+ if (curl_easy_setopt(state->curl,
86
+ CURLOPT_PROXYUSERNAME, s->proxyusername)) {
87
+ goto err;
88
+ }
89
}
90
if (s->proxypassword) {
91
- curl_easy_setopt(state->curl,
92
- CURLOPT_PROXYPASSWORD, s->proxypassword);
93
+ if (curl_easy_setopt(state->curl,
94
+ CURLOPT_PROXYPASSWORD, s->proxypassword)) {
95
+ goto err;
96
+ }
97
}
98
99
/* Restrict supported protocols to avoid security issues in the more
100
@@ -XXX,XX +XXX,XX @@ static int curl_init_state(BDRVCURLState *s, CURLState *state)
101
* Restricting protocols is only supported from 7.19.4 upwards.
102
*/
103
#if LIBCURL_VERSION_NUM >= 0x071304
104
- curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
105
- curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
106
+ if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) ||
107
+ curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) {
108
+ goto err;
109
+ }
110
#endif
111
112
#ifdef DEBUG_VERBOSE
113
- curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
114
+ if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) {
115
+ goto err;
116
+ }
117
#endif
118
}
119
120
state->s = s;
121
122
return 0;
123
+
124
+err:
125
+ curl_easy_cleanup(state->curl);
126
+ state->curl = NULL;
127
+ return -EIO;
128
}
129
130
/* Called with s->mutex held. */
131
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
132
}
133
134
s->accept_range = false;
135
- curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
136
- curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION,
137
- curl_header_cb);
138
- curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
139
+ if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) ||
140
+ curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) ||
141
+ curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) {
142
+ pstrcpy(state->errmsg, CURL_ERROR_SIZE,
143
+ "curl library initialization failed.");
144
+ goto out;
145
+ }
146
if (curl_easy_perform(state->curl))
147
goto out;
148
if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
149
@@ -XXX,XX +XXX,XX @@ static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
150
151
snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end);
152
trace_curl_setup_preadv(acb->bytes, start, state->range);
153
- curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
154
-
155
- if (curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) {
156
+ if (curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range) ||
157
+ curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) {
158
state->acb[0] = NULL;
159
acb->ret = -EIO;
160
161
--
162
2.34.1
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We are going to keep coroutine-wrappers code (structure-packing
3
There is a bug in handling BDRV_REQ_NO_WAIT flag: we still may wait in
4
parameters, BDRV_POLL wrapper functions) in separate auto-generated
4
wait_serialising_requests() if request is unaligned. And this is
5
files. So, we'll need a header with declaration of original _co_
5
possible for the only user of this flag (preallocate filter) if
6
functions, for those which are static now. As well, we'll need
6
underlying file is unaligned to its request_alignment on start.
7
declarations for wrapper functions. Do these declarations now, as a
7
8
preparation step.
8
So, we have to fix preallocate filter to do only aligned preallocate
9
requests.
10
11
Next, we should fix generic block/io.c somehow. Keeping in mind that
12
preallocate is the only user of BDRV_REQ_NO_WAIT and that we have to
13
fix its behavior now, it seems more safe to just assert that we never
14
use BDRV_REQ_NO_WAIT with unaligned requests and add corresponding
15
comment. Let's do so.
9
16
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Reviewed-by: Denis V. Lunev <den@openvz.org>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Message-Id: <20220215121609.38570-1-vsementsov@virtuozzo.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
20
[hreitz: Rebased on block GS/IO split]
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
Message-Id: <20200924185414.28642-4-vsementsov@virtuozzo.com>
16
---
22
---
17
block/coroutines.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++
23
include/block/block-common.h | 3 ++-
18
block.c | 8 +++---
24
block/io.c | 4 ++++
19
block/io.c | 34 +++++++++++------------
25
block/preallocate.c | 15 ++++++++++++---
20
3 files changed, 88 insertions(+), 21 deletions(-)
26
3 files changed, 18 insertions(+), 4 deletions(-)
21
create mode 100644 block/coroutines.h
22
27
23
diff --git a/block/coroutines.h b/block/coroutines.h
28
diff --git a/include/block/block-common.h b/include/block/block-common.h
24
new file mode 100644
25
index XXXXXXX..XXXXXXX
26
--- /dev/null
27
+++ b/block/coroutines.h
28
@@ -XXX,XX +XXX,XX @@
29
+/*
30
+ * Block layer I/O functions
31
+ *
32
+ * Copyright (c) 2003 Fabrice Bellard
33
+ *
34
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
35
+ * of this software and associated documentation files (the "Software"), to deal
36
+ * in the Software without restriction, including without limitation the rights
37
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38
+ * copies of the Software, and to permit persons to whom the Software is
39
+ * furnished to do so, subject to the following conditions:
40
+ *
41
+ * The above copyright notice and this permission notice shall be included in
42
+ * all copies or substantial portions of the Software.
43
+ *
44
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
47
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50
+ * THE SOFTWARE.
51
+ */
52
+
53
+#ifndef BLOCK_COROUTINES_INT_H
54
+#define BLOCK_COROUTINES_INT_H
55
+
56
+#include "block/block_int.h"
57
+
58
+int coroutine_fn bdrv_co_check(BlockDriverState *bs,
59
+ BdrvCheckResult *res, BdrvCheckMode fix);
60
+int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
61
+
62
+int coroutine_fn
63
+bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
64
+ bool is_write, BdrvRequestFlags flags);
65
+int
66
+bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
67
+ bool is_write, BdrvRequestFlags flags);
68
+
69
+int coroutine_fn
70
+bdrv_co_common_block_status_above(BlockDriverState *bs,
71
+ BlockDriverState *base,
72
+ bool want_zero,
73
+ int64_t offset,
74
+ int64_t bytes,
75
+ int64_t *pnum,
76
+ int64_t *map,
77
+ BlockDriverState **file);
78
+int
79
+bdrv_common_block_status_above(BlockDriverState *bs,
80
+ BlockDriverState *base,
81
+ bool want_zero,
82
+ int64_t offset,
83
+ int64_t bytes,
84
+ int64_t *pnum,
85
+ int64_t *map,
86
+ BlockDriverState **file);
87
+
88
+int coroutine_fn
89
+bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
90
+ bool is_read);
91
+int
92
+bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
93
+ bool is_read);
94
+
95
+#endif /* BLOCK_COROUTINES_INT_H */
96
diff --git a/block.c b/block.c
97
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
98
--- a/block.c
30
--- a/include/block/block-common.h
99
+++ b/block.c
31
+++ b/include/block/block-common.h
100
@@ -XXX,XX +XXX,XX @@
32
@@ -XXX,XX +XXX,XX @@ typedef enum {
101
#include "qemu/timer.h"
33
102
#include "qemu/cutils.h"
34
/*
103
#include "qemu/id.h"
35
* If we need to wait for other requests, just fail immediately. Used
104
+#include "block/coroutines.h"
36
- * only together with BDRV_REQ_SERIALISING.
105
37
+ * only together with BDRV_REQ_SERIALISING. Used only with requests aligned
106
#ifdef CONFIG_BSD
38
+ * to request_alignment (corresponding assertions are in block/io.c).
107
#include <sys/ioctl.h>
39
*/
108
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
40
BDRV_REQ_NO_WAIT = 0x400,
109
* free of errors) or -errno when an internal error occurred. The results of the
41
110
* check are stored in res.
111
*/
112
-static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
113
- BdrvCheckResult *res, BdrvCheckMode fix)
114
+int coroutine_fn bdrv_co_check(BlockDriverState *bs,
115
+ BdrvCheckResult *res, BdrvCheckMode fix)
116
{
117
if (bs->drv == NULL) {
118
return -ENOMEDIUM;
119
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
120
bdrv_init();
121
}
122
123
-static int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
124
- Error **errp)
125
+int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp)
126
{
127
BdrvChild *child, *parent;
128
uint64_t perm, shared_perm;
129
diff --git a/block/io.c b/block/io.c
42
diff --git a/block/io.c b/block/io.c
130
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
131
--- a/block/io.c
44
--- a/block/io.c
132
+++ b/block/io.c
45
+++ b/block/io.c
133
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
134
#include "block/blockjob.h"
47
135
#include "block/blockjob_int.h"
48
padding = bdrv_init_padding(bs, offset, bytes, &pad);
136
#include "block/block_int.h"
49
if (padding) {
137
+#include "block/coroutines.h"
50
+ assert(!(flags & BDRV_REQ_NO_WAIT));
138
#include "qemu/cutils.h"
51
bdrv_make_request_serialising(req, align);
139
#include "qapi/error.h"
52
140
#include "qemu/error-report.h"
53
bdrv_padding_rmw_read(child, req, &pad, true);
141
@@ -XXX,XX +XXX,XX @@ typedef struct RwCo {
54
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
142
BdrvRequestFlags flags;
55
* serialize the request to prevent interactions of the
143
} RwCo;
56
* widened region with other transactions.
144
57
*/
145
-static int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
58
+ assert(!(flags & BDRV_REQ_NO_WAIT));
146
- QEMUIOVector *qiov, bool is_write,
59
bdrv_make_request_serialising(&req, align);
147
- BdrvRequestFlags flags)
60
bdrv_padding_rmw_read(child, &req, &pad, false);
148
+int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
61
}
149
+ QEMUIOVector *qiov, bool is_write,
62
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(
150
+ BdrvRequestFlags flags)
63
/* TODO We can support BDRV_REQ_NO_FALLBACK here */
151
{
64
assert(!(read_flags & BDRV_REQ_NO_FALLBACK));
152
if (is_write) {
65
assert(!(write_flags & BDRV_REQ_NO_FALLBACK));
153
return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
66
+ assert(!(read_flags & BDRV_REQ_NO_WAIT));
154
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_rw_co_entry(void *opaque)
67
+ assert(!(write_flags & BDRV_REQ_NO_WAIT));
155
/*
68
156
* Process a vectored synchronous request using coroutines
69
if (!dst || !dst->bs || !bdrv_is_inserted(dst->bs)) {
157
*/
70
return -ENOMEDIUM;
158
-static int bdrv_prwv(BdrvChild *child, int64_t offset,
71
diff --git a/block/preallocate.c b/block/preallocate.c
159
- QEMUIOVector *qiov, bool is_write,
72
index XXXXXXX..XXXXXXX 100644
160
- BdrvRequestFlags flags)
73
--- a/block/preallocate.c
161
+int bdrv_prwv(BdrvChild *child, int64_t offset,
74
+++ b/block/preallocate.c
162
+ QEMUIOVector *qiov, bool is_write,
75
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
163
+ BdrvRequestFlags flags)
76
int64_t end = offset + bytes;
164
{
77
int64_t prealloc_start, prealloc_end;
165
RwCo rwco = {
78
int ret;
166
.child = child,
79
+ uint32_t file_align = bs->file->bs->bl.request_alignment;
167
@@ -XXX,XX +XXX,XX @@ early_out:
80
+ uint32_t prealloc_align = MAX(s->opts.prealloc_align, file_align);
168
return ret;
81
+
169
}
82
+ assert(QEMU_IS_ALIGNED(prealloc_align, file_align));
170
83
171
-static int coroutine_fn
84
if (!has_prealloc_perms(bs)) {
172
+int coroutine_fn
85
/* We don't have state neither should try to recover it */
173
bdrv_co_common_block_status_above(BlockDriverState *bs,
86
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
174
BlockDriverState *base,
87
175
bool want_zero,
88
/* Now we want new preallocation, as request writes beyond s->file_end. */
176
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
89
177
*
90
- prealloc_start = want_merge_zero ? MIN(offset, s->file_end) : s->file_end;
178
* See bdrv_co_block_status_above() for details.
91
- prealloc_end = QEMU_ALIGN_UP(end + s->opts.prealloc_size,
179
*/
92
- s->opts.prealloc_align);
180
-static int bdrv_common_block_status_above(BlockDriverState *bs,
93
+ prealloc_start = QEMU_ALIGN_UP(
181
- BlockDriverState *base,
94
+ want_merge_zero ? MIN(offset, s->file_end) : s->file_end,
182
- bool want_zero, int64_t offset,
95
+ file_align);
183
- int64_t bytes, int64_t *pnum,
96
+ prealloc_end = QEMU_ALIGN_UP(
184
- int64_t *map,
97
+ MAX(prealloc_start, end) + s->opts.prealloc_size,
185
- BlockDriverState **file)
98
+ prealloc_align);
186
+int bdrv_common_block_status_above(BlockDriverState *bs,
99
+
187
+ BlockDriverState *base,
100
+ want_merge_zero = want_merge_zero && (prealloc_start <= offset);
188
+ bool want_zero, int64_t offset,
101
189
+ int64_t bytes, int64_t *pnum,
102
ret = bdrv_co_pwrite_zeroes(
190
+ int64_t *map,
103
bs->file, prealloc_start, prealloc_end - prealloc_start,
191
+ BlockDriverState **file)
192
{
193
BdrvCoBlockStatusData data = {
194
.bs = bs,
195
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvVmstateCo {
196
bool is_read;
197
} BdrvVmstateCo;
198
199
-static int coroutine_fn
200
+int coroutine_fn
201
bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
202
bool is_read)
203
{
204
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
205
return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
206
}
207
208
-static inline int
209
-bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
210
- bool is_read)
211
+int bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
212
+ bool is_read)
213
{
214
BdrvVmstateCo data = {
215
.bs = bs,
216
--
104
--
217
2.26.2
105
2.34.1
218
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
iotest 040 already has some checks for the availability of the 'throttle'
4
driver, but some new code has been added in the course of time that
5
depends on 'throttle' but does not check for its availability. Add
6
a check to the TestCommitWithFilters class so that this iotest now
7
also passes again if 'throttle' has not been enabled in the QEMU
8
binaries.
9
10
Signed-off-by: Thomas Huth <thuth@redhat.com>
11
Message-Id: <20220223123127.3206042-1-thuth@redhat.com>
12
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
---
14
tests/qemu-iotests/040 | 1 +
15
1 file changed, 1 insertion(+)
16
17
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/040
20
+++ b/tests/qemu-iotests/040
21
@@ -XXX,XX +XXX,XX @@ class TestCommitWithFilters(iotests.QMPTestCase):
22
pattern_file)
23
self.assertFalse('Pattern verification failed' in result)
24
25
+ @iotests.skip_if_unsupported(['throttle'])
26
def setUp(self):
27
qemu_img('create', '-f', iotests.imgfmt, self.img0, '64M')
28
qemu_img('create', '-f', iotests.imgfmt, self.img1, '64M')
29
--
30
2.34.1
diff view generated by jsdifflib
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
In TAP mode, the stdout is reserved for the TAP protocol, so we
4
have to make sure to mark other lines with a comment '#' character
5
at the beginning to avoid that the TAP parser at the other end
6
gets confused.
7
8
To test this condition, run "configure" for example with:
9
10
--block-drv-rw-whitelist=copy-before-write,qcow2,raw,file,host_device,blkdebug,null-co,copy-on-read
11
12
so that iotest 041 will report that some tests are not run due to
13
the missing "quorum" driver. Without this change, "make check-block"
14
fails since the meson tap parser gets confused by these messages.
15
16
Signed-off-by: Thomas Huth <thuth@redhat.com>
17
Message-Id: <20220223124353.3273898-1-thuth@redhat.com>
18
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
19
---
20
tests/qemu-iotests/testrunner.py | 5 ++++-
21
1 file changed, 4 insertions(+), 1 deletion(-)
22
23
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
24
index XXXXXXX..XXXXXXX 100644
25
--- a/tests/qemu-iotests/testrunner.py
26
+++ b/tests/qemu-iotests/testrunner.py
27
@@ -XXX,XX +XXX,XX @@ def run_test(self, test: str,
28
description=res.description)
29
30
if res.casenotrun:
31
- print(res.casenotrun)
32
+ if self.tap:
33
+ print('#' + res.casenotrun.replace('\n', '\n#'))
34
+ else:
35
+ print(res.casenotrun)
36
37
return res
38
39
--
40
2.34.1
diff view generated by jsdifflib
New patch
1
Drop the use of OUTPUT_DIR (test/qemu-iotests under the build
2
directory), and instead write test output files (.out.bad, .notrun, and
3
.casenotrun) to TEST_DIR.
1
4
5
With this, the same test can be run concurrently without the separate
6
instances interfering, because they will need separate TEST_DIRs anyway.
7
Running the same test separately is useful when running the iotests with
8
various format/protocol combinations in parallel, or when you just want
9
to aggressively exercise a single test (e.g. when it fails only
10
sporadically).
11
12
Putting this output into TEST_DIR means that it will stick around for
13
inspection after the test run is done (though running the same test in
14
the same TEST_DIR will overwrite it, just as it used to be); but given
15
that TEST_DIR is a scratch directory, it should be clear that users can
16
delete all of its content at any point. (And if TEST_DIR is on tmpfs,
17
it will just disappear on shutdown.) Contrarily, alternative approaches
18
that would put these output files into OUTPUT_DIR with some prefix to
19
differentiate between separate test runs might easily lead to cluttering
20
OUTPUT_DIR.
21
22
(This change means OUTPUT_DIR is no longer written to by the iotests, so
23
we can drop its usage altogether.)
24
25
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
26
Message-Id: <20220221172909.762858-1-hreitz@redhat.com>
27
[hreitz: Simplified `Path(os.path.join(x, y))` to `Path(x, y)`, as
28
suggested by Vladimir; and rebased on 9086c7639822b6
29
("tests/qemu-iotests: Rework the checks and spots using GNU
30
sed")]
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
---
33
tests/qemu-iotests/common.rc | 6 +++---
34
tests/qemu-iotests/iotests.py | 5 ++---
35
tests/qemu-iotests/testenv.py | 5 +----
36
tests/qemu-iotests/testrunner.py | 14 ++++++++------
37
4 files changed, 14 insertions(+), 16 deletions(-)
38
39
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
40
index XXXXXXX..XXXXXXX 100644
41
--- a/tests/qemu-iotests/common.rc
42
+++ b/tests/qemu-iotests/common.rc
43
@@ -XXX,XX +XXX,XX @@
44
# bail out, setting up .notrun file
45
_notrun()
46
{
47
- echo "$*" >"$OUTPUT_DIR/$seq.notrun"
48
+ echo "$*" >"$TEST_DIR/$seq.notrun"
49
echo "$seq not run: $*"
50
status=0
51
exit
52
@@ -XXX,XX +XXX,XX @@ _img_info()
53
#
54
_casenotrun()
55
{
56
- echo " [case not run] $*" >>"$OUTPUT_DIR/$seq.casenotrun"
57
+ echo " [case not run] $*" >>"$TEST_DIR/$seq.casenotrun"
58
}
59
60
# just plain bail out
61
#
62
_fail()
63
{
64
- echo "$*" | tee -a "$OUTPUT_DIR/$seq.full"
65
+ echo "$*" | tee -a "$TEST_DIR/$seq.full"
66
echo "(see $seq.full for details)"
67
status=1
68
exit 1
69
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
70
index XXXXXXX..XXXXXXX 100644
71
--- a/tests/qemu-iotests/iotests.py
72
+++ b/tests/qemu-iotests/iotests.py
73
@@ -XXX,XX +XXX,XX @@
74
75
imgfmt = os.environ.get('IMGFMT', 'raw')
76
imgproto = os.environ.get('IMGPROTO', 'file')
77
-output_dir = os.environ.get('OUTPUT_DIR', '.')
78
79
try:
80
test_dir = os.environ['TEST_DIR']
81
@@ -XXX,XX +XXX,XX @@ def notrun(reason):
82
# Each test in qemu-iotests has a number ("seq")
83
seq = os.path.basename(sys.argv[0])
84
85
- with open('%s/%s.notrun' % (output_dir, seq), 'w', encoding='utf-8') \
86
+ with open('%s/%s.notrun' % (test_dir, seq), 'w', encoding='utf-8') \
87
as outfile:
88
outfile.write(reason + '\n')
89
logger.warning("%s not run: %s", seq, reason)
90
@@ -XXX,XX +XXX,XX @@ def case_notrun(reason):
91
# Each test in qemu-iotests has a number ("seq")
92
seq = os.path.basename(sys.argv[0])
93
94
- with open('%s/%s.casenotrun' % (output_dir, seq), 'a', encoding='utf-8') \
95
+ with open('%s/%s.casenotrun' % (test_dir, seq), 'a', encoding='utf-8') \
96
as outfile:
97
outfile.write(' [case not run] ' + reason + '\n')
98
99
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
100
index XXXXXXX..XXXXXXX 100644
101
--- a/tests/qemu-iotests/testenv.py
102
+++ b/tests/qemu-iotests/testenv.py
103
@@ -XXX,XX +XXX,XX @@ class TestEnv(ContextManager['TestEnv']):
104
# pylint: disable=too-many-instance-attributes
105
106
env_variables = ['PYTHONPATH', 'TEST_DIR', 'SOCK_DIR', 'SAMPLE_IMG_DIR',
107
- 'OUTPUT_DIR', 'PYTHON', 'QEMU_PROG', 'QEMU_IMG_PROG',
108
+ 'PYTHON', 'QEMU_PROG', 'QEMU_IMG_PROG',
109
'QEMU_IO_PROG', 'QEMU_NBD_PROG', 'QSD_PROG',
110
'QEMU_OPTIONS', 'QEMU_IMG_OPTIONS',
111
'QEMU_IO_OPTIONS', 'QEMU_IO_OPTIONS_NO_FMT',
112
@@ -XXX,XX +XXX,XX @@ def init_directories(self) -> None:
113
TEST_DIR
114
SOCK_DIR
115
SAMPLE_IMG_DIR
116
- OUTPUT_DIR
117
"""
118
119
# Path where qemu goodies live in this source tree.
120
@@ -XXX,XX +XXX,XX @@ def init_directories(self) -> None:
121
os.path.join(self.source_iotests,
122
'sample_images'))
123
124
- self.output_dir = os.getcwd() # OUTPUT_DIR
125
-
126
def init_binaries(self) -> None:
127
"""Init binary path variables:
128
PYTHON (for bash tests)
129
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
130
index XXXXXXX..XXXXXXX 100644
131
--- a/tests/qemu-iotests/testrunner.py
132
+++ b/tests/qemu-iotests/testrunner.py
133
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str, mp: bool) -> TestResult:
134
"""
135
136
f_test = Path(test)
137
- f_bad = Path(f_test.name + '.out.bad')
138
- f_notrun = Path(f_test.name + '.notrun')
139
- f_casenotrun = Path(f_test.name + '.casenotrun')
140
f_reference = Path(self.find_reference(test))
141
142
if not f_test.exists():
143
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str, mp: bool) -> TestResult:
144
description='No qualified output '
145
f'(expected {f_reference})')
146
147
- for p in (f_bad, f_notrun, f_casenotrun):
148
- silent_unlink(p)
149
-
150
args = [str(f_test.resolve())]
151
env = self.env.prepare_subprocess(args)
152
if mp:
153
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str, mp: bool) -> TestResult:
154
env[d] = os.path.join(env[d], f_test.name)
155
Path(env[d]).mkdir(parents=True, exist_ok=True)
156
157
+ test_dir = env['TEST_DIR']
158
+ f_bad = Path(test_dir, f_test.name + '.out.bad')
159
+ f_notrun = Path(test_dir, f_test.name + '.notrun')
160
+ f_casenotrun = Path(test_dir, f_test.name + '.casenotrun')
161
+
162
+ for p in (f_notrun, f_casenotrun):
163
+ silent_unlink(p)
164
+
165
t0 = time.time()
166
with f_bad.open('w', encoding="utf-8") as f:
167
with subprocess.Popen(args, cwd=str(f_test.parent), env=env,
168
--
169
2.34.1
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Pages are currently mapped READ/WRITE. To be able to use different
3
We are going to complicate bitmap initialization in the further
4
protections, add a new argument to qemu_vfio_pci_map_bar().
4
commit. And in future, backup job will be able to work without filter
5
(when source is immutable), so we'll need same bitmap initialization in
6
copy-before-write filter and in backup job. So, it's reasonable to do
7
it in block-copy.
5
8
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Note that for now cbw_open() is the only caller of
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
block_copy_state_new().
8
Message-Id: <20200922083821.578519-2-philmd@redhat.com>
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
14
Message-Id: <20220303194349.2304213-2-vsementsov@virtuozzo.com>
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
16
---
10
include/qemu/vfio-helpers.h | 2 +-
17
block/block-copy.c | 1 +
11
block/nvme.c | 3 ++-
18
block/copy-before-write.c | 4 ----
12
util/vfio-helpers.c | 4 ++--
19
2 files changed, 1 insertion(+), 4 deletions(-)
13
3 files changed, 5 insertions(+), 4 deletions(-)
14
20
15
diff --git a/include/qemu/vfio-helpers.h b/include/qemu/vfio-helpers.h
21
diff --git a/block/block-copy.c b/block/block-copy.c
16
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
17
--- a/include/qemu/vfio-helpers.h
23
--- a/block/block-copy.c
18
+++ b/include/qemu/vfio-helpers.h
24
+++ b/block/block-copy.c
19
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size,
25
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
20
int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s);
26
return NULL;
21
void qemu_vfio_dma_unmap(QEMUVFIOState *s, void *host);
27
}
22
void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index,
28
bdrv_disable_dirty_bitmap(copy_bitmap);
23
- uint64_t offset, uint64_t size,
29
+ bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap));
24
+ uint64_t offset, uint64_t size, int prot,
30
25
Error **errp);
31
/*
26
void qemu_vfio_pci_unmap_bar(QEMUVFIOState *s, int index, void *bar,
32
* If source is in backing chain of target assume that target is going to be
27
uint64_t offset, uint64_t size);
33
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
28
diff --git a/block/nvme.c b/block/nvme.c
29
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
30
--- a/block/nvme.c
35
--- a/block/copy-before-write.c
31
+++ b/block/nvme.c
36
+++ b/block/copy-before-write.c
32
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
37
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
33
goto out;
38
Error **errp)
39
{
40
BDRVCopyBeforeWriteState *s = bs->opaque;
41
- BdrvDirtyBitmap *copy_bitmap;
42
43
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
44
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
45
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
46
return -EINVAL;
34
}
47
}
35
48
36
- s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE, errp);
49
- copy_bitmap = block_copy_dirty_bitmap(s->bcs);
37
+ s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE,
50
- bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap));
38
+ PROT_READ | PROT_WRITE, errp);
51
-
39
if (!s->regs) {
52
return 0;
40
ret = -EINVAL;
53
}
41
goto out;
54
42
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/util/vfio-helpers.c
45
+++ b/util/vfio-helpers.c
46
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_pci_init_bar(QEMUVFIOState *s, int index, Error **errp)
47
* Map a PCI bar area.
48
*/
49
void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index,
50
- uint64_t offset, uint64_t size,
51
+ uint64_t offset, uint64_t size, int prot,
52
Error **errp)
53
{
54
void *p;
55
assert_bar_index_valid(s, index);
56
p = mmap(NULL, MIN(size, s->bar_region_info[index].size - offset),
57
- PROT_READ | PROT_WRITE, MAP_SHARED,
58
+ prot, MAP_SHARED,
59
s->device, s->bar_region_info[index].offset + offset);
60
if (p == MAP_FAILED) {
61
error_setg_errno(errp, errno, "Failed to map BAR region");
62
--
55
--
63
2.26.2
56
2.34.1
64
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
That simplifies handling failure in existing code and in further new
4
usage of bdrv_merge_dirty_bitmap().
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Message-Id: <20220303194349.2304213-3-vsementsov@virtuozzo.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
11
include/block/dirty-bitmap.h | 2 +-
12
block/dirty-bitmap.c | 9 +++++++--
13
block/monitor/bitmap-qmp-cmds.c | 5 +----
14
3 files changed, 9 insertions(+), 7 deletions(-)
15
16
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/dirty-bitmap.h
19
+++ b/include/block/dirty-bitmap.h
20
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap,
21
bool persistent);
22
void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap);
23
void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy);
24
-void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
25
+bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
26
HBitmap **backup, Error **errp);
27
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip);
28
bool bdrv_dirty_bitmap_get(BdrvDirtyBitmap *bitmap, int64_t offset);
29
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/dirty-bitmap.c
32
+++ b/block/dirty-bitmap.c
33
@@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
34
* Ensures permissions on bitmaps are reasonable; use for public API.
35
*
36
* @backup: If provided, make a copy of dest here prior to merge.
37
+ *
38
+ * Returns true on success, false on failure. In case of failure bitmaps are
39
+ * untouched.
40
*/
41
-void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
42
+bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
43
HBitmap **backup, Error **errp)
44
{
45
- bool ret;
46
+ bool ret = false;
47
48
bdrv_dirty_bitmaps_lock(dest->bs);
49
if (src->bs != dest->bs) {
50
@@ -XXX,XX +XXX,XX @@ out:
51
if (src->bs != dest->bs) {
52
bdrv_dirty_bitmaps_unlock(src->bs);
53
}
54
+
55
+ return ret;
56
}
57
58
/**
59
diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/monitor/bitmap-qmp-cmds.c
62
+++ b/block/monitor/bitmap-qmp-cmds.c
63
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
64
BlockDriverState *bs;
65
BdrvDirtyBitmap *dst, *src, *anon;
66
BlockDirtyBitmapMergeSourceList *lst;
67
- Error *local_err = NULL;
68
69
GLOBAL_STATE_CODE();
70
71
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
72
abort();
73
}
74
75
- bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
76
- if (local_err) {
77
- error_propagate(errp, local_err);
78
+ if (!bdrv_merge_dirty_bitmap(anon, src, NULL, errp)) {
79
dst = NULL;
80
goto out;
81
}
82
--
83
2.34.1
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This is the only non-ascii character in the file and it doesn't really
3
This will be used in the following commit to bring "incremental" mode
4
needed here. Let's use normal "'" symbol for consistency with the rest
4
to copy-before-write filter.
5
11 occurrences of "'" in the file.
6
5
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20220303194349.2304213-4-vsementsov@virtuozzo.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
10
---
11
include/block/block.h | 2 +-
11
include/block/block-copy.h | 1 +
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
block/block-copy.c | 14 +++++++++++++-
13
block/copy-before-write.c | 2 +-
14
3 files changed, 15 insertions(+), 2 deletions(-)
13
15
14
diff --git a/include/block/block.h b/include/block/block.h
16
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
18
--- a/include/block/block-copy.h
17
+++ b/include/block/block.h
19
+++ b/include/block/block-copy.h
18
@@ -XXX,XX +XXX,XX @@ enum BdrvChildRoleBits {
20
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState BlockCopyState;
19
BDRV_CHILD_FILTERED = (1 << 2),
21
typedef struct BlockCopyCallState BlockCopyCallState;
22
23
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
24
+ const BdrvDirtyBitmap *bitmap,
25
Error **errp);
26
27
/* Function should be called prior any actual copy request */
28
diff --git a/block/block-copy.c b/block/block-copy.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-copy.c
31
+++ b/block/block-copy.c
32
@@ -XXX,XX +XXX,XX @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
33
}
34
35
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
36
+ const BdrvDirtyBitmap *bitmap,
37
Error **errp)
38
{
39
+ ERRP_GUARD();
40
BlockCopyState *s;
41
int64_t cluster_size;
42
BdrvDirtyBitmap *copy_bitmap;
43
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
44
return NULL;
45
}
46
bdrv_disable_dirty_bitmap(copy_bitmap);
47
- bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap));
48
+ if (bitmap) {
49
+ if (!bdrv_merge_dirty_bitmap(copy_bitmap, bitmap, NULL, errp)) {
50
+ error_prepend(errp, "Failed to merge bitmap '%s' to internal "
51
+ "copy-bitmap: ", bdrv_dirty_bitmap_name(bitmap));
52
+ bdrv_release_dirty_bitmap(copy_bitmap);
53
+ return NULL;
54
+ }
55
+ } else {
56
+ bdrv_set_dirty_bitmap(copy_bitmap, 0,
57
+ bdrv_dirty_bitmap_size(copy_bitmap));
58
+ }
20
59
21
/*
60
/*
22
- * Child from which to read all data that isn’t allocated in the
61
* If source is in backing chain of target assume that target is going to be
23
+ * Child from which to read all data that isn't allocated in the
62
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
24
* parent (i.e., the backing child); such data is copied to the
63
index XXXXXXX..XXXXXXX 100644
25
* parent through COW (and optionally COR).
64
--- a/block/copy-before-write.c
26
* This field is mutually exclusive with DATA, METADATA, and
65
+++ b/block/copy-before-write.c
66
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
67
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
68
bs->file->bs->supported_zero_flags);
69
70
- s->bcs = block_copy_state_new(bs->file, s->target, errp);
71
+ s->bcs = block_copy_state_new(bs->file, s->target, NULL, errp);
72
if (!s->bcs) {
73
error_prepend(errp, "Cannot create block-copy-state: ");
74
return -EINVAL;
27
--
75
--
28
2.26.2
76
2.34.1
29
diff view generated by jsdifflib
1
From: Eric Auger <eric.auger@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The IOVA allocator currently ignores host reserved regions.
3
This brings "incremental" mode to copy-before-write filter: user can
4
As a result some chosen IOVAs may collide with some of them,
4
specify bitmap so that filter will copy only "dirty" areas.
5
resulting in VFIO MAP_DMA errors later on. This happens on ARM
6
where the MSI reserved window quickly is encountered:
7
[0x8000000, 0x8100000]. since 5.4 kernel, VFIO returns the usable
8
IOVA regions. So let's enumerate them in the prospect to avoid
9
them, later on.
10
5
11
Signed-off-by: Eric Auger <eric.auger@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-id: 20200929085550.30926-2-eric.auger@redhat.com
7
Message-Id: <20220303194349.2304213-5-vsementsov@virtuozzo.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
14
---
9
---
15
util/vfio-helpers.c | 72 +++++++++++++++++++++++++++++++++++++++++++--
10
qapi/block-core.json | 10 +++++++-
16
1 file changed, 70 insertions(+), 2 deletions(-)
11
block/copy-before-write.c | 51 ++++++++++++++++++++++++++++++++++++++-
12
2 files changed, 59 insertions(+), 2 deletions(-)
17
13
18
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
14
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/util/vfio-helpers.c
16
--- a/qapi/block-core.json
21
+++ b/util/vfio-helpers.c
17
+++ b/qapi/block-core.json
22
@@ -XXX,XX +XXX,XX @@ typedef struct {
18
@@ -XXX,XX +XXX,XX @@
23
uint64_t iova;
19
#
24
} IOVAMapping;
20
# @target: The target for copy-before-write operations.
25
21
#
26
+struct IOVARange {
22
+# @bitmap: If specified, copy-before-write filter will do
27
+ uint64_t start;
23
+# copy-before-write operations only for dirty regions of the
28
+ uint64_t end;
24
+# bitmap. Bitmap size must be equal to length of file and
29
+};
25
+# target child of the filter. Note also, that bitmap is used
26
+# only to initialize internal bitmap of the process, so further
27
+# modifications (or removing) of specified bitmap doesn't
28
+# influence the filter. (Since 7.0)
29
+#
30
# Since: 6.2
31
##
32
{ 'struct': 'BlockdevOptionsCbw',
33
'base': 'BlockdevOptionsGenericFormat',
34
- 'data': { 'target': 'BlockdevRef' } }
35
+ 'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap' } }
36
37
##
38
# @BlockdevOptions:
39
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/copy-before-write.c
42
+++ b/block/copy-before-write.c
43
@@ -XXX,XX +XXX,XX @@
44
45
#include "block/copy-before-write.h"
46
47
+#include "qapi/qapi-visit-block-core.h"
30
+
48
+
31
struct QEMUVFIOState {
49
typedef struct BDRVCopyBeforeWriteState {
32
QemuMutex lock;
50
BlockCopyState *bcs;
33
51
BdrvChild *target;
34
@@ -XXX,XX +XXX,XX @@ struct QEMUVFIOState {
52
@@ -XXX,XX +XXX,XX @@ static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
35
int device;
53
}
36
RAMBlockNotifier ram_notifier;
37
struct vfio_region_info config_region_info, bar_region_info[6];
38
+ struct IOVARange *usable_iova_ranges;
39
+ uint8_t nb_iova_ranges;
40
41
/* These fields are protected by @lock */
42
/* VFIO's IO virtual address space is managed by splitting into a few
43
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_pci_write_config(QEMUVFIOState *s, void *buf, int size, int
44
return ret == size ? 0 : -errno;
45
}
54
}
46
55
47
+static void collect_usable_iova_ranges(QEMUVFIOState *s, void *buf)
56
+static bool cbw_parse_bitmap_option(QDict *options, BdrvDirtyBitmap **bitmap,
57
+ Error **errp)
48
+{
58
+{
49
+ struct vfio_iommu_type1_info *info = (struct vfio_iommu_type1_info *)buf;
59
+ QDict *bitmap_qdict = NULL;
50
+ struct vfio_info_cap_header *cap = (void *)buf + info->cap_offset;
60
+ BlockDirtyBitmap *bmp_param = NULL;
51
+ struct vfio_iommu_type1_info_cap_iova_range *cap_iova_range;
61
+ Visitor *v = NULL;
52
+ int i;
62
+ bool ret = false;
53
+
63
+
54
+ while (cap->id != VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE) {
64
+ *bitmap = NULL;
55
+ if (!cap->next) {
65
+
56
+ return;
66
+ qdict_extract_subqdict(options, &bitmap_qdict, "bitmap.");
57
+ }
67
+ if (!qdict_size(bitmap_qdict)) {
58
+ cap = (struct vfio_info_cap_header *)(buf + cap->next);
68
+ ret = true;
69
+ goto out;
59
+ }
70
+ }
60
+
71
+
61
+ cap_iova_range = (struct vfio_iommu_type1_info_cap_iova_range *)cap;
72
+ v = qobject_input_visitor_new_flat_confused(bitmap_qdict, errp);
62
+
73
+ if (!v) {
63
+ s->nb_iova_ranges = cap_iova_range->nr_iovas;
74
+ goto out;
64
+ if (s->nb_iova_ranges > 1) {
65
+ s->usable_iova_ranges =
66
+ g_realloc(s->usable_iova_ranges,
67
+ s->nb_iova_ranges * sizeof(struct IOVARange));
68
+ }
75
+ }
69
+
76
+
70
+ for (i = 0; i < s->nb_iova_ranges; i++) {
77
+ visit_type_BlockDirtyBitmap(v, NULL, &bmp_param, errp);
71
+ s->usable_iova_ranges[i].start = cap_iova_range->iova_ranges[i].start;
78
+ if (!bmp_param) {
72
+ s->usable_iova_ranges[i].end = cap_iova_range->iova_ranges[i].end;
79
+ goto out;
73
+ }
80
+ }
81
+
82
+ *bitmap = block_dirty_bitmap_lookup(bmp_param->node, bmp_param->name, NULL,
83
+ errp);
84
+ if (!*bitmap) {
85
+ goto out;
86
+ }
87
+
88
+ ret = true;
89
+
90
+out:
91
+ qapi_free_BlockDirtyBitmap(bmp_param);
92
+ visit_free(v);
93
+ qobject_unref(bitmap_qdict);
94
+
95
+ return ret;
74
+}
96
+}
75
+
97
+
76
static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
98
static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
77
Error **errp)
99
Error **errp)
78
{
100
{
79
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
101
BDRVCopyBeforeWriteState *s = bs->opaque;
80
int i;
102
+ BdrvDirtyBitmap *bitmap = NULL;
81
uint16_t pci_cmd;
103
82
struct vfio_group_status group_status = { .argsz = sizeof(group_status) };
104
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
83
- struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };
105
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
84
+ struct vfio_iommu_type1_info *iommu_info = NULL;
106
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
85
+ size_t iommu_info_size = sizeof(*iommu_info);
107
return -EINVAL;
86
struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
87
char *group_file = NULL;
88
89
+ s->usable_iova_ranges = NULL;
90
+
91
/* Create a new container */
92
s->container = open("/dev/vfio/vfio", O_RDWR);
93
94
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
95
goto fail;
96
}
108
}
97
109
98
+ iommu_info = g_malloc0(iommu_info_size);
110
+ if (!cbw_parse_bitmap_option(options, &bitmap, errp)) {
99
+ iommu_info->argsz = iommu_info_size;
111
+ return -EINVAL;
100
+
101
/* Get additional IOMMU info */
102
- if (ioctl(s->container, VFIO_IOMMU_GET_INFO, &iommu_info)) {
103
+ if (ioctl(s->container, VFIO_IOMMU_GET_INFO, iommu_info)) {
104
error_setg_errno(errp, errno, "Failed to get IOMMU info");
105
ret = -errno;
106
goto fail;
107
}
108
109
+ /*
110
+ * if the kernel does not report usable IOVA regions, choose
111
+ * the legacy [QEMU_VFIO_IOVA_MIN, QEMU_VFIO_IOVA_MAX -1] region
112
+ */
113
+ s->nb_iova_ranges = 1;
114
+ s->usable_iova_ranges = g_new0(struct IOVARange, 1);
115
+ s->usable_iova_ranges[0].start = QEMU_VFIO_IOVA_MIN;
116
+ s->usable_iova_ranges[0].end = QEMU_VFIO_IOVA_MAX - 1;
117
+
118
+ if (iommu_info->argsz > iommu_info_size) {
119
+ iommu_info_size = iommu_info->argsz;
120
+ iommu_info = g_realloc(iommu_info, iommu_info_size);
121
+ if (ioctl(s->container, VFIO_IOMMU_GET_INFO, iommu_info)) {
122
+ ret = -errno;
123
+ goto fail;
124
+ }
125
+ collect_usable_iova_ranges(s, iommu_info);
126
+ }
112
+ }
127
+
113
+
128
s->device = ioctl(s->group, VFIO_GROUP_GET_DEVICE_FD, device);
114
bs->total_sectors = bs->file->bs->total_sectors;
129
115
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
130
if (s->device < 0) {
116
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
131
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
117
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
132
if (ret) {
118
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
133
goto fail;
119
bs->file->bs->supported_zero_flags);
134
}
120
135
+ g_free(iommu_info);
121
- s->bcs = block_copy_state_new(bs->file, s->target, NULL, errp);
136
return 0;
122
+ s->bcs = block_copy_state_new(bs->file, s->target, bitmap, errp);
137
fail:
123
if (!s->bcs) {
138
+ g_free(s->usable_iova_ranges);
124
error_prepend(errp, "Cannot create block-copy-state: ");
139
+ s->usable_iova_ranges = NULL;
125
return -EINVAL;
140
+ s->nb_iova_ranges = 0;
141
+ g_free(iommu_info);
142
close(s->group);
143
fail_container:
144
close(s->container);
145
@@ -XXX,XX +XXX,XX @@ void qemu_vfio_close(QEMUVFIOState *s)
146
qemu_vfio_undo_mapping(s, &s->mappings[i], NULL);
147
}
148
ram_block_notifier_remove(&s->ram_notifier);
149
+ g_free(s->usable_iova_ranges);
150
+ s->nb_iova_ranges = 0;
151
qemu_vfio_reset(s);
152
close(s->device);
153
close(s->group);
154
--
126
--
155
2.26.2
127
2.34.1
156
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Now that we are not maintaining boilerplate code for coroutine
3
Split block_copy_reset() out of block_copy_reset_unallocated() to be
4
wrappers, there is no more sense in keeping the extra indirection layer
4
used separately later.
5
of bdrv_prwv(). Let's drop it and instead generate pure bdrv_preadv()
6
and bdrv_pwritev().
7
8
Currently, bdrv_pwritev() and bdrv_preadv() are returning bytes on
9
success, auto generated functions will instead return zero, as their
10
_co_ prototype. Still, it's simple to make the conversion safe: the
11
only external user of bdrv_pwritev() is test-bdrv-drain, and it is
12
comfortable enough with bdrv_co_pwritev() instead. So prototypes are
13
moved to local block/coroutines.h. Next, the only internal use is
14
bdrv_pread() and bdrv_pwrite(), which are modified to return bytes on
15
success.
16
17
Of course, it would be great to convert bdrv_pread() and bdrv_pwrite()
18
to return 0 on success. But this requires audit (and probably
19
conversion) of all their users, let's leave it for another day
20
refactoring.
21
5
22
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Message-Id: <20220303194349.2304213-6-vsementsov@virtuozzo.com>
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
26
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-Id: <20200924185414.28642-7-vsementsov@virtuozzo.com>
28
---
10
---
29
block/coroutines.h | 10 ++++-----
11
include/block/block-copy.h | 1 +
30
include/block/block.h | 2 --
12
block/block-copy.c | 21 +++++++++++++--------
31
block/io.c | 49 ++++++++---------------------------------
13
2 files changed, 14 insertions(+), 8 deletions(-)
32
tests/test-bdrv-drain.c | 2 +-
33
4 files changed, 15 insertions(+), 48 deletions(-)
34
14
35
diff --git a/block/coroutines.h b/block/coroutines.h
15
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
36
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
37
--- a/block/coroutines.h
17
--- a/include/block/block-copy.h
38
+++ b/block/coroutines.h
18
+++ b/include/block/block-copy.h
39
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
19
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm);
40
BdrvCheckResult *res, BdrvCheckMode fix);
20
41
int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
21
void block_copy_state_free(BlockCopyState *s);
42
22
43
-int coroutine_fn
23
+void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes);
44
-bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
24
int64_t block_copy_reset_unallocated(BlockCopyState *s,
45
- bool is_write, BdrvRequestFlags flags);
25
int64_t offset, int64_t *count);
46
int generated_co_wrapper
26
47
-bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
27
diff --git a/block/block-copy.c b/block/block-copy.c
48
- bool is_write, BdrvRequestFlags flags);
49
+bdrv_preadv(BdrvChild *child, int64_t offset, unsigned int bytes,
50
+ QEMUIOVector *qiov, BdrvRequestFlags flags);
51
+int generated_co_wrapper
52
+bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes,
53
+ QEMUIOVector *qiov, BdrvRequestFlags flags);
54
55
int coroutine_fn
56
bdrv_co_common_block_status_above(BlockDriverState *bs,
57
diff --git a/include/block/block.h b/include/block/block.h
58
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
59
--- a/include/block/block.h
29
--- a/block/block-copy.c
60
+++ b/include/block/block.h
30
+++ b/block/block-copy.c
61
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
31
@@ -XXX,XX +XXX,XX @@ static int block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset,
62
int bytes, BdrvRequestFlags flags);
63
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
64
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes);
65
-int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov);
66
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes);
67
-int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov);
68
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
69
const void *buf, int count);
70
/*
71
diff --git a/block/io.c b/block/io.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/block/io.c
74
+++ b/block/io.c
75
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
76
return 0;
77
}
78
79
-int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
80
- QEMUIOVector *qiov, bool is_write,
81
- BdrvRequestFlags flags)
82
-{
83
- if (is_write) {
84
- return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
85
- } else {
86
- return bdrv_co_preadv(child, offset, qiov->size, qiov, flags);
87
- }
88
-}
89
-
90
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
91
int bytes, BdrvRequestFlags flags)
92
{
93
- QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
94
-
95
- return bdrv_prwv(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags);
96
+ return bdrv_pwritev(child, offset, bytes, NULL,
97
+ BDRV_REQ_ZERO_WRITE | flags);
98
}
99
100
/*
101
@@ -XXX,XX +XXX,XX @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
102
}
32
}
103
}
33
}
104
34
105
-/* return < 0 if error. See bdrv_pwrite() for the return codes */
35
+void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes)
106
-int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
36
+{
107
-{
37
+ QEMU_LOCK_GUARD(&s->lock);
108
- int ret;
38
+
109
-
39
+ bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
110
- ret = bdrv_prwv(child, offset, qiov, false, 0);
40
+ if (s->progress) {
111
- if (ret < 0) {
41
+ progress_set_remaining(s->progress,
112
- return ret;
42
+ bdrv_get_dirty_count(s->copy_bitmap) +
113
- }
43
+ s->in_flight_bytes);
114
-
44
+ }
115
- return qiov->size;
45
+}
116
-}
46
+
117
-
47
/*
118
/* See bdrv_pwrite() for the return codes */
48
* Reset bits in copy_bitmap starting at offset if they represent unallocated
119
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
49
* data in the image. May reset subsequent contiguous bits.
120
{
50
@@ -XXX,XX +XXX,XX @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
121
+ int ret;
51
bytes = clusters * s->cluster_size;
122
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
52
123
53
if (!ret) {
124
if (bytes < 0) {
54
- qemu_co_mutex_lock(&s->lock);
125
return -EINVAL;
55
- bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
56
- if (s->progress) {
57
- progress_set_remaining(s->progress,
58
- bdrv_get_dirty_count(s->copy_bitmap) +
59
- s->in_flight_bytes);
60
- }
61
- qemu_co_mutex_unlock(&s->lock);
62
+ block_copy_reset(s, offset, bytes);
126
}
63
}
127
64
128
- return bdrv_preadv(child, offset, &qiov);
65
*count = bytes;
129
-}
130
+ ret = bdrv_preadv(child, offset, bytes, &qiov, 0);
131
132
-int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
133
-{
134
- int ret;
135
-
136
- ret = bdrv_prwv(child, offset, qiov, true, 0);
137
- if (ret < 0) {
138
- return ret;
139
- }
140
-
141
- return qiov->size;
142
+ return ret < 0 ? ret : bytes;
143
}
144
145
/* Return no. of bytes on success or < 0 on error. Important errors are:
146
@@ -XXX,XX +XXX,XX @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
147
*/
148
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
149
{
150
+ int ret;
151
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
152
153
if (bytes < 0) {
154
return -EINVAL;
155
}
156
157
- return bdrv_pwritev(child, offset, &qiov);
158
+ ret = bdrv_pwritev(child, offset, bytes, &qiov, 0);
159
+
160
+ return ret < 0 ? ret : bytes;
161
}
162
163
/*
164
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/tests/test-bdrv-drain.c
167
+++ b/tests/test-bdrv-drain.c
168
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs,
169
}
170
s->io_co = NULL;
171
172
- ret = bdrv_preadv(bs->backing, offset, qiov);
173
+ ret = bdrv_co_preadv(bs->backing, offset, bytes, qiov, 0);
174
s->has_read = true;
175
176
/* Wake up drain_co if it runs */
177
--
66
--
178
2.26.2
67
2.34.1
179
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Use code generation implemented in previous commit to generated
3
Split intersecting-requests functionality out of block-copy to be
4
coroutine wrappers in block.c and block/io.c
4
reused in copy-before-write filter.
5
6
Note: while being here, fix tiny typo in MAINTAINERS.
5
7
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Message-Id: <20220303194349.2304213-7-vsementsov@virtuozzo.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
Message-Id: <20200924185414.28642-6-vsementsov@virtuozzo.com>
11
---
12
---
12
block/coroutines.h | 6 +-
13
include/block/reqlist.h | 67 +++++++++++++++++++++++
13
include/block/block.h | 16 ++--
14
block/block-copy.c | 116 +++++++++++++---------------------------
14
block.c | 73 ---------------
15
block/reqlist.c | 76 ++++++++++++++++++++++++++
15
block/io.c | 212 ------------------------------------------
16
MAINTAINERS | 4 +-
16
4 files changed, 13 insertions(+), 294 deletions(-)
17
block/meson.build | 1 +
18
5 files changed, 184 insertions(+), 80 deletions(-)
19
create mode 100644 include/block/reqlist.h
20
create mode 100644 block/reqlist.c
17
21
18
diff --git a/block/coroutines.h b/block/coroutines.h
22
diff --git a/include/block/reqlist.h b/include/block/reqlist.h
23
new file mode 100644
24
index XXXXXXX..XXXXXXX
25
--- /dev/null
26
+++ b/include/block/reqlist.h
27
@@ -XXX,XX +XXX,XX @@
28
+/*
29
+ * reqlist API
30
+ *
31
+ * Copyright (C) 2013 Proxmox Server Solutions
32
+ * Copyright (c) 2021 Virtuozzo International GmbH.
33
+ *
34
+ * Authors:
35
+ * Dietmar Maurer (dietmar@proxmox.com)
36
+ * Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
37
+ *
38
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
39
+ * See the COPYING file in the top-level directory.
40
+ */
41
+
42
+#ifndef REQLIST_H
43
+#define REQLIST_H
44
+
45
+#include "qemu/coroutine.h"
46
+
47
+/*
48
+ * The API is not thread-safe and shouldn't be. The struct is public to be part
49
+ * of other structures and protected by third-party locks, see
50
+ * block/block-copy.c for example.
51
+ */
52
+
53
+typedef struct BlockReq {
54
+ int64_t offset;
55
+ int64_t bytes;
56
+
57
+ CoQueue wait_queue; /* coroutines blocked on this req */
58
+ QLIST_ENTRY(BlockReq) list;
59
+} BlockReq;
60
+
61
+typedef QLIST_HEAD(, BlockReq) BlockReqList;
62
+
63
+/*
64
+ * Initialize new request and add it to the list. Caller must be sure that
65
+ * there are no conflicting requests in the list.
66
+ */
67
+void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
68
+ int64_t bytes);
69
+/* Search for request in the list intersecting with @offset/@bytes area. */
70
+BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
71
+ int64_t bytes);
72
+
73
+/*
74
+ * If there are no intersecting requests return false. Otherwise, wait for the
75
+ * first found intersecting request to finish and return true.
76
+ *
77
+ * @lock is passed to qemu_co_queue_wait()
78
+ * False return value proves that lock was released at no point.
79
+ */
80
+bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
81
+ int64_t bytes, CoMutex *lock);
82
+
83
+/*
84
+ * Shrink request and wake all waiting coroutines (maybe some of them are not
85
+ * intersecting with shrunk request).
86
+ */
87
+void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes);
88
+
89
+/*
90
+ * Remove request and wake all waiting coroutines. Do not release any memory.
91
+ */
92
+void coroutine_fn reqlist_remove_req(BlockReq *req);
93
+
94
+#endif /* REQLIST_H */
95
diff --git a/block/block-copy.c b/block/block-copy.c
19
index XXXXXXX..XXXXXXX 100644
96
index XXXXXXX..XXXXXXX 100644
20
--- a/block/coroutines.h
97
--- a/block/block-copy.c
21
+++ b/block/coroutines.h
98
+++ b/block/block-copy.c
22
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
99
@@ -XXX,XX +XXX,XX @@
23
int coroutine_fn
100
#include "trace.h"
24
bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
101
#include "qapi/error.h"
25
bool is_write, BdrvRequestFlags flags);
102
#include "block/block-copy.h"
26
-int
103
+#include "block/reqlist.h"
27
+int generated_co_wrapper
104
#include "sysemu/block-backend.h"
28
bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
105
#include "qemu/units.h"
29
bool is_write, BdrvRequestFlags flags);
106
#include "qemu/coroutine.h"
30
107
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyTask {
31
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
108
*/
32
int64_t *pnum,
109
BlockCopyState *s;
33
int64_t *map,
110
BlockCopyCallState *call_state;
34
BlockDriverState **file);
111
- int64_t offset;
35
-int
112
/*
36
+int generated_co_wrapper
113
* @method can also be set again in the while loop of
37
bdrv_common_block_status_above(BlockDriverState *bs,
114
* block_copy_dirty_clusters(), but it is never accessed concurrently
38
BlockDriverState *base,
115
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyTask {
39
bool want_zero,
116
BlockCopyMethod method;
40
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
117
41
int coroutine_fn
118
/*
42
bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
119
- * Fields whose state changes throughout the execution
43
bool is_read);
120
- * Protected by lock in BlockCopyState.
44
-int
121
+ * Generally, req is protected by lock in BlockCopyState, Still req.offset
45
+int generated_co_wrapper
122
+ * is only set on task creation, so may be read concurrently after creation.
46
bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
123
+ * req.bytes is changed at most once, and need only protecting the case of
47
bool is_read);
124
+ * parallel read while updating @bytes value in block_copy_task_shrink().
48
125
*/
49
diff --git a/include/block/block.h b/include/block/block.h
126
- CoQueue wait_queue; /* coroutines blocked on this task */
50
index XXXXXXX..XXXXXXX 100644
127
- /*
51
--- a/include/block/block.h
128
- * Only protect the case of parallel read while updating @bytes
52
+++ b/include/block/block.h
129
- * value in block_copy_task_shrink().
53
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs);
130
- */
54
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
131
- int64_t bytes;
55
PreallocMode prealloc, BdrvRequestFlags flags,
132
- QLIST_ENTRY(BlockCopyTask) list;
56
Error **errp);
133
+ BlockReq req;
57
-int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
134
} BlockCopyTask;
58
- PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
135
59
+int generated_co_wrapper
136
static int64_t task_end(BlockCopyTask *task)
60
+bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
137
{
61
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
138
- return task->offset + task->bytes;
62
139
+ return task->req.offset + task->req.bytes;
63
int64_t bdrv_nb_sectors(BlockDriverState *bs);
64
int64_t bdrv_getlength(BlockDriverState *bs);
65
@@ -XXX,XX +XXX,XX @@ typedef enum {
66
BDRV_FIX_ERRORS = 2,
67
} BdrvCheckMode;
68
69
-int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
70
+int generated_co_wrapper bdrv_check(BlockDriverState *bs, BdrvCheckResult *res,
71
+ BdrvCheckMode fix);
72
73
/* The units of offset and total_work_size may be chosen arbitrarily by the
74
* block driver; total_work_size may change during the course of the amendment
75
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb);
76
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
77
78
/* Invalidate any cached metadata used by image formats */
79
-int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
80
+int generated_co_wrapper bdrv_invalidate_cache(BlockDriverState *bs,
81
+ Error **errp);
82
void bdrv_invalidate_cache_all(Error **errp);
83
int bdrv_inactivate_all(void);
84
85
/* Ensure contents are flushed to disk. */
86
-int bdrv_flush(BlockDriverState *bs);
87
+int generated_co_wrapper bdrv_flush(BlockDriverState *bs);
88
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
89
int bdrv_flush_all(void);
90
void bdrv_close_all(void);
91
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all(void);
92
AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \
93
cond); })
94
95
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
96
+int generated_co_wrapper bdrv_pdiscard(BdrvChild *child, int64_t offset,
97
+ int64_t bytes);
98
int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
99
int bdrv_has_zero_init_1(BlockDriverState *bs);
100
int bdrv_has_zero_init(BlockDriverState *bs);
101
diff --git a/block.c b/block.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block.c
104
+++ b/block.c
105
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
106
return bs->drv->bdrv_co_check(bs, res, fix);
107
}
140
}
108
141
109
-typedef struct CheckCo {
142
typedef struct BlockCopyState {
110
- BlockDriverState *bs;
143
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
111
- BdrvCheckResult *res;
144
CoMutex lock;
112
- BdrvCheckMode fix;
145
int64_t in_flight_bytes;
113
- int ret;
146
BlockCopyMethod method;
114
-} CheckCo;
147
- QLIST_HEAD(, BlockCopyTask) tasks; /* All tasks from all block-copy calls */
115
-
148
+ BlockReqList reqs;
116
-static void coroutine_fn bdrv_check_co_entry(void *opaque)
149
QLIST_HEAD(, BlockCopyCallState) calls;
150
/*
151
* skip_unallocated:
152
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyState {
153
RateLimit rate_limit;
154
} BlockCopyState;
155
156
-/* Called with lock held */
157
-static BlockCopyTask *find_conflicting_task(BlockCopyState *s,
158
- int64_t offset, int64_t bytes)
117
-{
159
-{
118
- CheckCo *cco = opaque;
160
- BlockCopyTask *t;
119
- cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
161
-
120
- aio_wait_kick();
162
- QLIST_FOREACH(t, &s->tasks, list) {
163
- if (offset + bytes > t->offset && offset < t->offset + t->bytes) {
164
- return t;
165
- }
166
- }
167
-
168
- return NULL;
121
-}
169
-}
122
-
170
-
123
-int bdrv_check(BlockDriverState *bs,
171
-/*
124
- BdrvCheckResult *res, BdrvCheckMode fix)
172
- * If there are no intersecting tasks return false. Otherwise, wait for the
173
- * first found intersecting tasks to finish and return true.
174
- *
175
- * Called with lock held. May temporary release the lock.
176
- * Return value of 0 proves that lock was NOT released.
177
- */
178
-static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
179
- int64_t bytes)
125
-{
180
-{
126
- Coroutine *co;
181
- BlockCopyTask *task = find_conflicting_task(s, offset, bytes);
127
- CheckCo cco = {
182
-
128
- .bs = bs,
183
- if (!task) {
129
- .res = res,
184
- return false;
130
- .ret = -EINPROGRESS,
131
- .fix = fix,
132
- };
133
-
134
- if (qemu_in_coroutine()) {
135
- /* Fast-path if already in coroutine context */
136
- bdrv_check_co_entry(&cco);
137
- } else {
138
- co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
139
- bdrv_coroutine_enter(bs, co);
140
- BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
141
- }
185
- }
142
-
186
-
143
- return cco.ret;
187
- qemu_co_queue_wait(&task->wait_queue, &s->lock);
188
-
189
- return true;
144
-}
190
-}
145
-
191
-
146
/*
192
/* Called with lock held */
147
* Return values:
193
static int64_t block_copy_chunk_size(BlockCopyState *s)
148
* 0 - success
149
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp)
150
return 0;
151
}
152
153
-typedef struct InvalidateCacheCo {
154
- BlockDriverState *bs;
155
- Error **errp;
156
- bool done;
157
- int ret;
158
-} InvalidateCacheCo;
159
-
160
-static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
161
-{
162
- InvalidateCacheCo *ico = opaque;
163
- ico->ret = bdrv_co_invalidate_cache(ico->bs, ico->errp);
164
- ico->done = true;
165
- aio_wait_kick();
166
-}
167
-
168
-int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
169
-{
170
- Coroutine *co;
171
- InvalidateCacheCo ico = {
172
- .bs = bs,
173
- .done = false,
174
- .errp = errp
175
- };
176
-
177
- if (qemu_in_coroutine()) {
178
- /* Fast-path if already in coroutine context */
179
- bdrv_invalidate_cache_co_entry(&ico);
180
- } else {
181
- co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico);
182
- bdrv_coroutine_enter(bs, co);
183
- BDRV_POLL_WHILE(bs, !ico.done);
184
- }
185
-
186
- return ico.ret;
187
-}
188
-
189
void bdrv_invalidate_cache_all(Error **errp)
190
{
194
{
191
BlockDriverState *bs;
195
@@ -XXX,XX +XXX,XX @@ block_copy_task_create(BlockCopyState *s, BlockCopyCallState *call_state,
192
diff --git a/block/io.c b/block/io.c
196
bytes = QEMU_ALIGN_UP(bytes, s->cluster_size);
193
index XXXXXXX..XXXXXXX 100644
197
194
--- a/block/io.c
198
/* region is dirty, so no existent tasks possible in it */
195
+++ b/block/io.c
199
- assert(!find_conflicting_task(s, offset, bytes));
196
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
200
+ assert(!reqlist_find_conflict(&s->reqs, offset, bytes));
197
return 0;
201
198
}
202
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
199
203
s->in_flight_bytes += bytes;
200
-typedef int coroutine_fn BdrvRequestEntry(void *opaque);
204
@@ -XXX,XX +XXX,XX @@ block_copy_task_create(BlockCopyState *s, BlockCopyCallState *call_state,
201
-typedef struct BdrvRunCo {
205
.task.func = block_copy_task_entry,
202
- BdrvRequestEntry *entry;
206
.s = s,
203
- void *opaque;
207
.call_state = call_state,
204
- int ret;
205
- bool done;
206
- Coroutine *co; /* Coroutine, running bdrv_run_co_entry, for debugging */
207
-} BdrvRunCo;
208
-
209
-static void coroutine_fn bdrv_run_co_entry(void *opaque)
210
-{
211
- BdrvRunCo *arg = opaque;
212
-
213
- arg->ret = arg->entry(arg->opaque);
214
- arg->done = true;
215
- aio_wait_kick();
216
-}
217
-
218
-static int bdrv_run_co(BlockDriverState *bs, BdrvRequestEntry *entry,
219
- void *opaque)
220
-{
221
- if (qemu_in_coroutine()) {
222
- /* Fast-path if already in coroutine context */
223
- return entry(opaque);
224
- } else {
225
- BdrvRunCo s = { .entry = entry, .opaque = opaque };
226
-
227
- s.co = qemu_coroutine_create(bdrv_run_co_entry, &s);
228
- bdrv_coroutine_enter(bs, s.co);
229
-
230
- BDRV_POLL_WHILE(bs, !s.done);
231
-
232
- return s.ret;
233
- }
234
-}
235
-
236
-typedef struct RwCo {
237
- BdrvChild *child;
238
- int64_t offset;
239
- QEMUIOVector *qiov;
240
- bool is_write;
241
- BdrvRequestFlags flags;
242
-} RwCo;
243
-
244
int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
245
QEMUIOVector *qiov, bool is_write,
246
BdrvRequestFlags flags)
247
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
248
}
249
}
250
251
-static int coroutine_fn bdrv_rw_co_entry(void *opaque)
252
-{
253
- RwCo *rwco = opaque;
254
-
255
- return bdrv_co_prwv(rwco->child, rwco->offset, rwco->qiov,
256
- rwco->is_write, rwco->flags);
257
-}
258
-
259
-/*
260
- * Process a vectored synchronous request using coroutines
261
- */
262
-int bdrv_prwv(BdrvChild *child, int64_t offset,
263
- QEMUIOVector *qiov, bool is_write,
264
- BdrvRequestFlags flags)
265
-{
266
- RwCo rwco = {
267
- .child = child,
268
- .offset = offset,
269
- .qiov = qiov,
270
- .is_write = is_write,
271
- .flags = flags,
272
- };
273
-
274
- return bdrv_run_co(child->bs, bdrv_rw_co_entry, &rwco);
275
-}
276
-
277
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
278
int bytes, BdrvRequestFlags flags)
279
{
280
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
281
return result;
282
}
283
284
-
285
-typedef struct BdrvCoBlockStatusData {
286
- BlockDriverState *bs;
287
- BlockDriverState *base;
288
- bool want_zero;
289
- int64_t offset;
290
- int64_t bytes;
291
- int64_t *pnum;
292
- int64_t *map;
293
- BlockDriverState **file;
294
-} BdrvCoBlockStatusData;
295
-
296
/*
297
* Returns the allocation status of the specified sectors.
298
* Drivers not implementing the functionality are assumed to not support
299
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
300
return ret;
301
}
302
303
-/* Coroutine wrapper for bdrv_block_status_above() */
304
-static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
305
-{
306
- BdrvCoBlockStatusData *data = opaque;
307
-
308
- return bdrv_co_common_block_status_above(data->bs, data->base,
309
- data->want_zero,
310
- data->offset, data->bytes,
311
- data->pnum, data->map, data->file);
312
-}
313
-
314
-/*
315
- * Synchronous wrapper around bdrv_co_block_status_above().
316
- *
317
- * See bdrv_co_block_status_above() for details.
318
- */
319
-int bdrv_common_block_status_above(BlockDriverState *bs,
320
- BlockDriverState *base,
321
- bool want_zero, int64_t offset,
322
- int64_t bytes, int64_t *pnum,
323
- int64_t *map,
324
- BlockDriverState **file)
325
-{
326
- BdrvCoBlockStatusData data = {
327
- .bs = bs,
328
- .base = base,
329
- .want_zero = want_zero,
330
- .offset = offset,
208
- .offset = offset,
331
- .bytes = bytes,
209
- .bytes = bytes,
332
- .pnum = pnum,
210
.method = s->method,
333
- .map = map,
211
};
334
- .file = file,
212
- qemu_co_queue_init(&task->wait_queue);
335
- };
213
- QLIST_INSERT_HEAD(&s->tasks, task, list);
336
-
214
+ reqlist_init_req(&s->reqs, &task->req, offset, bytes);
337
- return bdrv_run_co(bs, bdrv_block_status_above_co_entry, &data);
215
338
-}
216
return task;
339
-
340
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
341
int64_t offset, int64_t bytes, int64_t *pnum,
342
int64_t *map, BlockDriverState **file)
343
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top,
344
return 0;
345
}
217
}
346
218
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn block_copy_task_shrink(BlockCopyTask *task,
347
-typedef struct BdrvVmstateCo {
219
int64_t new_bytes)
348
- BlockDriverState *bs;
220
{
349
- QEMUIOVector *qiov;
221
QEMU_LOCK_GUARD(&task->s->lock);
350
- int64_t pos;
222
- if (new_bytes == task->bytes) {
351
- bool is_read;
223
+ if (new_bytes == task->req.bytes) {
352
-} BdrvVmstateCo;
224
return;
353
-
225
}
354
int coroutine_fn
226
355
bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
227
- assert(new_bytes > 0 && new_bytes < task->bytes);
356
bool is_read)
228
+ assert(new_bytes > 0 && new_bytes < task->req.bytes);
357
@@ -XXX,XX +XXX,XX @@ bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
229
230
- task->s->in_flight_bytes -= task->bytes - new_bytes;
231
+ task->s->in_flight_bytes -= task->req.bytes - new_bytes;
232
bdrv_set_dirty_bitmap(task->s->copy_bitmap,
233
- task->offset + new_bytes, task->bytes - new_bytes);
234
+ task->req.offset + new_bytes,
235
+ task->req.bytes - new_bytes);
236
237
- task->bytes = new_bytes;
238
- qemu_co_queue_restart_all(&task->wait_queue);
239
+ reqlist_shrink_req(&task->req, new_bytes);
240
}
241
242
static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret)
243
{
244
QEMU_LOCK_GUARD(&task->s->lock);
245
- task->s->in_flight_bytes -= task->bytes;
246
+ task->s->in_flight_bytes -= task->req.bytes;
247
if (ret < 0) {
248
- bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes);
249
+ bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->req.offset,
250
+ task->req.bytes);
251
}
252
- QLIST_REMOVE(task, list);
253
if (task->s->progress) {
254
progress_set_remaining(task->s->progress,
255
bdrv_get_dirty_count(task->s->copy_bitmap) +
256
task->s->in_flight_bytes);
257
}
258
- qemu_co_queue_restart_all(&task->wait_queue);
259
+ reqlist_remove_req(&task->req);
260
}
261
262
void block_copy_state_free(BlockCopyState *s)
263
@@ -XXX,XX +XXX,XX @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
264
265
ratelimit_init(&s->rate_limit);
266
qemu_co_mutex_init(&s->lock);
267
- QLIST_INIT(&s->tasks);
268
+ QLIST_INIT(&s->reqs);
269
QLIST_INIT(&s->calls);
270
271
return s;
272
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_run(AioTaskPool *pool,
273
274
aio_task_pool_wait_slot(pool);
275
if (aio_task_pool_status(pool) < 0) {
276
- co_put_to_shres(task->s->mem, task->bytes);
277
+ co_put_to_shres(task->s->mem, task->req.bytes);
278
block_copy_task_end(task, -ECANCELED);
279
g_free(task);
280
return -ECANCELED;
281
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
282
BlockCopyMethod method = t->method;
283
int ret;
284
285
- ret = block_copy_do_copy(s, t->offset, t->bytes, &method, &error_is_read);
286
+ ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method,
287
+ &error_is_read);
288
289
WITH_QEMU_LOCK_GUARD(&s->lock) {
290
if (s->method == t->method) {
291
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
292
t->call_state->error_is_read = error_is_read;
293
}
294
} else if (s->progress) {
295
- progress_work_done(s->progress, t->bytes);
296
+ progress_work_done(s->progress, t->req.bytes);
297
}
298
}
299
- co_put_to_shres(s->mem, t->bytes);
300
+ co_put_to_shres(s->mem, t->req.bytes);
301
block_copy_task_end(t, ret);
302
358
return ret;
303
return ret;
359
}
304
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
360
305
trace_block_copy_skip_range(s, offset, bytes);
361
-static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
306
break;
362
-{
307
}
363
- BdrvVmstateCo *co = opaque;
308
- if (task->offset > offset) {
364
-
309
- trace_block_copy_skip_range(s, offset, task->offset - offset);
365
- return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
310
+ if (task->req.offset > offset) {
366
-}
311
+ trace_block_copy_skip_range(s, offset, task->req.offset - offset);
367
-
312
}
368
-int bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
313
369
- bool is_read)
314
found_dirty = true;
370
-{
315
371
- BdrvVmstateCo data = {
316
- ret = block_copy_block_status(s, task->offset, task->bytes,
372
- .bs = bs,
317
+ ret = block_copy_block_status(s, task->req.offset, task->req.bytes,
373
- .qiov = qiov,
318
&status_bytes);
374
- .pos = pos,
319
assert(ret >= 0); /* never fail */
375
- .is_read = is_read,
320
- if (status_bytes < task->bytes) {
376
- };
321
+ if (status_bytes < task->req.bytes) {
377
-
322
block_copy_task_shrink(task, status_bytes);
378
- return bdrv_run_co(bs, bdrv_co_rw_vmstate_entry, &data);
323
}
379
-}
324
if (qatomic_read(&s->skip_unallocated) &&
380
-
325
!(ret & BDRV_BLOCK_ALLOCATED)) {
381
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
326
block_copy_task_end(task, 0);
382
int64_t pos, int size)
327
- trace_block_copy_skip_range(s, task->offset, task->bytes);
383
{
328
+ trace_block_copy_skip_range(s, task->req.offset, task->req.bytes);
384
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb)
329
offset = task_end(task);
385
/**************************************************************/
330
bytes = end - offset;
386
/* Coroutine block device emulation */
331
g_free(task);
387
332
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
388
-static int coroutine_fn bdrv_flush_co_entry(void *opaque)
333
}
389
-{
334
}
390
- return bdrv_co_flush(opaque);
335
391
-}
336
- ratelimit_calculate_delay(&s->rate_limit, task->bytes);
392
-
337
+ ratelimit_calculate_delay(&s->rate_limit, task->req.bytes);
393
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
338
394
{
339
- trace_block_copy_process(s, task->offset);
395
BdrvChild *primary_child = bdrv_primary_child(bs);
340
+ trace_block_copy_process(s, task->req.offset);
396
@@ -XXX,XX +XXX,XX @@ early_exit:
341
397
return ret;
342
- co_get_from_shres(s->mem, task->bytes);
398
}
343
+ co_get_from_shres(s->mem, task->req.bytes);
399
344
400
-int bdrv_flush(BlockDriverState *bs)
345
offset = task_end(task);
401
-{
346
bytes = end - offset;
402
- return bdrv_run_co(bs, bdrv_flush_co_entry, bs);
347
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
403
-}
348
* Check that there is no task we still need to
404
-
349
* wait to complete
405
-typedef struct DiscardCo {
350
*/
406
- BdrvChild *child;
351
- ret = block_copy_wait_one(s, call_state->offset,
407
- int64_t offset;
352
- call_state->bytes);
408
- int64_t bytes;
353
+ ret = reqlist_wait_one(&s->reqs, call_state->offset,
409
-} DiscardCo;
354
+ call_state->bytes, &s->lock);
410
-
355
if (ret == 0) {
411
-static int coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
356
/*
412
-{
357
* No pending tasks, but check again the bitmap in this
413
- DiscardCo *rwco = opaque;
358
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
414
-
359
* between this and the critical section in
415
- return bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
360
* block_copy_dirty_clusters().
416
-}
361
*
417
-
362
- * block_copy_wait_one return value 0 also means that it
418
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
363
+ * reqlist_wait_one return value 0 also means that it
419
int64_t bytes)
364
* didn't release the lock. So, we are still in the same
420
{
365
* critical section, not interrupted by any concurrent
421
@@ -XXX,XX +XXX,XX @@ out:
366
* access to state.
422
return ret;
367
diff --git a/block/reqlist.c b/block/reqlist.c
423
}
368
new file mode 100644
424
369
index XXXXXXX..XXXXXXX
425
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
370
--- /dev/null
426
-{
371
+++ b/block/reqlist.c
427
- DiscardCo rwco = {
372
@@ -XXX,XX +XXX,XX @@
428
- .child = child,
373
+/*
429
- .offset = offset,
374
+ * reqlist API
430
- .bytes = bytes,
375
+ *
431
- };
376
+ * Copyright (C) 2013 Proxmox Server Solutions
432
-
377
+ * Copyright (c) 2021 Virtuozzo International GmbH.
433
- return bdrv_run_co(child->bs, bdrv_pdiscard_co_entry, &rwco);
378
+ *
434
-}
379
+ * Authors:
435
-
380
+ * Dietmar Maurer (dietmar@proxmox.com)
436
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
381
+ * Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
437
{
382
+ *
438
BlockDriver *drv = bs->drv;
383
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
439
@@ -XXX,XX +XXX,XX @@ out:
384
+ * See the COPYING file in the top-level directory.
440
385
+ */
441
return ret;
386
+
442
}
387
+#include "qemu/osdep.h"
443
-
388
+
444
-typedef struct TruncateCo {
389
+#include "block/reqlist.h"
445
- BdrvChild *child;
390
+
446
- int64_t offset;
391
+void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
447
- bool exact;
392
+ int64_t bytes)
448
- PreallocMode prealloc;
393
+{
449
- BdrvRequestFlags flags;
394
+ assert(!reqlist_find_conflict(reqs, offset, bytes));
450
- Error **errp;
395
+
451
-} TruncateCo;
396
+ *req = (BlockReq) {
452
-
397
+ .offset = offset,
453
-static int coroutine_fn bdrv_truncate_co_entry(void *opaque)
398
+ .bytes = bytes,
454
-{
399
+ };
455
- TruncateCo *tco = opaque;
400
+ qemu_co_queue_init(&req->wait_queue);
456
-
401
+ QLIST_INSERT_HEAD(reqs, req, list);
457
- return bdrv_co_truncate(tco->child, tco->offset, tco->exact,
402
+}
458
- tco->prealloc, tco->flags, tco->errp);
403
+
459
-}
404
+BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
460
-
405
+ int64_t bytes)
461
-int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
406
+{
462
- PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
407
+ BlockReq *r;
463
-{
408
+
464
- TruncateCo tco = {
409
+ QLIST_FOREACH(r, reqs, list) {
465
- .child = child,
410
+ if (offset + bytes > r->offset && offset < r->offset + r->bytes) {
466
- .offset = offset,
411
+ return r;
467
- .exact = exact,
412
+ }
468
- .prealloc = prealloc,
413
+ }
469
- .flags = flags,
414
+
470
- .errp = errp,
415
+ return NULL;
471
- };
416
+}
472
-
417
+
473
- return bdrv_run_co(child->bs, bdrv_truncate_co_entry, &tco);
418
+bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
474
-}
419
+ int64_t bytes, CoMutex *lock)
420
+{
421
+ BlockReq *r = reqlist_find_conflict(reqs, offset, bytes);
422
+
423
+ if (!r) {
424
+ return false;
425
+ }
426
+
427
+ qemu_co_queue_wait(&r->wait_queue, lock);
428
+
429
+ return true;
430
+}
431
+
432
+void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes)
433
+{
434
+ if (new_bytes == req->bytes) {
435
+ return;
436
+ }
437
+
438
+ assert(new_bytes > 0 && new_bytes < req->bytes);
439
+
440
+ req->bytes = new_bytes;
441
+ qemu_co_queue_restart_all(&req->wait_queue);
442
+}
443
+
444
+void coroutine_fn reqlist_remove_req(BlockReq *req)
445
+{
446
+ QLIST_REMOVE(req, list);
447
+ qemu_co_queue_restart_all(&req->wait_queue);
448
+}
449
diff --git a/MAINTAINERS b/MAINTAINERS
450
index XXXXXXX..XXXXXXX 100644
451
--- a/MAINTAINERS
452
+++ b/MAINTAINERS
453
@@ -XXX,XX +XXX,XX @@ F: block/stream.c
454
F: block/mirror.c
455
F: qapi/job.json
456
F: block/block-copy.c
457
-F: include/block/block-copy.c
458
+F: include/block/block-copy.h
459
+F: block/reqlist.c
460
+F: include/block/reqlist.h
461
F: block/copy-before-write.h
462
F: block/copy-before-write.c
463
F: include/block/aio_task.h
464
diff --git a/block/meson.build b/block/meson.build
465
index XXXXXXX..XXXXXXX 100644
466
--- a/block/meson.build
467
+++ b/block/meson.build
468
@@ -XXX,XX +XXX,XX @@ block_ss.add(files(
469
'qcow2.c',
470
'quorum.c',
471
'raw-format.c',
472
+ 'reqlist.c',
473
'snapshot.c',
474
'throttle-groups.c',
475
'throttle.c',
475
--
476
--
476
2.26.2
477
2.34.1
477
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Per the datasheet sections 3.1.13/3.1.14:
3
Let's reuse convenient helper.
4
"The host should not read the doorbell registers."
5
4
6
As we don't need read access, map the doorbells with write-only
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
permission. We keep a reference to this mapped address in the
6
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
BDRVNVMeState structure.
7
Message-Id: <20220303194349.2304213-8-vsementsov@virtuozzo.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
10
block/reqlist.c | 3 ++-
11
1 file changed, 2 insertions(+), 1 deletion(-)
9
12
10
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
diff --git a/block/reqlist.c b/block/reqlist.c
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200922083821.578519-3-philmd@redhat.com>
13
---
14
block/nvme.c | 29 +++++++++++++++++++----------
15
1 file changed, 19 insertions(+), 10 deletions(-)
16
17
diff --git a/block/nvme.c b/block/nvme.c
18
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
19
--- a/block/nvme.c
15
--- a/block/reqlist.c
20
+++ b/block/nvme.c
16
+++ b/block/reqlist.c
21
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@
22
#define NVME_SQ_ENTRY_BYTES 64
18
*/
23
#define NVME_CQ_ENTRY_BYTES 16
19
24
#define NVME_QUEUE_SIZE 128
20
#include "qemu/osdep.h"
25
-#define NVME_BAR_SIZE 8192
21
+#include "qemu/range.h"
26
+#define NVME_DOORBELL_SIZE 4096
22
27
23
#include "block/reqlist.h"
28
/*
24
29
* We have to leave one slot empty as that is the full queue case where
25
@@ -XXX,XX +XXX,XX @@ BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
26
BlockReq *r;
31
/* Memory mapped registers */
27
32
typedef volatile struct {
28
QLIST_FOREACH(r, reqs, list) {
33
NvmeBar ctrl;
29
- if (offset + bytes > r->offset && offset < r->offset + r->bytes) {
34
- struct {
30
+ if (ranges_overlap(offset, bytes, r->offset, r->bytes)) {
35
- uint32_t sq_tail;
31
return r;
36
- uint32_t cq_head;
37
- } doorbells[];
38
} NVMeRegs;
39
40
#define INDEX_ADMIN 0
41
@@ -XXX,XX +XXX,XX @@ struct BDRVNVMeState {
42
AioContext *aio_context;
43
QEMUVFIOState *vfio;
44
NVMeRegs *regs;
45
+ /* Memory mapped registers */
46
+ volatile struct {
47
+ uint32_t sq_tail;
48
+ uint32_t cq_head;
49
+ } *doorbells;
50
/* The submission/completion queue pairs.
51
* [0]: admin queue.
52
* [1..]: io queues.
53
@@ -XXX,XX +XXX,XX @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
54
error_propagate(errp, local_err);
55
goto fail;
56
}
57
- q->sq.doorbell = &s->regs->doorbells[idx * s->doorbell_scale].sq_tail;
58
+ q->sq.doorbell = &s->doorbells[idx * s->doorbell_scale].sq_tail;
59
60
nvme_init_queue(s, &q->cq, size, NVME_CQ_ENTRY_BYTES, &local_err);
61
if (local_err) {
62
error_propagate(errp, local_err);
63
goto fail;
64
}
65
- q->cq.doorbell = &s->regs->doorbells[idx * s->doorbell_scale].cq_head;
66
+ q->cq.doorbell = &s->doorbells[idx * s->doorbell_scale].cq_head;
67
68
return q;
69
fail:
70
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
71
goto out;
72
}
73
74
- s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE,
75
+ s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, sizeof(NvmeBar),
76
PROT_READ | PROT_WRITE, errp);
77
if (!s->regs) {
78
ret = -EINVAL;
79
goto out;
80
}
81
-
82
/* Perform initialize sequence as described in NVMe spec "7.6.1
83
* Initialization". */
84
85
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
86
}
32
}
87
}
33
}
88
89
+ s->doorbells = qemu_vfio_pci_map_bar(s->vfio, 0, sizeof(NvmeBar),
90
+ NVME_DOORBELL_SIZE, PROT_WRITE, errp);
91
+ if (!s->doorbells) {
92
+ ret = -EINVAL;
93
+ goto out;
94
+ }
95
+
96
/* Set up admin queue. */
97
s->queues = g_new(NVMeQueuePair *, 1);
98
s->queues[INDEX_ADMIN] = nvme_create_queue_pair(s, aio_context, 0,
99
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
100
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
101
false, NULL, NULL);
102
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
103
- qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE);
104
+ qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->doorbells,
105
+ sizeof(NvmeBar), NVME_DOORBELL_SIZE);
106
+ qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, sizeof(NvmeBar));
107
qemu_vfio_close(s->vfio);
108
109
g_free(s->device);
110
--
34
--
111
2.26.2
35
2.34.1
112
diff view generated by jsdifflib
1
From: Eric Auger <eric.auger@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Introduce the qemu_vfio_find_fixed/temp_iova helpers which
3
Add a convenient function similar with bdrv_block_status() to get
4
respectively allocate IOVAs from the bottom/top parts of the
4
status of dirty bitmap.
5
usable IOVA range, without picking within host IOVA reserved
6
windows. The allocation remains basic: if the size is too big
7
for the remaining of the current usable IOVA range, we jump
8
to the next one, leaving a hole in the address map.
9
5
10
Signed-off-by: Eric Auger <eric.auger@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-id: 20200929085550.30926-3-eric.auger@redhat.com
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20220303194349.2304213-9-vsementsov@virtuozzo.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
---
10
---
14
util/vfio-helpers.c | 57 +++++++++++++++++++++++++++++++++++++++++----
11
include/block/dirty-bitmap.h | 2 ++
15
1 file changed, 53 insertions(+), 4 deletions(-)
12
include/qemu/hbitmap.h | 12 ++++++++++++
13
block/dirty-bitmap.c | 6 ++++++
14
util/hbitmap.c | 33 +++++++++++++++++++++++++++++++++
15
4 files changed, 53 insertions(+)
16
16
17
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
17
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/util/vfio-helpers.c
19
--- a/include/block/dirty-bitmap.h
20
+++ b/util/vfio-helpers.c
20
+++ b/include/block/dirty-bitmap.h
21
@@ -XXX,XX +XXX,XX @@ static bool qemu_vfio_verify_mappings(QEMUVFIOState *s)
21
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, int64_t offset,
22
bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
23
int64_t start, int64_t end, int64_t max_dirty_count,
24
int64_t *dirty_start, int64_t *dirty_count);
25
+bool bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap, int64_t offset,
26
+ int64_t bytes, int64_t *count);
27
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
28
Error **errp);
29
30
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/qemu/hbitmap.h
33
+++ b/include/qemu/hbitmap.h
34
@@ -XXX,XX +XXX,XX @@ bool hbitmap_next_dirty_area(const HBitmap *hb, int64_t start, int64_t end,
35
int64_t max_dirty_count,
36
int64_t *dirty_start, int64_t *dirty_count);
37
38
+/*
39
+ * bdrv_dirty_bitmap_status:
40
+ * @hb: The HBitmap to operate on
41
+ * @start: The bit to start from
42
+ * @count: Number of bits to proceed
43
+ * @pnum: Out-parameter. How many bits has same value starting from @start
44
+ *
45
+ * Returns true if bitmap is dirty at @start, false otherwise.
46
+ */
47
+bool hbitmap_status(const HBitmap *hb, int64_t start, int64_t count,
48
+ int64_t *pnum);
49
+
50
/**
51
* hbitmap_iter_next:
52
* @hbi: HBitmapIter to operate on.
53
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/dirty-bitmap.c
56
+++ b/block/dirty-bitmap.c
57
@@ -XXX,XX +XXX,XX @@ bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
58
dirty_start, dirty_count);
59
}
60
61
+bool bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap, int64_t offset,
62
+ int64_t bytes, int64_t *count)
63
+{
64
+ return hbitmap_status(bitmap->bitmap, offset, bytes, count);
65
+}
66
+
67
/**
68
* bdrv_merge_dirty_bitmap: merge src into dest.
69
* Ensures permissions on bitmaps are reasonable; use for public API.
70
diff --git a/util/hbitmap.c b/util/hbitmap.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/util/hbitmap.c
73
+++ b/util/hbitmap.c
74
@@ -XXX,XX +XXX,XX @@ bool hbitmap_next_dirty_area(const HBitmap *hb, int64_t start, int64_t end,
22
return true;
75
return true;
23
}
76
}
24
77
25
+static int
78
+bool hbitmap_status(const HBitmap *hb, int64_t start, int64_t count,
26
+qemu_vfio_find_fixed_iova(QEMUVFIOState *s, size_t size, uint64_t *iova)
79
+ int64_t *pnum)
27
+{
80
+{
28
+ int i;
81
+ int64_t next_dirty, next_zero;
29
+
82
+
30
+ for (i = 0; i < s->nb_iova_ranges; i++) {
83
+ assert(start >= 0);
31
+ if (s->usable_iova_ranges[i].end < s->low_water_mark) {
84
+ assert(count > 0);
32
+ continue;
85
+ assert(start + count <= hb->orig_size);
33
+ }
34
+ s->low_water_mark =
35
+ MAX(s->low_water_mark, s->usable_iova_ranges[i].start);
36
+
86
+
37
+ if (s->usable_iova_ranges[i].end - s->low_water_mark + 1 >= size ||
87
+ next_dirty = hbitmap_next_dirty(hb, start, count);
38
+ s->usable_iova_ranges[i].end - s->low_water_mark + 1 == 0) {
88
+ if (next_dirty == -1) {
39
+ *iova = s->low_water_mark;
89
+ *pnum = count;
40
+ s->low_water_mark += size;
90
+ return false;
41
+ return 0;
42
+ }
43
+ }
91
+ }
44
+ return -ENOMEM;
92
+
93
+ if (next_dirty > start) {
94
+ *pnum = next_dirty - start;
95
+ return false;
96
+ }
97
+
98
+ assert(next_dirty == start);
99
+
100
+ next_zero = hbitmap_next_zero(hb, start, count);
101
+ if (next_zero == -1) {
102
+ *pnum = count;
103
+ return true;
104
+ }
105
+
106
+ assert(next_zero > start);
107
+ *pnum = next_zero - start;
108
+ return false;
45
+}
109
+}
46
+
110
+
47
+static int
111
bool hbitmap_empty(const HBitmap *hb)
48
+qemu_vfio_find_temp_iova(QEMUVFIOState *s, size_t size, uint64_t *iova)
112
{
49
+{
113
return hb->count == 0;
50
+ int i;
51
+
52
+ for (i = s->nb_iova_ranges - 1; i >= 0; i--) {
53
+ if (s->usable_iova_ranges[i].start > s->high_water_mark) {
54
+ continue;
55
+ }
56
+ s->high_water_mark =
57
+ MIN(s->high_water_mark, s->usable_iova_ranges[i].end + 1);
58
+
59
+ if (s->high_water_mark - s->usable_iova_ranges[i].start + 1 >= size ||
60
+ s->high_water_mark - s->usable_iova_ranges[i].start + 1 == 0) {
61
+ *iova = s->high_water_mark - size;
62
+ s->high_water_mark = *iova;
63
+ return 0;
64
+ }
65
+ }
66
+ return -ENOMEM;
67
+}
68
+
69
/* Map [host, host + size) area into a contiguous IOVA address space, and store
70
* the result in @iova if not NULL. The caller need to make sure the area is
71
* aligned to page size, and mustn't overlap with existing mapping areas (split
72
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size,
73
goto out;
74
}
75
if (!temporary) {
76
- iova0 = s->low_water_mark;
77
+ if (qemu_vfio_find_fixed_iova(s, size, &iova0)) {
78
+ ret = -ENOMEM;
79
+ goto out;
80
+ }
81
+
82
mapping = qemu_vfio_add_mapping(s, host, size, index + 1, iova0);
83
if (!mapping) {
84
ret = -ENOMEM;
85
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size,
86
qemu_vfio_undo_mapping(s, mapping, NULL);
87
goto out;
88
}
89
- s->low_water_mark += size;
90
qemu_vfio_dump_mappings(s);
91
} else {
92
- iova0 = s->high_water_mark - size;
93
+ if (qemu_vfio_find_temp_iova(s, size, &iova0)) {
94
+ ret = -ENOMEM;
95
+ goto out;
96
+ }
97
ret = qemu_vfio_do_mapping(s, host, size, iova0);
98
if (ret) {
99
goto out;
100
}
101
- s->high_water_mark -= size;
102
}
103
}
104
if (iova) {
105
--
114
--
106
2.26.2
115
2.34.1
107
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Most of our coroutine wrappers already follow this convention:
3
Add function to wait for all intersecting requests.
4
4
To be used in the further commit.
5
We have 'coroutine_fn bdrv_co_<something>(<normal argument list>)' as
6
the core function, and a wrapper 'bdrv_<something>(<same argument
7
list>)' which does parameter packing and calls bdrv_run_co().
8
9
The only outsiders are the bdrv_prwv_co and
10
bdrv_common_block_status_above wrappers. Let's refactor them to behave
11
as the others, it simplifies further conversion of coroutine wrappers.
12
13
This patch adds an indirection layer, but it will be compensated by
14
a further commit, which will drop bdrv_co_prwv together with the
15
is_write logic, to keep the read and write paths separate.
16
5
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Nikita Lapshin <nikita.lapshin@virtuozzo.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
20
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-Id: <20220303194349.2304213-10-vsementsov@virtuozzo.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
22
Message-Id: <20200924185414.28642-3-vsementsov@virtuozzo.com>
23
---
11
---
24
block/io.c | 60 +++++++++++++++++++++++++++++-------------------------
12
include/block/reqlist.h | 8 ++++++++
25
1 file changed, 32 insertions(+), 28 deletions(-)
13
block/reqlist.c | 8 ++++++++
14
2 files changed, 16 insertions(+)
26
15
27
diff --git a/block/io.c b/block/io.c
16
diff --git a/include/block/reqlist.h b/include/block/reqlist.h
28
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
29
--- a/block/io.c
18
--- a/include/block/reqlist.h
30
+++ b/block/io.c
19
+++ b/include/block/reqlist.h
31
@@ -XXX,XX +XXX,XX @@ typedef struct RwCo {
20
@@ -XXX,XX +XXX,XX @@ BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
32
BdrvRequestFlags flags;
21
bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
33
} RwCo;
22
int64_t bytes, CoMutex *lock);
34
23
35
+static int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
24
+/*
36
+ QEMUIOVector *qiov, bool is_write,
25
+ * Wait for all intersecting requests. It just calls reqlist_wait_one() in a
37
+ BdrvRequestFlags flags)
26
+ * loop, caller is responsible to stop producing new requests in this region
27
+ * in parallel, otherwise reqlist_wait_all() may never return.
28
+ */
29
+void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
30
+ int64_t bytes, CoMutex *lock);
31
+
32
/*
33
* Shrink request and wake all waiting coroutines (maybe some of them are not
34
* intersecting with shrunk request).
35
diff --git a/block/reqlist.c b/block/reqlist.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/reqlist.c
38
+++ b/block/reqlist.c
39
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
40
return true;
41
}
42
43
+void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
44
+ int64_t bytes, CoMutex *lock)
38
+{
45
+{
39
+ if (is_write) {
46
+ while (reqlist_wait_one(reqs, offset, bytes, lock)) {
40
+ return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
47
+ /* continue */
41
+ } else {
42
+ return bdrv_co_preadv(child, offset, qiov->size, qiov, flags);
43
+ }
48
+ }
44
+}
49
+}
45
+
50
+
46
static int coroutine_fn bdrv_rw_co_entry(void *opaque)
51
void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes)
47
{
52
{
48
RwCo *rwco = opaque;
53
if (new_bytes == req->bytes) {
49
50
- if (!rwco->is_write) {
51
- return bdrv_co_preadv(rwco->child, rwco->offset,
52
- rwco->qiov->size, rwco->qiov,
53
- rwco->flags);
54
- } else {
55
- return bdrv_co_pwritev(rwco->child, rwco->offset,
56
- rwco->qiov->size, rwco->qiov,
57
- rwco->flags);
58
- }
59
+ return bdrv_co_prwv(rwco->child, rwco->offset, rwco->qiov,
60
+ rwco->is_write, rwco->flags);
61
}
62
63
/*
64
* Process a vectored synchronous request using coroutines
65
*/
66
-static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
67
- QEMUIOVector *qiov, bool is_write,
68
- BdrvRequestFlags flags)
69
+static int bdrv_prwv(BdrvChild *child, int64_t offset,
70
+ QEMUIOVector *qiov, bool is_write,
71
+ BdrvRequestFlags flags)
72
{
73
RwCo rwco = {
74
.child = child,
75
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
76
{
77
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
78
79
- return bdrv_prwv_co(child, offset, &qiov, true,
80
- BDRV_REQ_ZERO_WRITE | flags);
81
+ return bdrv_prwv(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags);
82
}
83
84
/*
85
@@ -XXX,XX +XXX,XX @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
86
{
87
int ret;
88
89
- ret = bdrv_prwv_co(child, offset, qiov, false, 0);
90
+ ret = bdrv_prwv(child, offset, qiov, false, 0);
91
if (ret < 0) {
92
return ret;
93
}
94
@@ -XXX,XX +XXX,XX @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
95
{
96
int ret;
97
98
- ret = bdrv_prwv_co(child, offset, qiov, true, 0);
99
+ ret = bdrv_prwv(child, offset, qiov, true, 0);
100
if (ret < 0) {
101
return ret;
102
}
103
@@ -XXX,XX +XXX,XX @@ early_out:
104
return ret;
105
}
106
107
-static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
108
- BlockDriverState *base,
109
- bool want_zero,
110
- int64_t offset,
111
- int64_t bytes,
112
- int64_t *pnum,
113
- int64_t *map,
114
- BlockDriverState **file)
115
+static int coroutine_fn
116
+bdrv_co_common_block_status_above(BlockDriverState *bs,
117
+ BlockDriverState *base,
118
+ bool want_zero,
119
+ int64_t offset,
120
+ int64_t bytes,
121
+ int64_t *pnum,
122
+ int64_t *map,
123
+ BlockDriverState **file)
124
{
125
BlockDriverState *p;
126
int ret = 0;
127
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
128
{
129
BdrvCoBlockStatusData *data = opaque;
130
131
- return bdrv_co_block_status_above(data->bs, data->base,
132
- data->want_zero,
133
- data->offset, data->bytes,
134
- data->pnum, data->map, data->file);
135
+ return bdrv_co_common_block_status_above(data->bs, data->base,
136
+ data->want_zero,
137
+ data->offset, data->bytes,
138
+ data->pnum, data->map, data->file);
139
}
140
141
/*
142
--
54
--
143
2.26.2
55
2.34.1
144
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Like for read/write in a previous commit, drop extra indirection layer,
3
Add new block driver handlers and corresponding generic wrappers.
4
generate directly bdrv_readv_vmstate() and bdrv_writev_vmstate().
4
It will be used to allow copy-before-write filter to provide
5
reach fleecing interface in further commit.
6
7
In future this approach may be used to allow reading qcow2 internal
8
snapshots, for example to export them through NBD.
5
9
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Message-Id: <20220303194349.2304213-11-vsementsov@virtuozzo.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
[hreitz: Rebased on block GS/IO split]
10
Message-Id: <20200924185414.28642-8-vsementsov@virtuozzo.com>
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
---
15
---
12
block/coroutines.h | 10 +++----
16
include/block/block_int-common.h | 18 ++++++++
13
include/block/block.h | 6 ++--
17
include/block/block_int-io.h | 9 ++++
14
block/io.c | 70 ++++++++++++++++++++++---------------------
18
block/io.c | 72 ++++++++++++++++++++++++++++++++
15
3 files changed, 44 insertions(+), 42 deletions(-)
19
3 files changed, 99 insertions(+)
16
20
17
diff --git a/block/coroutines.h b/block/coroutines.h
21
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
18
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
19
--- a/block/coroutines.h
23
--- a/include/block/block_int-common.h
20
+++ b/block/coroutines.h
24
+++ b/include/block/block_int-common.h
21
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
25
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
22
int64_t *map,
26
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
23
BlockDriverState **file);
27
int64_t *map, BlockDriverState **file);
24
28
25
-int coroutine_fn
29
+ /*
26
-bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
30
+ * Snapshot-access API.
27
- bool is_read);
31
+ *
28
-int generated_co_wrapper
32
+ * Block-driver may provide snapshot-access API: special functions to access
29
-bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
33
+ * some internal "snapshot". The functions are similar with normal
30
- bool is_read);
34
+ * read/block_status/discard handler, but don't have any specific handling
31
+int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs,
35
+ * in generic block-layer: no serializing, no alignment, no tracked
32
+ QEMUIOVector *qiov, int64_t pos);
36
+ * requests. So, block-driver that realizes these APIs is fully responsible
33
+int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs,
37
+ * for synchronization between snapshot-access API and normal IO requests.
34
+ QEMUIOVector *qiov, int64_t pos);
38
+ */
35
39
+ int coroutine_fn (*bdrv_co_preadv_snapshot)(BlockDriverState *bs,
36
#endif /* BLOCK_COROUTINES_INT_H */
40
+ int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
37
diff --git a/include/block/block.h b/include/block/block.h
41
+ int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs,
42
+ bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
43
+ int64_t *map, BlockDriverState **file);
44
+ int coroutine_fn (*bdrv_co_pdiscard_snapshot)(BlockDriverState *bs,
45
+ int64_t offset, int64_t bytes);
46
+
47
/*
48
* Invalidate any cached meta-data.
49
*/
50
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
38
index XXXXXXX..XXXXXXX 100644
51
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block.h
52
--- a/include/block/block_int-io.h
40
+++ b/include/block/block.h
53
+++ b/include/block/block_int-io.h
41
@@ -XXX,XX +XXX,XX @@ int path_has_protocol(const char *path);
54
@@ -XXX,XX +XXX,XX @@
42
int path_is_absolute(const char *path);
55
* the I/O API.
43
char *path_combine(const char *base_path, const char *filename);
56
*/
44
57
45
-int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
58
+int coroutine_fn bdrv_co_preadv_snapshot(BdrvChild *child,
46
-int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
59
+ int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
47
+int generated_co_wrapper
60
+int coroutine_fn bdrv_co_snapshot_block_status(BlockDriverState *bs,
48
+bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
61
+ bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
49
+int generated_co_wrapper
62
+ int64_t *map, BlockDriverState **file);
50
+bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
63
+int coroutine_fn bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
51
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
64
+ int64_t offset, int64_t bytes);
52
int64_t pos, int size);
65
+
53
66
+
67
int coroutine_fn bdrv_co_preadv(BdrvChild *child,
68
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
69
BdrvRequestFlags flags);
54
diff --git a/block/io.c b/block/io.c
70
diff --git a/block/io.c b/block/io.c
55
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
56
--- a/block/io.c
72
--- a/block/io.c
57
+++ b/block/io.c
73
+++ b/block/io.c
58
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top,
74
@@ -XXX,XX +XXX,XX @@ void bdrv_cancel_in_flight(BlockDriverState *bs)
75
bs->drv->bdrv_cancel_in_flight(bs);
76
}
59
}
77
}
60
78
+
61
int coroutine_fn
79
+int coroutine_fn
62
-bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
80
+bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes,
63
- bool is_read)
81
+ QEMUIOVector *qiov, size_t qiov_offset)
64
+bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
82
+{
65
{
83
+ BlockDriverState *bs = child->bs;
66
BlockDriver *drv = bs->drv;
84
+ BlockDriver *drv = bs->drv;
67
BlockDriverState *child_bs = bdrv_primary_bs(bs);
85
+ int ret;
68
int ret = -ENOTSUP;
86
+ IO_CODE();
69
87
+
70
+ if (!drv) {
88
+ if (!drv) {
71
+ return -ENOMEDIUM;
89
+ return -ENOMEDIUM;
72
+ }
90
+ }
73
+
91
+
74
bdrv_inc_in_flight(bs);
92
+ if (!drv->bdrv_co_preadv_snapshot) {
75
93
+ return -ENOTSUP;
76
+ if (drv->bdrv_load_vmstate) {
77
+ ret = drv->bdrv_load_vmstate(bs, qiov, pos);
78
+ } else if (child_bs) {
79
+ ret = bdrv_co_readv_vmstate(child_bs, qiov, pos);
80
+ }
94
+ }
81
+
95
+
96
+ bdrv_inc_in_flight(bs);
97
+ ret = drv->bdrv_co_preadv_snapshot(bs, offset, bytes, qiov, qiov_offset);
82
+ bdrv_dec_in_flight(bs);
98
+ bdrv_dec_in_flight(bs);
83
+
99
+
84
+ return ret;
100
+ return ret;
85
+}
101
+}
86
+
102
+
87
+int coroutine_fn
103
+int coroutine_fn
88
+bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
104
+bdrv_co_snapshot_block_status(BlockDriverState *bs,
105
+ bool want_zero, int64_t offset, int64_t bytes,
106
+ int64_t *pnum, int64_t *map,
107
+ BlockDriverState **file)
89
+{
108
+{
90
+ BlockDriver *drv = bs->drv;
109
+ BlockDriver *drv = bs->drv;
91
+ BlockDriverState *child_bs = bdrv_primary_bs(bs);
110
+ int ret;
92
+ int ret = -ENOTSUP;
111
+ IO_CODE();
93
+
112
+
94
if (!drv) {
113
+ if (!drv) {
95
- ret = -ENOMEDIUM;
96
- } else if (drv->bdrv_load_vmstate) {
97
- if (is_read) {
98
- ret = drv->bdrv_load_vmstate(bs, qiov, pos);
99
- } else {
100
- ret = drv->bdrv_save_vmstate(bs, qiov, pos);
101
- }
102
+ return -ENOMEDIUM;
114
+ return -ENOMEDIUM;
103
+ }
115
+ }
104
+
116
+
117
+ if (!drv->bdrv_co_snapshot_block_status) {
118
+ return -ENOTSUP;
119
+ }
120
+
105
+ bdrv_inc_in_flight(bs);
121
+ bdrv_inc_in_flight(bs);
122
+ ret = drv->bdrv_co_snapshot_block_status(bs, want_zero, offset, bytes,
123
+ pnum, map, file);
124
+ bdrv_dec_in_flight(bs);
106
+
125
+
107
+ if (drv->bdrv_save_vmstate) {
126
+ return ret;
108
+ ret = drv->bdrv_save_vmstate(bs, qiov, pos);
127
+}
109
} else if (child_bs) {
110
- ret = bdrv_co_rw_vmstate(child_bs, qiov, pos, is_read);
111
+ ret = bdrv_co_writev_vmstate(child_bs, qiov, pos);
112
}
113
114
bdrv_dec_in_flight(bs);
115
+
128
+
116
return ret;
129
+int coroutine_fn
117
}
130
+bdrv_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
118
131
+{
119
@@ -XXX,XX +XXX,XX @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
132
+ BlockDriver *drv = bs->drv;
120
int64_t pos, int size)
133
+ int ret;
121
{
134
+ IO_CODE();
122
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size);
135
+
123
- int ret;
136
+ if (!drv) {
124
+ int ret = bdrv_writev_vmstate(bs, &qiov, pos);
137
+ return -ENOMEDIUM;
125
138
+ }
126
- ret = bdrv_writev_vmstate(bs, &qiov, pos);
139
+
127
- if (ret < 0) {
140
+ if (!drv->bdrv_co_pdiscard_snapshot) {
128
- return ret;
141
+ return -ENOTSUP;
129
- }
142
+ }
130
-
143
+
131
- return size;
144
+ bdrv_inc_in_flight(bs);
132
-}
145
+ ret = drv->bdrv_co_pdiscard_snapshot(bs, offset, bytes);
133
-
146
+ bdrv_dec_in_flight(bs);
134
-int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
147
+
135
-{
148
+ return ret;
136
- return bdrv_rw_vmstate(bs, qiov, pos, false);
149
+}
137
+ return ret < 0 ? ret : size;
138
}
139
140
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
141
int64_t pos, int size)
142
{
143
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size);
144
- int ret;
145
+ int ret = bdrv_readv_vmstate(bs, &qiov, pos);
146
147
- ret = bdrv_readv_vmstate(bs, &qiov, pos);
148
- if (ret < 0) {
149
- return ret;
150
- }
151
-
152
- return size;
153
-}
154
-
155
-int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
156
-{
157
- return bdrv_rw_vmstate(bs, qiov, pos, true);
158
+ return ret < 0 ? ret : size;
159
}
160
161
/**************************************************************/
162
--
150
--
163
2.26.2
151
2.34.1
164
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We have a very frequent pattern of creating a coroutine from a function
3
The new block driver simply utilizes snapshot-access API of underlying
4
with several arguments:
4
block node.
5
5
6
- create a structure to pack parameters
6
In further patches we want to use it like this:
7
- create _entry function to call original function taking parameters
7
8
from struct
8
[guest] [NBD export]
9
- do different magic to handle completion: set ret to NOT_DONE or
9
| |
10
EINPROGRESS or use separate bool field
10
| root | root
11
- fill the struct and create coroutine from _entry function with this
11
v file v
12
struct as a parameter
12
[copy-before-write]<------[snapshot-access]
13
- do coroutine enter and BDRV_POLL_WHILE loop
13
| |
14
14
| file | target
15
Let's reduce code duplication by generating coroutine wrappers.
15
v v
16
16
[active-disk] [temp.img]
17
This patch adds scripts/block-coroutine-wrapper.py together with some
17
18
friends, which will generate functions with declared prototypes marked
18
This way, NBD client will be able to read snapshotted state of active
19
by the 'generated_co_wrapper' specifier.
19
disk, when active disk is continued to be written by guest. This is
20
20
known as "fleecing", and currently uses another scheme based on qcow2
21
The usage of new code generation is as follows:
21
temporary image which backing file is active-disk. New scheme comes
22
22
with benefits - see next commit.
23
1. define the coroutine function somewhere
23
24
24
The other possible application is exporting internal snapshots of
25
int coroutine_fn bdrv_co_NAME(...) {...}
25
qcow2, like this:
26
26
27
2. declare in some header file
27
[guest] [NBD export]
28
28
| |
29
int generated_co_wrapper bdrv_NAME(...);
29
| root | root
30
30
v file v
31
with same list of parameters (generated_co_wrapper is
31
[qcow2]<---------[snapshot-access]
32
defined in "include/block/block.h").
32
33
33
For this, we'll need to implement snapshot-access API handlers in
34
3. Make sure the block_gen_c declaration in block/meson.build
34
qcow2 driver, and improve snapshot-access block driver (and API) to
35
mentions the file with your marker function.
35
make it possible to select snapshot by name. Another thing to improve
36
36
is size of snapshot. Now for simplicity we just use size of bs->file,
37
Still, no function is now marked, this work is for the following
37
which is OK for backup, but for qcow2 snapshots export we'll need to
38
commit.
38
imporve snapshot-access API to get size of snapshot.
39
39
40
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
40
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
41
Reviewed-by: Eric Blake <eblake@redhat.com>
41
Message-Id: <20220303194349.2304213-12-vsementsov@virtuozzo.com>
42
Message-Id: <20200924185414.28642-5-vsementsov@virtuozzo.com>
42
[hreitz: Rebased on block GS/IO split]
43
[Added encoding='utf-8' to open() calls as requested by Vladimir. Fixed
43
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
44
typo and grammar issues pointed out by Eric Blake.
45
--Stefan]
46
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
47
---
44
---
48
block/block-gen.h | 49 +++++++
45
qapi/block-core.json | 4 +-
49
include/block/block.h | 10 ++
46
include/block/block_int-common.h | 6 ++
50
block/meson.build | 8 ++
47
block/snapshot-access.c | 132 +++++++++++++++++++++++++++++++
51
docs/devel/block-coroutine-wrapper.rst | 54 +++++++
48
MAINTAINERS | 1 +
52
docs/devel/index.rst | 1 +
49
block/meson.build | 1 +
53
scripts/block-coroutine-wrapper.py | 188 +++++++++++++++++++++++++
50
5 files changed, 143 insertions(+), 1 deletion(-)
54
6 files changed, 310 insertions(+)
51
create mode 100644 block/snapshot-access.c
55
create mode 100644 block/block-gen.h
52
56
create mode 100644 docs/devel/block-coroutine-wrapper.rst
53
diff --git a/qapi/block-core.json b/qapi/block-core.json
57
create mode 100644 scripts/block-coroutine-wrapper.py
54
index XXXXXXX..XXXXXXX 100644
58
55
--- a/qapi/block-core.json
59
diff --git a/block/block-gen.h b/block/block-gen.h
56
+++ b/qapi/block-core.json
57
@@ -XXX,XX +XXX,XX @@
58
# @blkreplay: Since 4.2
59
# @compress: Since 5.0
60
# @copy-before-write: Since 6.2
61
+# @snapshot-access: Since 7.0
62
#
63
# Since: 2.9
64
##
65
{ 'enum': 'BlockdevDriver',
66
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
67
'cloop', 'compress', 'copy-before-write', 'copy-on-read', 'dmg',
68
- 'file', 'ftp', 'ftps', 'gluster',
69
+ 'file', 'snapshot-access', 'ftp', 'ftps', 'gluster',
70
{'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
71
{'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
72
'http', 'https', 'iscsi',
73
@@ -XXX,XX +XXX,XX @@
74
'rbd': 'BlockdevOptionsRbd',
75
'replication': { 'type': 'BlockdevOptionsReplication',
76
'if': 'CONFIG_REPLICATION' },
77
+ 'snapshot-access': 'BlockdevOptionsGenericFormat',
78
'ssh': 'BlockdevOptionsSsh',
79
'throttle': 'BlockdevOptionsThrottle',
80
'vdi': 'BlockdevOptionsGenericFormat',
81
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/include/block/block_int-common.h
84
+++ b/include/block/block_int-common.h
85
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
86
* in generic block-layer: no serializing, no alignment, no tracked
87
* requests. So, block-driver that realizes these APIs is fully responsible
88
* for synchronization between snapshot-access API and normal IO requests.
89
+ *
90
+ * TODO: To be able to support qcow2's internal snapshots, this API will
91
+ * need to be extended to:
92
+ * - be able to select a specific snapshot
93
+ * - receive the snapshot's actual length (which may differ from bs's
94
+ * length)
95
*/
96
int coroutine_fn (*bdrv_co_preadv_snapshot)(BlockDriverState *bs,
97
int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
98
diff --git a/block/snapshot-access.c b/block/snapshot-access.c
60
new file mode 100644
99
new file mode 100644
61
index XXXXXXX..XXXXXXX
100
index XXXXXXX..XXXXXXX
62
--- /dev/null
101
--- /dev/null
63
+++ b/block/block-gen.h
102
+++ b/block/snapshot-access.c
64
@@ -XXX,XX +XXX,XX @@
103
@@ -XXX,XX +XXX,XX @@
65
+/*
104
+/*
66
+ * Block coroutine wrapping core, used by auto-generated block/block-gen.c
105
+ * snapshot_access block driver
67
+ *
106
+ *
68
+ * Copyright (c) 2003 Fabrice Bellard
107
+ * Copyright (c) 2022 Virtuozzo International GmbH.
69
+ * Copyright (c) 2020 Virtuozzo International GmbH
108
+ *
70
+ *
109
+ * Author:
71
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
110
+ * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
72
+ * of this software and associated documentation files (the "Software"), to deal
111
+ *
73
+ * in the Software without restriction, including without limitation the rights
112
+ * This program is free software; you can redistribute it and/or modify
74
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
113
+ * it under the terms of the GNU General Public License as published by
75
+ * copies of the Software, and to permit persons to whom the Software is
114
+ * the Free Software Foundation; either version 2 of the License, or
76
+ * furnished to do so, subject to the following conditions:
115
+ * (at your option) any later version.
77
+ *
116
+ *
78
+ * The above copyright notice and this permission notice shall be included in
117
+ * This program is distributed in the hope that it will be useful,
79
+ * all copies or substantial portions of the Software.
118
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
80
+ *
119
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
120
+ * GNU General Public License for more details.
82
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
121
+ *
83
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
122
+ * You should have received a copy of the GNU General Public License
84
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
123
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
85
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
86
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
87
+ * THE SOFTWARE.
88
+ */
124
+ */
89
+
125
+
90
+#ifndef BLOCK_BLOCK_GEN_H
126
+#include "qemu/osdep.h"
91
+#define BLOCK_BLOCK_GEN_H
127
+
92
+
128
+#include "sysemu/block-backend.h"
129
+#include "qemu/cutils.h"
93
+#include "block/block_int.h"
130
+#include "block/block_int.h"
94
+
131
+
95
+/* Base structure for argument packing structures */
132
+static coroutine_fn int
96
+typedef struct BdrvPollCo {
133
+snapshot_access_co_preadv_part(BlockDriverState *bs,
97
+ BlockDriverState *bs;
134
+ int64_t offset, int64_t bytes,
98
+ bool in_progress;
135
+ QEMUIOVector *qiov, size_t qiov_offset,
99
+ int ret;
136
+ BdrvRequestFlags flags)
100
+ Coroutine *co; /* Keep pointer here for debugging */
137
+{
101
+} BdrvPollCo;
138
+ if (flags) {
102
+
139
+ return -ENOTSUP;
103
+static inline int bdrv_poll_co(BdrvPollCo *s)
140
+ }
104
+{
141
+
105
+ assert(!qemu_in_coroutine());
142
+ return bdrv_co_preadv_snapshot(bs->file, offset, bytes, qiov, qiov_offset);
106
+
143
+}
107
+ bdrv_coroutine_enter(s->bs, s->co);
144
+
108
+ BDRV_POLL_WHILE(s->bs, s->in_progress);
145
+static int coroutine_fn
109
+
146
+snapshot_access_co_block_status(BlockDriverState *bs,
110
+ return s->ret;
147
+ bool want_zero, int64_t offset,
111
+}
148
+ int64_t bytes, int64_t *pnum,
112
+
149
+ int64_t *map, BlockDriverState **file)
113
+#endif /* BLOCK_BLOCK_GEN_H */
150
+{
114
diff --git a/include/block/block.h b/include/block/block.h
151
+ return bdrv_co_snapshot_block_status(bs->file->bs, want_zero, offset,
115
index XXXXXXX..XXXXXXX 100644
152
+ bytes, pnum, map, file);
116
--- a/include/block/block.h
153
+}
117
+++ b/include/block/block.h
154
+
118
@@ -XXX,XX +XXX,XX @@
155
+static int coroutine_fn snapshot_access_co_pdiscard(BlockDriverState *bs,
119
#include "block/blockjob.h"
156
+ int64_t offset, int64_t bytes)
120
#include "qemu/hbitmap.h"
157
+{
121
158
+ return bdrv_co_pdiscard_snapshot(bs->file->bs, offset, bytes);
122
+/*
159
+}
123
+ * generated_co_wrapper
160
+
124
+ *
161
+static int coroutine_fn
125
+ * Function specifier, which does nothing but mark functions to be
162
+snapshot_access_co_pwrite_zeroes(BlockDriverState *bs,
126
+ * generated by scripts/block-coroutine-wrapper.py
163
+ int64_t offset, int64_t bytes,
127
+ *
164
+ BdrvRequestFlags flags)
128
+ * Read more in docs/devel/block-coroutine-wrapper.rst
165
+{
129
+ */
166
+ return -ENOTSUP;
130
+#define generated_co_wrapper
167
+}
131
+
168
+
132
/* block.c */
169
+static coroutine_fn int
133
typedef struct BlockDriver BlockDriver;
170
+snapshot_access_co_pwritev_part(BlockDriverState *bs,
134
typedef struct BdrvChild BdrvChild;
171
+ int64_t offset, int64_t bytes,
172
+ QEMUIOVector *qiov, size_t qiov_offset,
173
+ BdrvRequestFlags flags)
174
+{
175
+ return -ENOTSUP;
176
+}
177
+
178
+
179
+static void snapshot_access_refresh_filename(BlockDriverState *bs)
180
+{
181
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
182
+ bs->file->bs->filename);
183
+}
184
+
185
+static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
186
+ Error **errp)
187
+{
188
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
189
+ BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
190
+ false, errp);
191
+ if (!bs->file) {
192
+ return -EINVAL;
193
+ }
194
+
195
+ bs->total_sectors = bs->file->bs->total_sectors;
196
+
197
+ return 0;
198
+}
199
+
200
+static void snapshot_access_child_perm(BlockDriverState *bs, BdrvChild *c,
201
+ BdrvChildRole role,
202
+ BlockReopenQueue *reopen_queue,
203
+ uint64_t perm, uint64_t shared,
204
+ uint64_t *nperm, uint64_t *nshared)
205
+{
206
+ /*
207
+ * Currently, we don't need any permissions. If bs->file provides
208
+ * snapshot-access API, we can use it.
209
+ */
210
+ *nperm = 0;
211
+ *nshared = BLK_PERM_ALL;
212
+}
213
+
214
+BlockDriver bdrv_snapshot_access_drv = {
215
+ .format_name = "snapshot-access",
216
+
217
+ .bdrv_open = snapshot_access_open,
218
+
219
+ .bdrv_co_preadv_part = snapshot_access_co_preadv_part,
220
+ .bdrv_co_pwritev_part = snapshot_access_co_pwritev_part,
221
+ .bdrv_co_pwrite_zeroes = snapshot_access_co_pwrite_zeroes,
222
+ .bdrv_co_pdiscard = snapshot_access_co_pdiscard,
223
+ .bdrv_co_block_status = snapshot_access_co_block_status,
224
+
225
+ .bdrv_refresh_filename = snapshot_access_refresh_filename,
226
+
227
+ .bdrv_child_perm = snapshot_access_child_perm,
228
+};
229
+
230
+static void snapshot_access_init(void)
231
+{
232
+ bdrv_register(&bdrv_snapshot_access_drv);
233
+}
234
+
235
+block_init(snapshot_access_init);
236
diff --git a/MAINTAINERS b/MAINTAINERS
237
index XXXXXXX..XXXXXXX 100644
238
--- a/MAINTAINERS
239
+++ b/MAINTAINERS
240
@@ -XXX,XX +XXX,XX @@ F: block/reqlist.c
241
F: include/block/reqlist.h
242
F: block/copy-before-write.h
243
F: block/copy-before-write.c
244
+F: block/snapshot-access.c
245
F: include/block/aio_task.h
246
F: block/aio_task.c
247
F: util/qemu-co-shared-resource.c
135
diff --git a/block/meson.build b/block/meson.build
248
diff --git a/block/meson.build b/block/meson.build
136
index XXXXXXX..XXXXXXX 100644
249
index XXXXXXX..XXXXXXX 100644
137
--- a/block/meson.build
250
--- a/block/meson.build
138
+++ b/block/meson.build
251
+++ b/block/meson.build
139
@@ -XXX,XX +XXX,XX @@ module_block_h = custom_target('module_block.h',
252
@@ -XXX,XX +XXX,XX @@ block_ss.add(files(
140
command: [module_block_py, '@OUTPUT0@', modsrc])
253
'raw-format.c',
141
block_ss.add(module_block_h)
254
'reqlist.c',
142
255
'snapshot.c',
143
+wrapper_py = find_program('../scripts/block-coroutine-wrapper.py')
256
+ 'snapshot-access.c',
144
+block_gen_c = custom_target('block-gen.c',
257
'throttle-groups.c',
145
+ output: 'block-gen.c',
258
'throttle.c',
146
+ input: files('../include/block/block.h',
259
'vhdx-endian.c',
147
+ 'coroutines.h'),
148
+ command: [wrapper_py, '@OUTPUT@', '@INPUT@'])
149
+block_ss.add(block_gen_c)
150
+
151
block_ss.add(files('stream.c'))
152
153
softmmu_ss.add(files('qapi-sysemu.c'))
154
diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst
155
new file mode 100644
156
index XXXXXXX..XXXXXXX
157
--- /dev/null
158
+++ b/docs/devel/block-coroutine-wrapper.rst
159
@@ -XXX,XX +XXX,XX @@
160
+=======================
161
+block-coroutine-wrapper
162
+=======================
163
+
164
+A lot of functions in QEMU block layer (see ``block/*``) can only be
165
+called in coroutine context. Such functions are normally marked by the
166
+coroutine_fn specifier. Still, sometimes we need to call them from
167
+non-coroutine context; for this we need to start a coroutine, run the
168
+needed function from it and wait for the coroutine to finish in a
169
+BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one
170
+void* argument. So for each coroutine_fn function which needs a
171
+non-coroutine interface, we should define a structure to pack the
172
+parameters, define a separate function to unpack the parameters and
173
+call the original function and finally define a new interface function
174
+with same list of arguments as original one, which will pack the
175
+parameters into a struct, create a coroutine, run it and wait in
176
+BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand,
177
+so we have a script to generate them.
178
+
179
+Usage
180
+=====
181
+
182
+Assume we have defined the ``coroutine_fn`` function
183
+``bdrv_co_foo(<some args>)`` and need a non-coroutine interface for it,
184
+called ``bdrv_foo(<same args>)``. In this case the script can help. To
185
+trigger the generation:
186
+
187
+1. You need ``bdrv_foo`` declaration somewhere (for example, in
188
+ ``block/coroutines.h``) with the ``generated_co_wrapper`` mark,
189
+ like this:
190
+
191
+.. code-block:: c
192
+
193
+ int generated_co_wrapper bdrv_foo(<some args>);
194
+
195
+2. You need to feed this declaration to block-coroutine-wrapper script.
196
+ For this, add the .h (or .c) file with the declaration to the
197
+ ``input: files(...)`` list of ``block_gen_c`` target declaration in
198
+ ``block/meson.build``
199
+
200
+You are done. During the build, coroutine wrappers will be generated in
201
+``<BUILD_DIR>/block/block-gen.c``.
202
+
203
+Links
204
+=====
205
+
206
+1. The script location is ``scripts/block-coroutine-wrapper.py``.
207
+
208
+2. Generic place for private ``generated_co_wrapper`` declarations is
209
+ ``block/coroutines.h``, for public declarations:
210
+ ``include/block/block.h``
211
+
212
+3. The core API of generated coroutine wrappers is placed in
213
+ (not generated) ``block/block-gen.h``
214
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
215
index XXXXXXX..XXXXXXX 100644
216
--- a/docs/devel/index.rst
217
+++ b/docs/devel/index.rst
218
@@ -XXX,XX +XXX,XX @@ Contents:
219
reset
220
s390-dasd-ipl
221
clocks
222
+ block-coroutine-wrapper
223
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
224
new file mode 100644
225
index XXXXXXX..XXXXXXX
226
--- /dev/null
227
+++ b/scripts/block-coroutine-wrapper.py
228
@@ -XXX,XX +XXX,XX @@
229
+#! /usr/bin/env python3
230
+"""Generate coroutine wrappers for block subsystem.
231
+
232
+The program parses one or several concatenated c files from stdin,
233
+searches for functions with the 'generated_co_wrapper' specifier
234
+and generates corresponding wrappers on stdout.
235
+
236
+Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
237
+
238
+Copyright (c) 2020 Virtuozzo International GmbH.
239
+
240
+This program is free software; you can redistribute it and/or modify
241
+it under the terms of the GNU General Public License as published by
242
+the Free Software Foundation; either version 2 of the License, or
243
+(at your option) any later version.
244
+
245
+This program is distributed in the hope that it will be useful,
246
+but WITHOUT ANY WARRANTY; without even the implied warranty of
247
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
248
+GNU General Public License for more details.
249
+
250
+You should have received a copy of the GNU General Public License
251
+along with this program. If not, see <http://www.gnu.org/licenses/>.
252
+"""
253
+
254
+import sys
255
+import re
256
+import subprocess
257
+import json
258
+from typing import Iterator
259
+
260
+
261
+def prettify(code: str) -> str:
262
+ """Prettify code using clang-format if available"""
263
+
264
+ try:
265
+ style = json.dumps({
266
+ 'IndentWidth': 4,
267
+ 'BraceWrapping': {'AfterFunction': True},
268
+ 'BreakBeforeBraces': 'Custom',
269
+ 'SortIncludes': False,
270
+ 'MaxEmptyLinesToKeep': 2,
271
+ })
272
+ p = subprocess.run(['clang-format', f'-style={style}'], check=True,
273
+ encoding='utf-8', input=code,
274
+ stdout=subprocess.PIPE)
275
+ return p.stdout
276
+ except FileNotFoundError:
277
+ return code
278
+
279
+
280
+def gen_header():
281
+ copyright = re.sub('^.*Copyright', 'Copyright', __doc__, flags=re.DOTALL)
282
+ copyright = re.sub('^(?=.)', ' * ', copyright.strip(), flags=re.MULTILINE)
283
+ copyright = re.sub('^$', ' *', copyright, flags=re.MULTILINE)
284
+ return f"""\
285
+/*
286
+ * File is generated by scripts/block-coroutine-wrapper.py
287
+ *
288
+{copyright}
289
+ */
290
+
291
+#include "qemu/osdep.h"
292
+#include "block/coroutines.h"
293
+#include "block/block-gen.h"
294
+#include "block/block_int.h"\
295
+"""
296
+
297
+
298
+class ParamDecl:
299
+ param_re = re.compile(r'(?P<decl>'
300
+ r'(?P<type>.*[ *])'
301
+ r'(?P<name>[a-z][a-z0-9_]*)'
302
+ r')')
303
+
304
+ def __init__(self, param_decl: str) -> None:
305
+ m = self.param_re.match(param_decl.strip())
306
+ if m is None:
307
+ raise ValueError(f'Wrong parameter declaration: "{param_decl}"')
308
+ self.decl = m.group('decl')
309
+ self.type = m.group('type')
310
+ self.name = m.group('name')
311
+
312
+
313
+class FuncDecl:
314
+ def __init__(self, return_type: str, name: str, args: str) -> None:
315
+ self.return_type = return_type.strip()
316
+ self.name = name.strip()
317
+ self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
318
+
319
+ def gen_list(self, format: str) -> str:
320
+ return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
321
+
322
+ def gen_block(self, format: str) -> str:
323
+ return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
324
+
325
+
326
+# Match wrappers declared with a generated_co_wrapper mark
327
+func_decl_re = re.compile(r'^int\s*generated_co_wrapper\s*'
328
+ r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
329
+ r'\((?P<args>[^)]*)\);$', re.MULTILINE)
330
+
331
+
332
+def func_decl_iter(text: str) -> Iterator:
333
+ for m in func_decl_re.finditer(text):
334
+ yield FuncDecl(return_type='int',
335
+ name=m.group('wrapper_name'),
336
+ args=m.group('args'))
337
+
338
+
339
+def snake_to_camel(func_name: str) -> str:
340
+ """
341
+ Convert underscore names like 'some_function_name' to camel-case like
342
+ 'SomeFunctionName'
343
+ """
344
+ words = func_name.split('_')
345
+ words = [w[0].upper() + w[1:] for w in words]
346
+ return ''.join(words)
347
+
348
+
349
+def gen_wrapper(func: FuncDecl) -> str:
350
+ assert func.name.startswith('bdrv_')
351
+ assert not func.name.startswith('bdrv_co_')
352
+ assert func.return_type == 'int'
353
+ assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *']
354
+
355
+ name = 'bdrv_co_' + func.name[5:]
356
+ bs = 'bs' if func.args[0].type == 'BlockDriverState *' else 'child->bs'
357
+ struct_name = snake_to_camel(name)
358
+
359
+ return f"""\
360
+/*
361
+ * Wrappers for {name}
362
+ */
363
+
364
+typedef struct {struct_name} {{
365
+ BdrvPollCo poll_state;
366
+{ func.gen_block(' {decl};') }
367
+}} {struct_name};
368
+
369
+static void coroutine_fn {name}_entry(void *opaque)
370
+{{
371
+ {struct_name} *s = opaque;
372
+
373
+ s->poll_state.ret = {name}({ func.gen_list('s->{name}') });
374
+ s->poll_state.in_progress = false;
375
+
376
+ aio_wait_kick();
377
+}}
378
+
379
+int {func.name}({ func.gen_list('{decl}') })
380
+{{
381
+ if (qemu_in_coroutine()) {{
382
+ return {name}({ func.gen_list('{name}') });
383
+ }} else {{
384
+ {struct_name} s = {{
385
+ .poll_state.bs = {bs},
386
+ .poll_state.in_progress = true,
387
+
388
+{ func.gen_block(' .{name} = {name},') }
389
+ }};
390
+
391
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
392
+
393
+ return bdrv_poll_co(&s.poll_state);
394
+ }}
395
+}}"""
396
+
397
+
398
+def gen_wrappers(input_code: str) -> str:
399
+ res = ''
400
+ for func in func_decl_iter(input_code):
401
+ res += '\n\n\n'
402
+ res += gen_wrapper(func)
403
+
404
+ return prettify(res) # prettify to wrap long lines
405
+
406
+
407
+if __name__ == '__main__':
408
+ if len(sys.argv) < 3:
409
+ exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...')
410
+
411
+ with open(sys.argv[1], 'w', encoding='utf-8') as f_out:
412
+ f_out.write(gen_header())
413
+ for fname in sys.argv[2:]:
414
+ with open(fname, encoding='utf-8') as f_in:
415
+ f_out.write(gen_wrappers(f_in.read()))
416
+ f_out.write('\n')
417
--
260
--
418
2.26.2
261
2.34.1
419
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This is the only coroutine wrapper from block.c and block/io.c which
3
Current scheme of image fleecing looks like this:
4
doesn't return a value, so let's convert it to the common behavior, to
4
5
simplify moving to generated coroutine wrappers in a further commit.
5
[guest] [NBD export]
6
6
| |
7
Also, bdrv_invalidate_cache is a void function, returning error only
7
|root | root
8
through **errp parameter, which is considered to be bad practice, as
8
v v
9
it forces callers to define and propagate local_err variable, so
9
[copy-before-write] -----> [temp.qcow2]
10
conversion is good anyway.
10
| target |
11
11
|file |backing
12
This patch leaves the conversion of .bdrv_co_invalidate_cache() driver
12
v |
13
callbacks and bdrv_invalidate_cache_all() for another day.
13
[active disk] <-------------+
14
15
- On guest writes copy-before-write filter copies old data from active
16
disk to temp.qcow2. So fleecing client (NBD export) when reads
17
changed regions from temp.qcow2 image and unchanged from active disk
18
through backing link.
19
20
This patch makes possible new image fleecing scheme:
21
22
[guest] [NBD export]
23
| |
24
| root | root
25
v file v
26
[copy-before-write]<------[snapshot-access]
27
| |
28
| file | target
29
v v
30
[active-disk] [temp.img]
31
32
- copy-before-write does CBW operations and also provides
33
snapshot-access API. The API may be accessed through
34
snapshot-access driver.
35
36
Benefits of new scheme:
37
38
1. Access control: if remote client try to read data that not covered
39
by original dirty bitmap used on copy-before-write open, client gets
40
-EACCES.
41
42
2. Discard support: if remote client do DISCARD, this additionally to
43
discarding data in temp.img informs block-copy process to not copy
44
these clusters. Next read from discarded area will return -EACCES.
45
This is significant thing: when fleecing user reads data that was
46
not yet copied to temp.img, we can avoid copying it on further guest
47
write.
48
49
3. Synchronisation between client reads and block-copy write is more
50
efficient. In old scheme we just rely on BDRV_REQ_SERIALISING flag
51
used for writes to temp.qcow2. New scheme is less blocking:
52
- fleecing reads are never blocked: if data region is untouched or
53
in-flight, we just read from active-disk, otherwise we read from
54
temp.img
55
- writes to temp.img are not blocked by fleecing reads
56
- still, guest writes of-course are blocked by in-flight fleecing
57
reads, that currently read from active-disk - it's the minimum
58
necessary blocking
59
60
4. Temporary image may be of any format, as we don't rely on backing
61
feature.
62
63
5. Permission relation are simplified. With old scheme we have to share
64
write permission on target child of copy-before-write, otherwise
65
backing link conflicts with copy-before-write file child write
66
permissions. With new scheme we don't have backing link, and
67
copy-before-write node may have unshared access to temporary node.
68
(Not realized in this commit, will be in future).
69
70
6. Having control on fleecing reads we'll be able to implement
71
alternative behavior on failed copy-before-write operations.
72
Currently we just break guest request (that's a historical behavior
73
of backup). But in some scenarios it's a bad behavior: better
74
is to drop the backup as failed but don't break guest request.
75
With new scheme we can simply unset some bits in a bitmap on CBW
76
failure and further fleecing reads will -EACCES, or something like
77
this. (Not implemented in this commit, will be in future)
78
Additional application for this is implementing timeout for CBW
79
operations.
80
81
Iotest 257 output is updated, as two more bitmaps now live in
82
copy-before-write filter.
14
83
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
84
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
85
Message-Id: <20220303194349.2304213-13-vsementsov@virtuozzo.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
86
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
18
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Message-Id: <20200924185414.28642-2-vsementsov@virtuozzo.com>
21
---
87
---
22
include/block/block.h | 2 +-
88
block/copy-before-write.c | 212 ++++++++++++++++++++++++++++++++++-
23
block.c | 32 ++++++++++++++++++--------------
89
tests/qemu-iotests/257.out | 224 +++++++++++++++++++++++++++++++++++++
24
2 files changed, 19 insertions(+), 15 deletions(-)
90
2 files changed, 435 insertions(+), 1 deletion(-)
25
91
26
diff --git a/include/block/block.h b/include/block/block.h
92
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
27
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block.h
94
--- a/block/copy-before-write.c
29
+++ b/include/block/block.h
95
+++ b/block/copy-before-write.c
30
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb);
96
@@ -XXX,XX +XXX,XX @@
31
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
97
#include "block/block-copy.h"
32
98
33
/* Invalidate any cached metadata used by image formats */
99
#include "block/copy-before-write.h"
34
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
100
+#include "block/reqlist.h"
35
+int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
101
36
void bdrv_invalidate_cache_all(Error **errp);
102
#include "qapi/qapi-visit-block-core.h"
37
int bdrv_inactivate_all(void);
103
38
104
typedef struct BDRVCopyBeforeWriteState {
39
diff --git a/block.c b/block.c
105
BlockCopyState *bcs;
40
index XXXXXXX..XXXXXXX 100644
106
BdrvChild *target;
41
--- a/block.c
107
+
42
+++ b/block.c
108
+ /*
43
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
109
+ * @lock: protects access to @access_bitmap, @done_bitmap and
44
bdrv_init();
110
+ * @frozen_read_reqs
111
+ */
112
+ CoMutex lock;
113
+
114
+ /*
115
+ * @access_bitmap: represents areas allowed for reading by fleecing user.
116
+ * Reading from non-dirty areas leads to -EACCES.
117
+ */
118
+ BdrvDirtyBitmap *access_bitmap;
119
+
120
+ /*
121
+ * @done_bitmap: represents areas that was successfully copied to @target by
122
+ * copy-before-write operations.
123
+ */
124
+ BdrvDirtyBitmap *done_bitmap;
125
+
126
+ /*
127
+ * @frozen_read_reqs: current read requests for fleecing user in bs->file
128
+ * node. These areas must not be rewritten by guest.
129
+ */
130
+ BlockReqList frozen_read_reqs;
131
} BDRVCopyBeforeWriteState;
132
133
static coroutine_fn int cbw_co_preadv(
134
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_co_preadv(
135
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
45
}
136
}
46
137
47
-static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
138
+/*
48
- Error **errp)
139
+ * Do copy-before-write operation.
49
+static int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
140
+ *
50
+ Error **errp)
141
+ * On failure guest request must be failed too.
51
{
142
+ *
52
BdrvChild *child, *parent;
143
+ * On success, we also wait for all in-flight fleecing read requests in source
53
uint64_t perm, shared_perm;
144
+ * node, and it's guaranteed that after cbw_do_copy_before_write() successful
54
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
145
+ * return there are no such requests and they will never appear.
55
BdrvDirtyBitmap *bm;
146
+ */
56
147
static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs,
57
if (!bs->drv) {
148
uint64_t offset, uint64_t bytes, BdrvRequestFlags flags)
58
- return;
149
{
59
+ return -ENOMEDIUM;
150
BDRVCopyBeforeWriteState *s = bs->opaque;
60
}
151
+ int ret;
61
152
uint64_t off, end;
62
QLIST_FOREACH(child, &bs->children, next) {
153
int64_t cluster_size = block_copy_cluster_size(s->bcs);
63
bdrv_co_invalidate_cache(child->bs, &local_err);
154
64
if (local_err) {
155
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs,
65
error_propagate(errp, local_err);
156
off = QEMU_ALIGN_DOWN(offset, cluster_size);
66
- return;
157
end = QEMU_ALIGN_UP(offset + bytes, cluster_size);
67
+ return -EINVAL;
158
68
}
159
- return block_copy(s->bcs, off, end - off, true);
69
}
160
+ ret = block_copy(s->bcs, off, end - off, true);
70
161
+ if (ret < 0) {
71
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
162
+ return ret;
72
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, errp);
163
+ }
73
if (ret < 0) {
164
+
74
bs->open_flags |= BDRV_O_INACTIVE;
165
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
75
- return;
166
+ bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off);
76
+ return ret;
167
+ reqlist_wait_all(&s->frozen_read_reqs, off, end - off, &s->lock);
77
}
168
+ }
78
bdrv_set_perm(bs, perm, shared_perm);
79
80
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
81
if (local_err) {
82
bs->open_flags |= BDRV_O_INACTIVE;
83
error_propagate(errp, local_err);
84
- return;
85
+ return -EINVAL;
86
}
87
}
88
89
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
90
if (ret < 0) {
91
bs->open_flags |= BDRV_O_INACTIVE;
92
error_setg_errno(errp, -ret, "Could not refresh total sector count");
93
- return;
94
+ return ret;
95
}
96
}
97
98
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
99
if (local_err) {
100
bs->open_flags |= BDRV_O_INACTIVE;
101
error_propagate(errp, local_err);
102
- return;
103
+ return -EINVAL;
104
}
105
}
106
}
107
+
169
+
108
+ return 0;
170
+ return 0;
109
}
171
}
110
172
111
typedef struct InvalidateCacheCo {
173
static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs,
112
BlockDriverState *bs;
174
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cbw_co_flush(BlockDriverState *bs)
113
Error **errp;
175
return bdrv_co_flush(bs->file->bs);
114
bool done;
176
}
177
178
+/*
179
+ * If @offset not accessible - return NULL.
180
+ *
181
+ * Otherwise, set @pnum to some bytes that accessible from @file (@file is set
182
+ * to bs->file or to s->target). Return newly allocated BlockReq object that
183
+ * should be than passed to cbw_snapshot_read_unlock().
184
+ *
185
+ * It's guaranteed that guest writes will not interact in the region until
186
+ * cbw_snapshot_read_unlock() called.
187
+ */
188
+static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs,
189
+ int64_t offset, int64_t bytes,
190
+ int64_t *pnum, BdrvChild **file)
191
+{
192
+ BDRVCopyBeforeWriteState *s = bs->opaque;
193
+ BlockReq *req = g_new(BlockReq, 1);
194
+ bool done;
195
+
196
+ QEMU_LOCK_GUARD(&s->lock);
197
+
198
+ if (bdrv_dirty_bitmap_next_zero(s->access_bitmap, offset, bytes) != -1) {
199
+ g_free(req);
200
+ return NULL;
201
+ }
202
+
203
+ done = bdrv_dirty_bitmap_status(s->done_bitmap, offset, bytes, pnum);
204
+ if (done) {
205
+ /*
206
+ * Special invalid BlockReq, that is handled in
207
+ * cbw_snapshot_read_unlock(). We don't need to lock something to read
208
+ * from s->target.
209
+ */
210
+ *req = (BlockReq) {.offset = -1, .bytes = -1};
211
+ *file = s->target;
212
+ } else {
213
+ reqlist_init_req(&s->frozen_read_reqs, req, offset, bytes);
214
+ *file = bs->file;
215
+ }
216
+
217
+ return req;
218
+}
219
+
220
+static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req)
221
+{
222
+ BDRVCopyBeforeWriteState *s = bs->opaque;
223
+
224
+ if (req->offset == -1 && req->bytes == -1) {
225
+ g_free(req);
226
+ return;
227
+ }
228
+
229
+ QEMU_LOCK_GUARD(&s->lock);
230
+
231
+ reqlist_remove_req(req);
232
+ g_free(req);
233
+}
234
+
235
+static coroutine_fn int
236
+cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes,
237
+ QEMUIOVector *qiov, size_t qiov_offset)
238
+{
239
+ BlockReq *req;
240
+ BdrvChild *file;
115
+ int ret;
241
+ int ret;
116
} InvalidateCacheCo;
242
+
117
243
+ /* TODO: upgrade to async loop using AioTask */
118
static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
244
+ while (bytes) {
119
{
245
+ int64_t cur_bytes;
120
InvalidateCacheCo *ico = opaque;
246
+
121
- bdrv_co_invalidate_cache(ico->bs, ico->errp);
247
+ req = cbw_snapshot_read_lock(bs, offset, bytes, &cur_bytes, &file);
122
+ ico->ret = bdrv_co_invalidate_cache(ico->bs, ico->errp);
248
+ if (!req) {
123
ico->done = true;
249
+ return -EACCES;
124
aio_wait_kick();
250
+ }
251
+
252
+ ret = bdrv_co_preadv_part(file, offset, cur_bytes,
253
+ qiov, qiov_offset, 0);
254
+ cbw_snapshot_read_unlock(bs, req);
255
+ if (ret < 0) {
256
+ return ret;
257
+ }
258
+
259
+ bytes -= cur_bytes;
260
+ offset += cur_bytes;
261
+ qiov_offset += cur_bytes;
262
+ }
263
+
264
+ return 0;
265
+}
266
+
267
+static int coroutine_fn
268
+cbw_co_snapshot_block_status(BlockDriverState *bs,
269
+ bool want_zero, int64_t offset, int64_t bytes,
270
+ int64_t *pnum, int64_t *map,
271
+ BlockDriverState **file)
272
+{
273
+ BDRVCopyBeforeWriteState *s = bs->opaque;
274
+ BlockReq *req;
275
+ int ret;
276
+ int64_t cur_bytes;
277
+ BdrvChild *child;
278
+
279
+ req = cbw_snapshot_read_lock(bs, offset, bytes, &cur_bytes, &child);
280
+ if (!req) {
281
+ return -EACCES;
282
+ }
283
+
284
+ ret = bdrv_block_status(child->bs, offset, cur_bytes, pnum, map, file);
285
+ if (child == s->target) {
286
+ /*
287
+ * We refer to s->target only for areas that we've written to it.
288
+ * And we can not report unallocated blocks in s->target: this will
289
+ * break generic block-status-above logic, that will go to
290
+ * copy-before-write filtered child in this case.
291
+ */
292
+ assert(ret & BDRV_BLOCK_ALLOCATED);
293
+ }
294
+
295
+ cbw_snapshot_read_unlock(bs, req);
296
+
297
+ return ret;
298
+}
299
+
300
+static int coroutine_fn cbw_co_pdiscard_snapshot(BlockDriverState *bs,
301
+ int64_t offset, int64_t bytes)
302
+{
303
+ BDRVCopyBeforeWriteState *s = bs->opaque;
304
+
305
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
306
+ bdrv_reset_dirty_bitmap(s->access_bitmap, offset, bytes);
307
+ }
308
+
309
+ block_copy_reset(s->bcs, offset, bytes);
310
+
311
+ return bdrv_co_pdiscard(s->target, offset, bytes);
312
+}
313
+
314
static void cbw_refresh_filename(BlockDriverState *bs)
315
{
316
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
317
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
318
{
319
BDRVCopyBeforeWriteState *s = bs->opaque;
320
BdrvDirtyBitmap *bitmap = NULL;
321
+ int64_t cluster_size;
322
323
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
324
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
325
@@ -XXX,XX +XXX,XX @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
326
return -EINVAL;
327
}
328
329
+ cluster_size = block_copy_cluster_size(s->bcs);
330
+
331
+ s->done_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
332
+ if (!s->done_bitmap) {
333
+ return -EINVAL;
334
+ }
335
+ bdrv_disable_dirty_bitmap(s->done_bitmap);
336
+
337
+ /* s->access_bitmap starts equal to bcs bitmap */
338
+ s->access_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
339
+ if (!s->access_bitmap) {
340
+ return -EINVAL;
341
+ }
342
+ bdrv_disable_dirty_bitmap(s->access_bitmap);
343
+ bdrv_dirty_bitmap_merge_internal(s->access_bitmap,
344
+ block_copy_dirty_bitmap(s->bcs), NULL,
345
+ true);
346
+
347
+ qemu_co_mutex_init(&s->lock);
348
+ QLIST_INIT(&s->frozen_read_reqs);
349
+
350
return 0;
125
}
351
}
126
352
127
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
353
@@ -XXX,XX +XXX,XX @@ static void cbw_close(BlockDriverState *bs)
128
+int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
354
{
129
{
355
BDRVCopyBeforeWriteState *s = bs->opaque;
130
Coroutine *co;
356
131
InvalidateCacheCo ico = {
357
+ bdrv_release_dirty_bitmap(s->access_bitmap);
132
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
358
+ bdrv_release_dirty_bitmap(s->done_bitmap);
133
bdrv_coroutine_enter(bs, co);
359
+
134
BDRV_POLL_WHILE(bs, !ico.done);
360
block_copy_state_free(s->bcs);
135
}
361
s->bcs = NULL;
136
+
137
+ return ico.ret;
138
}
362
}
139
363
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_cbw_filter = {
140
void bdrv_invalidate_cache_all(Error **errp)
364
.bdrv_co_pdiscard = cbw_co_pdiscard,
141
{
365
.bdrv_co_flush = cbw_co_flush,
142
BlockDriverState *bs;
366
143
- Error *local_err = NULL;
367
+ .bdrv_co_preadv_snapshot = cbw_co_preadv_snapshot,
144
BdrvNextIterator it;
368
+ .bdrv_co_pdiscard_snapshot = cbw_co_pdiscard_snapshot,
145
369
+ .bdrv_co_snapshot_block_status = cbw_co_snapshot_block_status,
146
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
370
+
147
AioContext *aio_context = bdrv_get_aio_context(bs);
371
.bdrv_refresh_filename = cbw_refresh_filename,
148
+ int ret;
372
149
373
.bdrv_child_perm = cbw_child_perm,
150
aio_context_acquire(aio_context);
374
diff --git a/tests/qemu-iotests/257.out b/tests/qemu-iotests/257.out
151
- bdrv_invalidate_cache(bs, &local_err);
375
index XXXXXXX..XXXXXXX 100644
152
+ ret = bdrv_invalidate_cache(bs, errp);
376
--- a/tests/qemu-iotests/257.out
153
aio_context_release(aio_context);
377
+++ b/tests/qemu-iotests/257.out
154
- if (local_err) {
378
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
155
- error_propagate(errp, local_err);
379
{"return": ""}
156
+ if (ret < 0) {
380
{
157
bdrv_next_cleanup(&it);
381
"bitmaps": {
158
return;
382
+ "backup-top": [
159
}
383
+ {
384
+ "busy": false,
385
+ "count": 67108864,
386
+ "granularity": 65536,
387
+ "persistent": false,
388
+ "recording": false
389
+ },
390
+ {
391
+ "busy": false,
392
+ "count": 458752,
393
+ "granularity": 65536,
394
+ "persistent": false,
395
+ "recording": false
396
+ }
397
+ ],
398
"drive0": [
399
{
400
"busy": false,
401
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
402
{"return": ""}
403
{
404
"bitmaps": {
405
+ "backup-top": [
406
+ {
407
+ "busy": false,
408
+ "count": 67108864,
409
+ "granularity": 65536,
410
+ "persistent": false,
411
+ "recording": false
412
+ },
413
+ {
414
+ "busy": false,
415
+ "count": 458752,
416
+ "granularity": 65536,
417
+ "persistent": false,
418
+ "recording": false
419
+ }
420
+ ],
421
"drive0": [
422
{
423
"busy": false,
424
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
425
{"return": ""}
426
{
427
"bitmaps": {
428
+ "backup-top": [
429
+ {
430
+ "busy": false,
431
+ "count": 67108864,
432
+ "granularity": 65536,
433
+ "persistent": false,
434
+ "recording": false
435
+ },
436
+ {
437
+ "busy": false,
438
+ "count": 458752,
439
+ "granularity": 65536,
440
+ "persistent": false,
441
+ "recording": false
442
+ }
443
+ ],
444
"drive0": [
445
{
446
"busy": false,
447
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
448
{"return": ""}
449
{
450
"bitmaps": {
451
+ "backup-top": [
452
+ {
453
+ "busy": false,
454
+ "count": 67108864,
455
+ "granularity": 65536,
456
+ "persistent": false,
457
+ "recording": false
458
+ },
459
+ {
460
+ "busy": false,
461
+ "count": 458752,
462
+ "granularity": 65536,
463
+ "persistent": false,
464
+ "recording": false
465
+ }
466
+ ],
467
"drive0": [
468
{
469
"busy": false,
470
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
471
{"return": ""}
472
{
473
"bitmaps": {
474
+ "backup-top": [
475
+ {
476
+ "busy": false,
477
+ "count": 67108864,
478
+ "granularity": 65536,
479
+ "persistent": false,
480
+ "recording": false
481
+ },
482
+ {
483
+ "busy": false,
484
+ "count": 458752,
485
+ "granularity": 65536,
486
+ "persistent": false,
487
+ "recording": false
488
+ }
489
+ ],
490
"drive0": [
491
{
492
"busy": false,
493
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
494
{"return": ""}
495
{
496
"bitmaps": {
497
+ "backup-top": [
498
+ {
499
+ "busy": false,
500
+ "count": 67108864,
501
+ "granularity": 65536,
502
+ "persistent": false,
503
+ "recording": false
504
+ },
505
+ {
506
+ "busy": false,
507
+ "count": 458752,
508
+ "granularity": 65536,
509
+ "persistent": false,
510
+ "recording": false
511
+ }
512
+ ],
513
"drive0": [
514
{
515
"busy": false,
516
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
517
{"return": ""}
518
{
519
"bitmaps": {
520
+ "backup-top": [
521
+ {
522
+ "busy": false,
523
+ "count": 67108864,
524
+ "granularity": 65536,
525
+ "persistent": false,
526
+ "recording": false
527
+ },
528
+ {
529
+ "busy": false,
530
+ "count": 458752,
531
+ "granularity": 65536,
532
+ "persistent": false,
533
+ "recording": false
534
+ }
535
+ ],
536
"drive0": [
537
{
538
"busy": false,
539
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
540
{"return": ""}
541
{
542
"bitmaps": {
543
+ "backup-top": [
544
+ {
545
+ "busy": false,
546
+ "count": 67108864,
547
+ "granularity": 65536,
548
+ "persistent": false,
549
+ "recording": false
550
+ },
551
+ {
552
+ "busy": false,
553
+ "count": 458752,
554
+ "granularity": 65536,
555
+ "persistent": false,
556
+ "recording": false
557
+ }
558
+ ],
559
"drive0": [
560
{
561
"busy": false,
562
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
563
{"return": ""}
564
{
565
"bitmaps": {
566
+ "backup-top": [
567
+ {
568
+ "busy": false,
569
+ "count": 67108864,
570
+ "granularity": 65536,
571
+ "persistent": false,
572
+ "recording": false
573
+ },
574
+ {
575
+ "busy": false,
576
+ "count": 458752,
577
+ "granularity": 65536,
578
+ "persistent": false,
579
+ "recording": false
580
+ }
581
+ ],
582
"drive0": [
583
{
584
"busy": false,
585
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
586
{"return": ""}
587
{
588
"bitmaps": {
589
+ "backup-top": [
590
+ {
591
+ "busy": false,
592
+ "count": 67108864,
593
+ "granularity": 65536,
594
+ "persistent": false,
595
+ "recording": false
596
+ },
597
+ {
598
+ "busy": false,
599
+ "count": 458752,
600
+ "granularity": 65536,
601
+ "persistent": false,
602
+ "recording": false
603
+ }
604
+ ],
605
"drive0": [
606
{
607
"busy": false,
608
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
609
{"return": ""}
610
{
611
"bitmaps": {
612
+ "backup-top": [
613
+ {
614
+ "busy": false,
615
+ "count": 67108864,
616
+ "granularity": 65536,
617
+ "persistent": false,
618
+ "recording": false
619
+ },
620
+ {
621
+ "busy": false,
622
+ "count": 458752,
623
+ "granularity": 65536,
624
+ "persistent": false,
625
+ "recording": false
626
+ }
627
+ ],
628
"drive0": [
629
{
630
"busy": false,
631
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
632
{"return": ""}
633
{
634
"bitmaps": {
635
+ "backup-top": [
636
+ {
637
+ "busy": false,
638
+ "count": 67108864,
639
+ "granularity": 65536,
640
+ "persistent": false,
641
+ "recording": false
642
+ },
643
+ {
644
+ "busy": false,
645
+ "count": 458752,
646
+ "granularity": 65536,
647
+ "persistent": false,
648
+ "recording": false
649
+ }
650
+ ],
651
"drive0": [
652
{
653
"busy": false,
654
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
655
{"return": ""}
656
{
657
"bitmaps": {
658
+ "backup-top": [
659
+ {
660
+ "busy": false,
661
+ "count": 67108864,
662
+ "granularity": 65536,
663
+ "persistent": false,
664
+ "recording": false
665
+ },
666
+ {
667
+ "busy": false,
668
+ "count": 458752,
669
+ "granularity": 65536,
670
+ "persistent": false,
671
+ "recording": false
672
+ }
673
+ ],
674
"drive0": [
675
{
676
"busy": false,
677
@@ -XXX,XX +XXX,XX @@ write -P0x67 0x3fe0000 0x20000
678
{"return": ""}
679
{
680
"bitmaps": {
681
+ "backup-top": [
682
+ {
683
+ "busy": false,
684
+ "count": 67108864,
685
+ "granularity": 65536,
686
+ "persistent": false,
687
+ "recording": false
688
+ },
689
+ {
690
+ "busy": false,
691
+ "count": 458752,
692
+ "granularity": 65536,
693
+ "persistent": false,
694
+ "recording": false
695
+ }
696
+ ],
697
"drive0": [
698
{
699
"busy": false,
160
--
700
--
161
2.26.2
701
2.34.1
162
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
When we added io_uring AIO engine, we forgot to update qemu-options.hx,
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
so qemu(1) man page and qemu help were outdated.
4
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
5
Message-Id: <20220303194349.2304213-14-vsementsov@virtuozzo.com>
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
---
8
tests/qemu-iotests/tests/image-fleecing | 64 +++++++++++++-----
9
tests/qemu-iotests/tests/image-fleecing.out | 74 ++++++++++++++++++++-
10
2 files changed, 119 insertions(+), 19 deletions(-)
5
11
6
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
12
diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
index XXXXXXX..XXXXXXX 100755
8
Reviewed-by: Julia Suvorova <jusual@redhat.com>
14
--- a/tests/qemu-iotests/tests/image-fleecing
9
Reviewed-by: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
15
+++ b/tests/qemu-iotests/tests/image-fleecing
10
Message-Id: <20200924151511.131471-1-sgarzare@redhat.com>
16
@@ -XXX,XX +XXX,XX @@ remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1]
11
---
17
('0xdc', '32M', '32k'), # Left-end of partial-right [2]
12
qemu-options.hx | 10 ++++++----
18
('0xcd', '0x3ff0000', '64k')] # patterns[3]
13
1 file changed, 6 insertions(+), 4 deletions(-)
19
14
20
-def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
15
diff --git a/qemu-options.hx b/qemu-options.hx
21
+def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
22
+ fleece_img_path, nbd_sock_path, vm):
23
log('--- Setting up images ---')
24
log('')
25
26
assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
27
- assert qemu_img('create', '-f', 'qcow2', fleece_img_path, '64M') == 0
28
+ if use_snapshot_access_filter:
29
+ assert use_cbw
30
+ assert qemu_img('create', '-f', 'raw', fleece_img_path, '64M') == 0
31
+ else:
32
+ assert qemu_img('create', '-f', 'qcow2', fleece_img_path, '64M') == 0
33
34
for p in patterns:
35
qemu_io('-f', iotests.imgfmt,
36
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
37
log('')
38
39
40
- # create tmp_node backed by src_node
41
- log(vm.qmp('blockdev-add', {
42
- 'driver': 'qcow2',
43
- 'node-name': tmp_node,
44
- 'file': {
45
+ if use_snapshot_access_filter:
46
+ log(vm.qmp('blockdev-add', {
47
+ 'node-name': tmp_node,
48
'driver': 'file',
49
'filename': fleece_img_path,
50
- },
51
- 'backing': src_node,
52
- }))
53
+ }))
54
+ else:
55
+ # create tmp_node backed by src_node
56
+ log(vm.qmp('blockdev-add', {
57
+ 'driver': 'qcow2',
58
+ 'node-name': tmp_node,
59
+ 'file': {
60
+ 'driver': 'file',
61
+ 'filename': fleece_img_path,
62
+ },
63
+ 'backing': src_node,
64
+ }))
65
66
# Establish CBW from source to fleecing node
67
if use_cbw:
68
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
69
}))
70
71
log(vm.qmp('qom-set', path=qom_path, property='drive', value='fl-cbw'))
72
+
73
+ if use_snapshot_access_filter:
74
+ log(vm.qmp('blockdev-add', {
75
+ 'driver': 'snapshot-access',
76
+ 'node-name': 'fl-access',
77
+ 'file': 'fl-cbw',
78
+ }))
79
else:
80
log(vm.qmp('blockdev-backup',
81
job_id='fleecing',
82
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
83
target=tmp_node,
84
sync='none'))
85
86
+ export_node = 'fl-access' if use_snapshot_access_filter else tmp_node
87
+
88
log('')
89
log('--- Setting up NBD Export ---')
90
log('')
91
92
- nbd_uri = 'nbd+unix:///%s?socket=%s' % (tmp_node, nbd_sock_path)
93
+ nbd_uri = 'nbd+unix:///%s?socket=%s' % (export_node, nbd_sock_path)
94
log(vm.qmp('nbd-server-start',
95
{'addr': {'type': 'unix',
96
'data': {'path': nbd_sock_path}}}))
97
98
- log(vm.qmp('nbd-server-add', device=tmp_node))
99
+ log(vm.qmp('nbd-server-add', device=export_node))
100
101
log('')
102
log('--- Sanity Check ---')
103
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
104
log('--- Cleanup ---')
105
log('')
106
107
+ log(vm.qmp('nbd-server-stop'))
108
+
109
if use_cbw:
110
+ if use_snapshot_access_filter:
111
+ log(vm.qmp('blockdev-del', node_name='fl-access'))
112
log(vm.qmp('qom-set', path=qom_path, property='drive', value=src_node))
113
log(vm.qmp('blockdev-del', node_name='fl-cbw'))
114
else:
115
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
116
assert e is not None
117
log(e, filters=[iotests.filter_qmp_event])
118
119
- log(vm.qmp('nbd-server-stop'))
120
log(vm.qmp('blockdev-del', node_name=tmp_node))
121
vm.shutdown()
122
123
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm):
124
log('Done')
125
126
127
-def test(use_cbw):
128
+def test(use_cbw, use_snapshot_access_filter):
129
with iotests.FilePath('base.img') as base_img_path, \
130
iotests.FilePath('fleece.img') as fleece_img_path, \
131
iotests.FilePath('nbd.sock',
132
base_dir=iotests.sock_dir) as nbd_sock_path, \
133
iotests.VM() as vm:
134
- do_test(use_cbw, base_img_path, fleece_img_path, nbd_sock_path, vm)
135
+ do_test(use_cbw, use_snapshot_access_filter, base_img_path,
136
+ fleece_img_path, nbd_sock_path, vm)
137
138
139
log('=== Test backup(sync=none) based fleecing ===\n')
140
-test(False)
141
+test(False, False)
142
+
143
+log('=== Test cbw-filter based fleecing ===\n')
144
+test(True, False)
145
146
-log('=== Test filter based fleecing ===\n')
147
-test(True)
148
+log('=== Test fleecing-format based fleecing ===\n')
149
+test(True, True)
150
diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out
16
index XXXXXXX..XXXXXXX 100644
151
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-options.hx
152
--- a/tests/qemu-iotests/tests/image-fleecing.out
18
+++ b/qemu-options.hx
153
+++ b/tests/qemu-iotests/tests/image-fleecing.out
19
@@ -XXX,XX +XXX,XX @@ SRST
154
@@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k
20
The path to the image file in the local filesystem
155
21
156
--- Cleanup ---
22
``aio``
157
23
- Specifies the AIO backend (threads/native, default: threads)
158
+{"return": {}}
24
+ Specifies the AIO backend (threads/native/io_uring,
159
{"return": {}}
25
+ default: threads)
160
{"data": {"device": "fleecing", "len": 67108864, "offset": 393216, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
26
161
{"return": {}}
27
``locking``
162
+
28
Specifies whether the image file is protected with Linux OFD
163
+--- Confirming writes ---
29
@@ -XXX,XX +XXX,XX @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
164
+
30
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
165
+read -P0xab 0 64k
31
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
166
+read -P0xad 0x00f8000 64k
32
" [,snapshot=on|off][,rerror=ignore|stop|report]\n"
167
+read -P0x1d 0x2008000 64k
33
- " [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
168
+read -P0xea 0x3fe0000 64k
34
+ " [,werror=ignore|stop|report|enospc][,id=name]\n"
169
+read -P0xd5 0x108000 32k
35
+ " [,aio=threads|native|io_uring]\n"
170
+read -P0xdc 32M 32k
36
" [,readonly=on|off][,copy-on-read=on|off]\n"
171
+read -P0xcd 0x3ff0000 64k
37
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
172
+
38
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
173
+Done
39
@@ -XXX,XX +XXX,XX @@ SRST
174
+=== Test cbw-filter based fleecing ===
40
The default mode is ``cache=writeback``.
175
+
41
176
+--- Setting up images ---
42
``aio=aio``
177
+
43
- aio is "threads", or "native" and selects between pthread based
178
+Done
44
- disk I/O and native Linux AIO.
179
+
45
+ aio is "threads", "native", or "io_uring" and selects between pthread
180
+--- Launching VM ---
46
+ based disk I/O, native Linux AIO, or Linux io_uring API.
181
+
47
182
+Done
48
``format=format``
183
+
49
Specify which disk format will be used rather than detecting the
184
+--- Setting up Fleecing Graph ---
185
+
186
+{"return": {}}
187
+{"return": {}}
188
+{"return": {}}
189
+
190
+--- Setting up NBD Export ---
191
+
192
+{"return": {}}
193
+{"return": {}}
194
+
195
+--- Sanity Check ---
196
+
197
+read -P0x5d 0 64k
198
+read -P0xd5 1M 64k
199
+read -P0xdc 32M 64k
200
+read -P0xcd 0x3ff0000 64k
201
+read -P0 0x00f8000 32k
202
+read -P0 0x2010000 32k
203
+read -P0 0x3fe0000 64k
204
+
205
+--- Testing COW ---
206
+
207
+write -P0xab 0 64k
208
+{"return": ""}
209
+write -P0xad 0x00f8000 64k
210
+{"return": ""}
211
+write -P0x1d 0x2008000 64k
212
+{"return": ""}
213
+write -P0xea 0x3fe0000 64k
214
+{"return": ""}
215
+
216
+--- Verifying Data ---
217
+
218
+read -P0x5d 0 64k
219
+read -P0xd5 1M 64k
220
+read -P0xdc 32M 64k
221
+read -P0xcd 0x3ff0000 64k
222
+read -P0 0x00f8000 32k
223
+read -P0 0x2010000 32k
224
+read -P0 0x3fe0000 64k
225
+
226
+--- Cleanup ---
227
+
228
+{"return": {}}
229
+{"return": {}}
230
+{"return": {}}
231
{"return": {}}
232
233
--- Confirming writes ---
234
@@ -XXX,XX +XXX,XX @@ read -P0xdc 32M 32k
235
read -P0xcd 0x3ff0000 64k
236
237
Done
238
-=== Test filter based fleecing ===
239
+=== Test fleecing-format based fleecing ===
240
241
--- Setting up images ---
242
243
@@ -XXX,XX +XXX,XX @@ Done
244
{"return": {}}
245
{"return": {}}
246
{"return": {}}
247
+{"return": {}}
248
249
--- Setting up NBD Export ---
250
251
@@ -XXX,XX +XXX,XX @@ read -P0 0x3fe0000 64k
252
{"return": {}}
253
{"return": {}}
254
{"return": {}}
255
+{"return": {}}
256
257
--- Confirming writes ---
258
50
--
259
--
51
2.26.2
260
2.34.1
52
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Use self-explicit SCALE_MS definition instead of magic value
3
Add helper that returns both status and output, to be used in the
4
(missed in similar commit e4f310fe7f5).
4
following commit
5
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-Id: <20220303194349.2304213-15-vsementsov@virtuozzo.com>
8
Message-Id: <20200922083821.578519-7-philmd@redhat.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
9
---
10
block/nvme.c | 2 +-
10
tests/qemu-iotests/iotests.py | 3 +++
11
1 file changed, 1 insertion(+), 1 deletion(-)
11
1 file changed, 3 insertions(+)
12
12
13
diff --git a/block/nvme.c b/block/nvme.c
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
15
--- a/tests/qemu-iotests/iotests.py
16
+++ b/block/nvme.c
16
+++ b/tests/qemu-iotests/iotests.py
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
17
@@ -XXX,XX +XXX,XX @@ def qemu_io(*args):
18
CC_EN_MASK);
18
'''Run qemu-io and return the stdout data'''
19
/* Wait for CSTS.RDY = 1. */
19
return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))[0]
20
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
20
21
- deadline = now + timeout_ms * 1000000;
21
+def qemu_io_pipe_and_status(*args):
22
+ deadline = now + timeout_ms * SCALE_MS;
22
+ return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))
23
while (!NVME_CSTS_RDY(le32_to_cpu(regs->csts))) {
23
+
24
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
24
def qemu_io_log(*args):
25
error_setg(errp, "Timeout while waiting for device to start (%"
25
result = qemu_io(*args)
26
log(result, filters=[filter_testfiles, filter_qemu_io])
26
--
27
--
27
2.26.2
28
2.34.1
28
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
NVMeRegs only contains NvmeBar. Simplify the code by using NvmeBar
3
Note that reads zero areas (not dirty in the bitmap) fails, that's
4
directly.
4
correct.
5
5
6
This triggers a checkpatch.pl error:
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-Id: <20220303194349.2304213-16-vsementsov@virtuozzo.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
10
tests/qemu-iotests/tests/image-fleecing | 38 +++++++---
11
tests/qemu-iotests/tests/image-fleecing.out | 84 +++++++++++++++++++++
12
2 files changed, 113 insertions(+), 9 deletions(-)
7
13
8
ERROR: Use of volatile is usually wrong, please add a comment
14
diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing
9
#30: FILE: block/nvme.c:691:
15
index XXXXXXX..XXXXXXX 100755
10
+ volatile NvmeBar *regs;
16
--- a/tests/qemu-iotests/tests/image-fleecing
11
17
+++ b/tests/qemu-iotests/tests/image-fleecing
12
This is a false positive as in our case we are using I/O registers,
18
@@ -XXX,XX +XXX,XX @@
13
so the 'volatile' use is justified.
19
# Creator/Owner: John Snow <jsnow@redhat.com>
14
20
15
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
21
import iotests
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
-from iotests import log, qemu_img, qemu_io, qemu_io_silent
17
Message-Id: <20200922083821.578519-5-philmd@redhat.com>
23
+from iotests import log, qemu_img, qemu_io, qemu_io_silent, \
18
---
24
+ qemu_io_pipe_and_status
19
block/nvme.c | 23 +++++++++--------------
25
20
1 file changed, 9 insertions(+), 14 deletions(-)
26
iotests.script_initialize(
21
27
- supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', 'vhdx', 'raw'],
22
diff --git a/block/nvme.c b/block/nvme.c
28
+ supported_fmts=['qcow2'],
29
supported_platforms=['linux'],
30
required_fmts=['copy-before-write'],
31
+ unsupported_imgopts=['compat']
32
)
33
34
patterns = [('0x5d', '0', '64k'),
35
@@ -XXX,XX +XXX,XX @@ remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1]
36
('0xcd', '0x3ff0000', '64k')] # patterns[3]
37
38
def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
39
- fleece_img_path, nbd_sock_path, vm):
40
+ fleece_img_path, nbd_sock_path, vm,
41
+ bitmap=False):
42
log('--- Setting up images ---')
43
log('')
44
45
assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
46
+ if bitmap:
47
+ assert qemu_img('bitmap', '--add', base_img_path, 'bitmap0') == 0
48
+
49
if use_snapshot_access_filter:
50
assert use_cbw
51
assert qemu_img('create', '-f', 'raw', fleece_img_path, '64M') == 0
52
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
53
54
# Establish CBW from source to fleecing node
55
if use_cbw:
56
- log(vm.qmp('blockdev-add', {
57
+ fl_cbw = {
58
'driver': 'copy-before-write',
59
'node-name': 'fl-cbw',
60
'file': src_node,
61
'target': tmp_node
62
- }))
63
+ }
64
+
65
+ if bitmap:
66
+ fl_cbw['bitmap'] = {'node': src_node, 'name': 'bitmap0'}
67
+
68
+ log(vm.qmp('blockdev-add', fl_cbw))
69
70
log(vm.qmp('qom-set', path=qom_path, property='drive', value='fl-cbw'))
71
72
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
73
for p in patterns + zeroes:
74
cmd = 'read -P%s %s %s' % p
75
log(cmd)
76
- assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0
77
+ out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd,
78
+ nbd_uri)
79
+ if ret != 0:
80
+ print(out)
81
82
log('')
83
log('--- Testing COW ---')
84
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
85
for p in patterns + zeroes:
86
cmd = 'read -P%s %s %s' % p
87
log(cmd)
88
- assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0
89
+ out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd,
90
+ nbd_uri)
91
+ if ret != 0:
92
+ print(out)
93
94
log('')
95
log('--- Cleanup ---')
96
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
97
log('Done')
98
99
100
-def test(use_cbw, use_snapshot_access_filter):
101
+def test(use_cbw, use_snapshot_access_filter, bitmap=False):
102
with iotests.FilePath('base.img') as base_img_path, \
103
iotests.FilePath('fleece.img') as fleece_img_path, \
104
iotests.FilePath('nbd.sock',
105
base_dir=iotests.sock_dir) as nbd_sock_path, \
106
iotests.VM() as vm:
107
do_test(use_cbw, use_snapshot_access_filter, base_img_path,
108
- fleece_img_path, nbd_sock_path, vm)
109
+ fleece_img_path, nbd_sock_path, vm, bitmap=bitmap)
110
111
112
log('=== Test backup(sync=none) based fleecing ===\n')
113
@@ -XXX,XX +XXX,XX @@ test(True, False)
114
115
log('=== Test fleecing-format based fleecing ===\n')
116
test(True, True)
117
+
118
+log('=== Test fleecing-format based fleecing with bitmap ===\n')
119
+test(True, True, bitmap=True)
120
diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out
23
index XXXXXXX..XXXXXXX 100644
121
index XXXXXXX..XXXXXXX 100644
24
--- a/block/nvme.c
122
--- a/tests/qemu-iotests/tests/image-fleecing.out
25
+++ b/block/nvme.c
123
+++ b/tests/qemu-iotests/tests/image-fleecing.out
26
@@ -XXX,XX +XXX,XX @@ typedef struct {
124
@@ -XXX,XX +XXX,XX @@ read -P0 0x00f8000 32k
27
QEMUBH *completion_bh;
125
read -P0 0x2010000 32k
28
} NVMeQueuePair;
126
read -P0 0x3fe0000 64k
29
127
30
-/* Memory mapped registers */
128
+--- Cleanup ---
31
-typedef volatile struct {
129
+
32
- NvmeBar ctrl;
130
+{"return": {}}
33
-} NVMeRegs;
131
+{"return": {}}
34
-
132
+{"return": {}}
35
#define INDEX_ADMIN 0
133
+{"return": {}}
36
#define INDEX_IO(n) (1 + n)
134
+{"return": {}}
37
135
+
38
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
136
+--- Confirming writes ---
39
uint64_t timeout_ms;
137
+
40
uint64_t deadline, now;
138
+read -P0xab 0 64k
41
Error *local_err = NULL;
139
+read -P0xad 0x00f8000 64k
42
- NVMeRegs *regs;
140
+read -P0x1d 0x2008000 64k
43
+ volatile NvmeBar *regs = NULL;
141
+read -P0xea 0x3fe0000 64k
44
142
+read -P0xd5 0x108000 32k
45
qemu_co_mutex_init(&s->dma_map_lock);
143
+read -P0xdc 32M 32k
46
qemu_co_queue_init(&s->dma_flush_queue);
144
+read -P0xcd 0x3ff0000 64k
47
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
145
+
48
/* Perform initialize sequence as described in NVMe spec "7.6.1
146
+Done
49
* Initialization". */
147
+=== Test fleecing-format based fleecing with bitmap ===
50
148
+
51
- cap = le64_to_cpu(regs->ctrl.cap);
149
+--- Setting up images ---
52
+ cap = le64_to_cpu(regs->cap);
150
+
53
if (!(cap & (1ULL << 37))) {
151
+Done
54
error_setg(errp, "Device doesn't support NVMe command set");
152
+
55
ret = -EINVAL;
153
+--- Launching VM ---
56
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
154
+
57
timeout_ms = MIN(500 * ((cap >> 24) & 0xFF), 30000);
155
+Done
58
156
+
59
/* Reset device to get a clean state. */
157
+--- Setting up Fleecing Graph ---
60
- regs->ctrl.cc = cpu_to_le32(le32_to_cpu(regs->ctrl.cc) & 0xFE);
158
+
61
+ regs->cc = cpu_to_le32(le32_to_cpu(regs->cc) & 0xFE);
159
+{"return": {}}
62
/* Wait for CSTS.RDY = 0. */
160
+{"return": {}}
63
deadline = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ms * SCALE_MS;
161
+{"return": {}}
64
- while (le32_to_cpu(regs->ctrl.csts) & 0x1) {
162
+{"return": {}}
65
+ while (le32_to_cpu(regs->csts) & 0x1) {
163
+
66
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
164
+--- Setting up NBD Export ---
67
error_setg(errp, "Timeout while waiting for device to reset (%"
165
+
68
PRId64 " ms)",
166
+{"return": {}}
69
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
167
+{"return": {}}
70
}
168
+
71
s->nr_queues = 1;
169
+--- Sanity Check ---
72
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
170
+
73
- regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
171
+read -P0x5d 0 64k
74
- regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
172
+read -P0xd5 1M 64k
75
- regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
173
+read -P0xdc 32M 64k
76
+ regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
174
+read -P0xcd 0x3ff0000 64k
77
+ regs->asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
175
+read -P0 0x00f8000 32k
78
+ regs->acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
176
+read failed: Invalid argument
79
177
+
80
/* After setting up all control registers we can enable device now. */
178
+read -P0 0x2010000 32k
81
- regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
179
+read failed: Invalid argument
82
+ regs->cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
180
+
83
(ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
181
+read -P0 0x3fe0000 64k
84
0x1);
182
+read failed: Invalid argument
85
/* Wait for CSTS.RDY = 1. */
183
+
86
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
184
+
87
deadline = now + timeout_ms * 1000000;
185
+--- Testing COW ---
88
- while (!(le32_to_cpu(regs->ctrl.csts) & 0x1)) {
186
+
89
+ while (!(le32_to_cpu(regs->csts) & 0x1)) {
187
+write -P0xab 0 64k
90
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
188
+{"return": ""}
91
error_setg(errp, "Timeout while waiting for device to start (%"
189
+write -P0xad 0x00f8000 64k
92
PRId64 " ms)",
190
+{"return": ""}
191
+write -P0x1d 0x2008000 64k
192
+{"return": ""}
193
+write -P0xea 0x3fe0000 64k
194
+{"return": ""}
195
+
196
+--- Verifying Data ---
197
+
198
+read -P0x5d 0 64k
199
+read -P0xd5 1M 64k
200
+read -P0xdc 32M 64k
201
+read -P0xcd 0x3ff0000 64k
202
+read -P0 0x00f8000 32k
203
+read failed: Invalid argument
204
+
205
+read -P0 0x2010000 32k
206
+read failed: Invalid argument
207
+
208
+read -P0 0x3fe0000 64k
209
+read failed: Invalid argument
210
+
211
+
212
--- Cleanup ---
213
214
{"return": {}}
93
--
215
--
94
2.26.2
216
2.34.1
95
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We only access the I/O register in nvme_init().
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Remove the reference in BDRVNVMeState and reduce its scope.
4
Message-Id: <20220303194349.2304213-17-vsementsov@virtuozzo.com>
5
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
6
---
7
tests/qemu-iotests/tests/image-fleecing | 125 +++++++++++++++-----
8
tests/qemu-iotests/tests/image-fleecing.out | 63 ++++++++++
9
2 files changed, 156 insertions(+), 32 deletions(-)
5
10
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
index XXXXXXX..XXXXXXX 100755
8
Message-Id: <20200922083821.578519-4-philmd@redhat.com>
13
--- a/tests/qemu-iotests/tests/image-fleecing
9
---
14
+++ b/tests/qemu-iotests/tests/image-fleecing
10
block/nvme.c | 29 ++++++++++++++++-------------
15
@@ -XXX,XX +XXX,XX @@ remainder = [('0xd5', '0x108000', '32k'), # Right-end of partial-left [1]
11
1 file changed, 16 insertions(+), 13 deletions(-)
16
('0xdc', '32M', '32k'), # Left-end of partial-right [2]
12
17
('0xcd', '0x3ff0000', '64k')] # patterns[3]
13
diff --git a/block/nvme.c b/block/nvme.c
18
19
-def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
20
- fleece_img_path, nbd_sock_path, vm,
21
+def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path,
22
+ fleece_img_path, nbd_sock_path=None,
23
+ target_img_path=None,
24
bitmap=False):
25
+ push_backup = target_img_path is not None
26
+ assert (nbd_sock_path is not None) != push_backup
27
+ if push_backup:
28
+ assert use_cbw
29
+
30
log('--- Setting up images ---')
31
log('')
32
33
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
34
else:
35
assert qemu_img('create', '-f', 'qcow2', fleece_img_path, '64M') == 0
36
37
+ if push_backup:
38
+ assert qemu_img('create', '-f', 'qcow2', target_img_path, '64M') == 0
39
+
40
for p in patterns:
41
qemu_io('-f', iotests.imgfmt,
42
'-c', 'write -P%s %s %s' % p, base_img_path)
43
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
44
45
export_node = 'fl-access' if use_snapshot_access_filter else tmp_node
46
47
- log('')
48
- log('--- Setting up NBD Export ---')
49
- log('')
50
+ if push_backup:
51
+ log('')
52
+ log('--- Starting actual backup ---')
53
+ log('')
54
55
- nbd_uri = 'nbd+unix:///%s?socket=%s' % (export_node, nbd_sock_path)
56
- log(vm.qmp('nbd-server-start',
57
- {'addr': {'type': 'unix',
58
- 'data': {'path': nbd_sock_path}}}))
59
+ log(vm.qmp('blockdev-add', **{
60
+ 'driver': iotests.imgfmt,
61
+ 'node-name': 'target',
62
+ 'file': {
63
+ 'driver': 'file',
64
+ 'filename': target_img_path
65
+ }
66
+ }))
67
+ log(vm.qmp('blockdev-backup', device=export_node,
68
+ sync='full', target='target',
69
+ job_id='push-backup', speed=1))
70
+ else:
71
+ log('')
72
+ log('--- Setting up NBD Export ---')
73
+ log('')
74
75
- log(vm.qmp('nbd-server-add', device=export_node))
76
+ nbd_uri = 'nbd+unix:///%s?socket=%s' % (export_node, nbd_sock_path)
77
+ log(vm.qmp('nbd-server-start',
78
+ {'addr': { 'type': 'unix',
79
+ 'data': { 'path': nbd_sock_path } } }))
80
81
- log('')
82
- log('--- Sanity Check ---')
83
- log('')
84
+ log(vm.qmp('nbd-server-add', device=export_node))
85
86
- for p in patterns + zeroes:
87
- cmd = 'read -P%s %s %s' % p
88
- log(cmd)
89
- out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd,
90
- nbd_uri)
91
- if ret != 0:
92
- print(out)
93
+ log('')
94
+ log('--- Sanity Check ---')
95
+ log('')
96
+
97
+ for p in patterns + zeroes:
98
+ cmd = 'read -P%s %s %s' % p
99
+ log(cmd)
100
+ out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd,
101
+ nbd_uri)
102
+ if ret != 0:
103
+ print(out)
104
105
log('')
106
log('--- Testing COW ---')
107
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
108
log(cmd)
109
log(vm.hmp_qemu_io(qom_path, cmd, qdev=True))
110
111
+ if push_backup:
112
+ # Check that previous operations were done during backup, not after
113
+ # If backup is already finished, it's possible that it was finished
114
+ # even before hmp qemu_io write, and we didn't actually test
115
+ # copy-before-write operation. This should not happen, as we use
116
+ # speed=1. But worth checking.
117
+ result = vm.qmp('query-block-jobs')
118
+ assert len(result['return']) == 1
119
+
120
+ result = vm.qmp('block-job-set-speed', device='push-backup', speed=0)
121
+ assert result == {'return': {}}
122
+
123
+ log(vm.event_wait(name='BLOCK_JOB_COMPLETED',
124
+ match={'data': {'device': 'push-backup'}}),
125
+ filters=[iotests.filter_qmp_event])
126
+ log(vm.qmp('blockdev-del', node_name='target'))
127
+
128
log('')
129
log('--- Verifying Data ---')
130
log('')
131
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
132
for p in patterns + zeroes:
133
cmd = 'read -P%s %s %s' % p
134
log(cmd)
135
- out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd,
136
- nbd_uri)
137
+ args = ['-r', '-c', cmd]
138
+ if push_backup:
139
+ args += [target_img_path]
140
+ else:
141
+ args += ['-f', 'raw', nbd_uri]
142
+ out, ret = qemu_io_pipe_and_status(*args)
143
if ret != 0:
144
print(out)
145
146
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
147
log('--- Cleanup ---')
148
log('')
149
150
- log(vm.qmp('nbd-server-stop'))
151
+ if not push_backup:
152
+ log(vm.qmp('nbd-server-stop'))
153
154
if use_cbw:
155
if use_snapshot_access_filter:
156
@@ -XXX,XX +XXX,XX @@ def do_test(use_cbw, use_snapshot_access_filter, base_img_path,
157
log('Done')
158
159
160
-def test(use_cbw, use_snapshot_access_filter, bitmap=False):
161
+def test(use_cbw, use_snapshot_access_filter,
162
+ nbd_sock_path=None, target_img_path=None, bitmap=False):
163
with iotests.FilePath('base.img') as base_img_path, \
164
iotests.FilePath('fleece.img') as fleece_img_path, \
165
- iotests.FilePath('nbd.sock',
166
- base_dir=iotests.sock_dir) as nbd_sock_path, \
167
iotests.VM() as vm:
168
- do_test(use_cbw, use_snapshot_access_filter, base_img_path,
169
- fleece_img_path, nbd_sock_path, vm, bitmap=bitmap)
170
+ do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path,
171
+ fleece_img_path, nbd_sock_path, target_img_path,
172
+ bitmap=bitmap)
173
+
174
+def test_pull(use_cbw, use_snapshot_access_filter, bitmap=False):
175
+ with iotests.FilePath('nbd.sock',
176
+ base_dir=iotests.sock_dir) as nbd_sock_path:
177
+ test(use_cbw, use_snapshot_access_filter, nbd_sock_path, None,
178
+ bitmap=bitmap)
179
+
180
+def test_push():
181
+ with iotests.FilePath('target.img') as target_img_path:
182
+ test(True, True, None, target_img_path)
183
184
185
log('=== Test backup(sync=none) based fleecing ===\n')
186
-test(False, False)
187
+test_pull(False, False)
188
189
log('=== Test cbw-filter based fleecing ===\n')
190
-test(True, False)
191
+test_pull(True, False)
192
193
log('=== Test fleecing-format based fleecing ===\n')
194
-test(True, True)
195
+test_pull(True, True)
196
197
log('=== Test fleecing-format based fleecing with bitmap ===\n')
198
-test(True, True, bitmap=True)
199
+test_pull(True, True, bitmap=True)
200
+
201
+log('=== Test push backup with fleecing ===\n')
202
+test_push()
203
diff --git a/tests/qemu-iotests/tests/image-fleecing.out b/tests/qemu-iotests/tests/image-fleecing.out
14
index XXXXXXX..XXXXXXX 100644
204
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
205
--- a/tests/qemu-iotests/tests/image-fleecing.out
16
+++ b/block/nvme.c
206
+++ b/tests/qemu-iotests/tests/image-fleecing.out
17
@@ -XXX,XX +XXX,XX @@ enum {
207
@@ -XXX,XX +XXX,XX @@ read -P0xdc 32M 32k
18
struct BDRVNVMeState {
208
read -P0xcd 0x3ff0000 64k
19
AioContext *aio_context;
209
20
QEMUVFIOState *vfio;
210
Done
21
- NVMeRegs *regs;
211
+=== Test push backup with fleecing ===
22
/* Memory mapped registers */
212
+
23
volatile struct {
213
+--- Setting up images ---
24
uint32_t sq_tail;
214
+
25
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
215
+Done
26
uint64_t timeout_ms;
216
+
27
uint64_t deadline, now;
217
+--- Launching VM ---
28
Error *local_err = NULL;
218
+
29
+ NVMeRegs *regs;
219
+Done
30
220
+
31
qemu_co_mutex_init(&s->dma_map_lock);
221
+--- Setting up Fleecing Graph ---
32
qemu_co_queue_init(&s->dma_flush_queue);
222
+
33
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
223
+{"return": {}}
34
goto out;
224
+{"return": {}}
35
}
225
+{"return": {}}
36
226
+{"return": {}}
37
- s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, sizeof(NvmeBar),
227
+
38
- PROT_READ | PROT_WRITE, errp);
228
+--- Starting actual backup ---
39
- if (!s->regs) {
229
+
40
+ regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, sizeof(NvmeBar),
230
+{"return": {}}
41
+ PROT_READ | PROT_WRITE, errp);
231
+{"return": {}}
42
+ if (!regs) {
232
+
43
ret = -EINVAL;
233
+--- Testing COW ---
44
goto out;
234
+
45
}
235
+write -P0xab 0 64k
46
/* Perform initialize sequence as described in NVMe spec "7.6.1
236
+{"return": ""}
47
* Initialization". */
237
+write -P0xad 0x00f8000 64k
48
238
+{"return": ""}
49
- cap = le64_to_cpu(s->regs->ctrl.cap);
239
+write -P0x1d 0x2008000 64k
50
+ cap = le64_to_cpu(regs->ctrl.cap);
240
+{"return": ""}
51
if (!(cap & (1ULL << 37))) {
241
+write -P0xea 0x3fe0000 64k
52
error_setg(errp, "Device doesn't support NVMe command set");
242
+{"return": ""}
53
ret = -EINVAL;
243
+{"data": {"device": "push-backup", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
54
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
244
+{"return": {}}
55
timeout_ms = MIN(500 * ((cap >> 24) & 0xFF), 30000);
245
+
56
246
+--- Verifying Data ---
57
/* Reset device to get a clean state. */
247
+
58
- s->regs->ctrl.cc = cpu_to_le32(le32_to_cpu(s->regs->ctrl.cc) & 0xFE);
248
+read -P0x5d 0 64k
59
+ regs->ctrl.cc = cpu_to_le32(le32_to_cpu(regs->ctrl.cc) & 0xFE);
249
+read -P0xd5 1M 64k
60
/* Wait for CSTS.RDY = 0. */
250
+read -P0xdc 32M 64k
61
deadline = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ms * SCALE_MS;
251
+read -P0xcd 0x3ff0000 64k
62
- while (le32_to_cpu(s->regs->ctrl.csts) & 0x1) {
252
+read -P0 0x00f8000 32k
63
+ while (le32_to_cpu(regs->ctrl.csts) & 0x1) {
253
+read -P0 0x2010000 32k
64
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
254
+read -P0 0x3fe0000 64k
65
error_setg(errp, "Timeout while waiting for device to reset (%"
255
+
66
PRId64 " ms)",
256
+--- Cleanup ---
67
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
257
+
68
}
258
+{"return": {}}
69
s->nr_queues = 1;
259
+{"return": {}}
70
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
260
+{"return": {}}
71
- s->regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
261
+{"return": {}}
72
- s->regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
262
+
73
- s->regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
263
+--- Confirming writes ---
74
+ regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
264
+
75
+ regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
265
+read -P0xab 0 64k
76
+ regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
266
+read -P0xad 0x00f8000 64k
77
267
+read -P0x1d 0x2008000 64k
78
/* After setting up all control registers we can enable device now. */
268
+read -P0xea 0x3fe0000 64k
79
- s->regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
269
+read -P0xd5 0x108000 32k
80
+ regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
270
+read -P0xdc 32M 32k
81
(ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
271
+read -P0xcd 0x3ff0000 64k
82
0x1);
272
+
83
/* Wait for CSTS.RDY = 1. */
273
+Done
84
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
85
deadline = now + timeout_ms * 1000000;
86
- while (!(le32_to_cpu(s->regs->ctrl.csts) & 0x1)) {
87
+ while (!(le32_to_cpu(regs->ctrl.csts) & 0x1)) {
88
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
89
error_setg(errp, "Timeout while waiting for device to start (%"
90
PRId64 " ms)",
91
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
92
ret = -EIO;
93
}
94
out:
95
+ if (regs) {
96
+ qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)regs, 0, sizeof(NvmeBar));
97
+ }
98
+
99
/* Cleaning up is done in nvme_file_open() upon error. */
100
return ret;
101
}
102
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
103
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
104
qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->doorbells,
105
sizeof(NvmeBar), NVME_DOORBELL_SIZE);
106
- qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, sizeof(NvmeBar));
107
qemu_vfio_close(s->vfio);
108
109
g_free(s->device);
110
--
274
--
111
2.26.2
275
2.34.1
112
diff view generated by jsdifflib