1
The following changes since commit 418fa86dd465b4fd8394373cf83db8fa65d7611c:
1
The following changes since commit 469e72ab7dbbd7ff4ee601e5ea7c29545d46593b:
2
2
3
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-040220-1' into staging (2020-02-04 18:55:06 +0000)
3
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2020-10-02 16:19:42 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-02-06
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to a541fcc27c98b96da187c7d4573f3270f3ddd283:
9
for you to fetch changes up to 9ab5741164b1727d22f69fe7001382baf0d56977:
10
10
11
iotests: add test for backup-top failure on permission activation (2020-02-06 13:47:45 +0100)
11
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved regions (2020-10-05 10:59:42 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- Drop BDRV_SECTOR_SIZE from qcow2
15
16
- Allow Python iotests to be added to the auto group
16
v2:
17
(and add some)
17
* Removed clang-format call from scripts/block-coroutine-wrapper.py. This
18
- Fix for the backup job
18
avoids the issue with clang version incompatibility. It could be added back
19
- Fix memleak in bdrv_refresh_filename()
19
in the future but the code is readable without reformatting and it also
20
- Use GStrings in two places for greater efficiency (than manually
20
makes the build less dependent on the environment.
21
handling string allocation)
22
21
23
----------------------------------------------------------------
22
----------------------------------------------------------------
24
Alberto Garcia (8):
25
qcow2: Assert that host cluster offsets fit in L2 table entries
26
block: Use a GString in bdrv_perm_names()
27
qcow2: Use a GString in report_unsupported_feature()
28
qcow2: Don't round the L1 table allocation up to the sector size
29
qcow2: Tighten cluster_offset alignment assertions
30
qcow2: Use bs->bl.request_alignment when updating an L1 entry
31
qcow2: Don't require aligned offsets in qcow2_co_copy_range_from()
32
qcow2: Use BDRV_SECTOR_SIZE instead of the hardcoded value
33
23
34
John Snow (1):
24
Eric Auger (2):
35
iotests: remove 'linux' from default supported platforms
25
util/vfio-helpers: Collect IOVA reserved regions
26
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved
27
regions
36
28
37
Pan Nengyuan (1):
29
Philippe Mathieu-Daudé (6):
38
block: fix memleaks in bdrv_refresh_filename
30
util/vfio-helpers: Pass page protections to qemu_vfio_pci_map_bar()
31
block/nvme: Map doorbells pages write-only
32
block/nvme: Reduce I/O registers scope
33
block/nvme: Drop NVMeRegs structure, directly use NvmeBar
34
block/nvme: Use register definitions from 'block/nvme.h'
35
block/nvme: Replace magic value by SCALE_MS definition
39
36
40
Thomas Huth (5):
37
Stefano Garzarella (1):
41
iotests: Test 041 only works on certain systems
38
docs: add 'io_uring' option to 'aio' param in qemu-options.hx
42
iotests: Test 183 does not work on macOS and OpenBSD
43
iotests: Check for the availability of the required devices in 267 and
44
127
45
iotests: Skip Python-based tests if QEMU does not support virtio-blk
46
iotests: Enable more tests in the 'auto' group to improve test
47
coverage
48
39
49
Vladimir Sementsov-Ogievskiy (2):
40
Vladimir Sementsov-Ogievskiy (8):
50
block/backup-top: fix failure path
41
block: return error-code from bdrv_invalidate_cache
51
iotests: add test for backup-top failure on permission activation
42
block/io: refactor coroutine wrappers
43
block: declare some coroutine functions in block/coroutines.h
44
scripts: add block-coroutine-wrapper.py
45
block: generate coroutine-wrapper code
46
block: drop bdrv_prwv
47
block/io: refactor save/load vmstate
48
include/block/block.h: drop non-ascii quotation mark
52
49
53
block.c | 12 +++--
50
block/block-gen.h | 49 ++++
54
block/backup-top.c | 21 ++++----
51
block/coroutines.h | 65 +++++
55
block/qcow2-cluster.c | 44 +++++++++++------
52
include/block/block.h | 36 ++-
56
block/qcow2-refcount.c | 2 +-
53
include/qemu/vfio-helpers.h | 2 +-
57
block/qcow2-snapshot.c | 3 +-
54
block.c | 97 +------
58
block/qcow2.c | 46 ++++++++----------
55
block/io.c | 339 ++++---------------------
59
tests/qemu-iotests/041 | 3 +-
56
block/nvme.c | 73 +++---
60
tests/qemu-iotests/127 | 2 +
57
tests/test-bdrv-drain.c | 2 +-
61
tests/qemu-iotests/183 | 1 +
58
util/vfio-helpers.c | 133 +++++++++-
62
tests/qemu-iotests/267 | 2 +
59
block/meson.build | 8 +
63
tests/qemu-iotests/283 | 92 +++++++++++++++++++++++++++++++++++
60
docs/devel/block-coroutine-wrapper.rst | 54 ++++
64
tests/qemu-iotests/283.out | 8 +++
61
docs/devel/index.rst | 1 +
65
tests/qemu-iotests/check | 12 ++++-
62
qemu-options.hx | 10 +-
66
tests/qemu-iotests/common.rc | 14 ++++++
63
scripts/block-coroutine-wrapper.py | 167 ++++++++++++
67
tests/qemu-iotests/group | 15 +++---
64
14 files changed, 608 insertions(+), 428 deletions(-)
68
tests/qemu-iotests/iotests.py | 16 ++++--
65
create mode 100644 block/block-gen.h
69
16 files changed, 220 insertions(+), 73 deletions(-)
66
create mode 100644 block/coroutines.h
70
create mode 100644 tests/qemu-iotests/283
67
create mode 100644 docs/devel/block-coroutine-wrapper.rst
71
create mode 100644 tests/qemu-iotests/283.out
68
create mode 100644 scripts/block-coroutine-wrapper.py
72
69
73
--
70
--
74
2.24.1
71
2.26.2
75
72
76
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
qemu-img's convert_co_copy_range() operates at the sector level and
3
Pages are currently mapped READ/WRITE. To be able to use different
4
block_copy() operates at the cluster level so this condition is always
4
protections, add a new argument to qemu_vfio_pci_map_bar().
5
true, but it is not necessary to restrict this here, so let's leave it
6
to the driver implementation return an error if there is any.
7
5
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: a4264aaee656910c84161a2965f7a501437379ca.1579374329.git.berto@igalia.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200922083821.578519-2-philmd@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
9
---
13
block/qcow2.c | 4 ----
10
include/qemu/vfio-helpers.h | 2 +-
14
1 file changed, 4 deletions(-)
11
block/nvme.c | 3 ++-
12
util/vfio-helpers.c | 4 ++--
13
3 files changed, 5 insertions(+), 4 deletions(-)
15
14
16
diff --git a/block/qcow2.c b/block/qcow2.c
15
diff --git a/include/qemu/vfio-helpers.h b/include/qemu/vfio-helpers.h
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
17
--- a/include/qemu/vfio-helpers.h
19
+++ b/block/qcow2.c
18
+++ b/include/qemu/vfio-helpers.h
20
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
19
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size,
21
case QCOW2_CLUSTER_NORMAL:
20
int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s);
22
child = s->data_file;
21
void qemu_vfio_dma_unmap(QEMUVFIOState *s, void *host);
23
copy_offset += offset_into_cluster(s, src_offset);
22
void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index,
24
- if ((copy_offset & 511) != 0) {
23
- uint64_t offset, uint64_t size,
25
- ret = -EIO;
24
+ uint64_t offset, uint64_t size, int prot,
26
- goto out;
25
Error **errp);
27
- }
26
void qemu_vfio_pci_unmap_bar(QEMUVFIOState *s, int index, void *bar,
28
break;
27
uint64_t offset, uint64_t size);
29
28
diff --git a/block/nvme.c b/block/nvme.c
30
default:
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/nvme.c
31
+++ b/block/nvme.c
32
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
33
goto out;
34
}
35
36
- s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE, errp);
37
+ s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, NVME_BAR_SIZE,
38
+ PROT_READ | PROT_WRITE, errp);
39
if (!s->regs) {
40
ret = -EINVAL;
41
goto out;
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");
31
--
62
--
32
2.24.1
63
2.26.2
33
64
34
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
This replaces all remaining instances in the qcow2 code.
3
Per the datasheet sections 3.1.13/3.1.14:
4
"The host should not read the doorbell registers."
4
5
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
As we don't need read access, map the doorbells with write-only
6
Message-id: b5f74b606c2d9873b12d29acdb7fd498029c4025.1579374329.git.berto@igalia.com
7
permission. We keep a reference to this mapped address in the
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
BDRVNVMeState structure.
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
10
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200922083821.578519-3-philmd@redhat.com>
9
---
13
---
10
block/qcow2.c | 8 +++++---
14
block/nvme.c | 29 +++++++++++++++++++----------
11
1 file changed, 5 insertions(+), 3 deletions(-)
15
1 file changed, 19 insertions(+), 10 deletions(-)
12
16
13
diff --git a/block/qcow2.c b/block/qcow2.c
17
diff --git a/block/nvme.c b/block/nvme.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
19
--- a/block/nvme.c
16
+++ b/block/qcow2.c
20
+++ b/block/nvme.c
17
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
21
@@ -XXX,XX +XXX,XX @@
18
22
#define NVME_SQ_ENTRY_BYTES 64
19
/* Validate options and set default values */
23
#define NVME_CQ_ENTRY_BYTES 16
20
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
24
#define NVME_QUEUE_SIZE 128
21
- error_setg(errp, "Image size must be a multiple of 512 bytes");
25
-#define NVME_BAR_SIZE 8192
22
+ error_setg(errp, "Image size must be a multiple of %u bytes",
26
+#define NVME_DOORBELL_SIZE 4096
23
+ (unsigned) BDRV_SECTOR_SIZE);
27
28
/*
29
* We have to leave one slot empty as that is the full queue case where
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
/* Memory mapped registers */
32
typedef volatile struct {
33
NvmeBar ctrl;
34
- struct {
35
- uint32_t sq_tail;
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) {
24
ret = -EINVAL;
78
ret = -EINVAL;
25
goto out;
79
goto out;
26
}
80
}
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
81
-
28
return -ENOTSUP;
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
}
29
}
87
}
30
88
31
- if (offset & 511) {
89
+ s->doorbells = qemu_vfio_pci_map_bar(s->vfio, 0, sizeof(NvmeBar),
32
- error_setg(errp, "The new size must be a multiple of 512");
90
+ NVME_DOORBELL_SIZE, PROT_WRITE, errp);
33
+ if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
91
+ if (!s->doorbells) {
34
+ error_setg(errp, "The new size must be a multiple of %u",
92
+ ret = -EINVAL;
35
+ (unsigned) BDRV_SECTOR_SIZE);
93
+ goto out;
36
return -EINVAL;
94
+ }
37
}
95
+
38
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);
39
--
110
--
40
2.24.1
111
2.26.2
41
112
42
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
qcow2_alloc_cluster_offset() and qcow2_get_cluster_offset() always
3
We only access the I/O register in nvme_init().
4
return offsets that are cluster-aligned so don't just check that they
4
Remove the reference in BDRVNVMeState and reduce its scope.
5
are sector-aligned.
6
5
7
The check in qcow2_co_preadv_task() is also replaced by an assertion
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
for the same reason.
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20200922083821.578519-4-philmd@redhat.com>
9
---
10
block/nvme.c | 29 ++++++++++++++++-------------
11
1 file changed, 16 insertions(+), 13 deletions(-)
9
12
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
diff --git a/block/nvme.c b/block/nvme.c
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
index XXXXXXX..XXXXXXX 100644
12
Message-id: 558ba339965f858bede4c73ce3f50f0c0493597d.1579374329.git.berto@igalia.com
15
--- a/block/nvme.c
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
+++ b/block/nvme.c
14
---
17
@@ -XXX,XX +XXX,XX @@ enum {
15
block/qcow2.c | 9 +++------
18
struct BDRVNVMeState {
16
1 file changed, 3 insertions(+), 6 deletions(-)
19
AioContext *aio_context;
20
QEMUVFIOState *vfio;
21
- NVMeRegs *regs;
22
/* Memory mapped registers */
23
volatile struct {
24
uint32_t sq_tail;
25
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
26
uint64_t timeout_ms;
27
uint64_t deadline, now;
28
Error *local_err = NULL;
29
+ NVMeRegs *regs;
30
31
qemu_co_mutex_init(&s->dma_map_lock);
32
qemu_co_queue_init(&s->dma_flush_queue);
33
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
34
goto out;
35
}
36
37
- s->regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, sizeof(NvmeBar),
38
- PROT_READ | PROT_WRITE, errp);
39
- if (!s->regs) {
40
+ regs = qemu_vfio_pci_map_bar(s->vfio, 0, 0, sizeof(NvmeBar),
41
+ PROT_READ | PROT_WRITE, errp);
42
+ if (!regs) {
43
ret = -EINVAL;
44
goto out;
45
}
46
/* Perform initialize sequence as described in NVMe spec "7.6.1
47
* Initialization". */
48
49
- cap = le64_to_cpu(s->regs->ctrl.cap);
50
+ cap = le64_to_cpu(regs->ctrl.cap);
51
if (!(cap & (1ULL << 37))) {
52
error_setg(errp, "Device doesn't support NVMe command set");
53
ret = -EINVAL;
54
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
55
timeout_ms = MIN(500 * ((cap >> 24) & 0xFF), 30000);
56
57
/* Reset device to get a clean state. */
58
- s->regs->ctrl.cc = cpu_to_le32(le32_to_cpu(s->regs->ctrl.cc) & 0xFE);
59
+ regs->ctrl.cc = cpu_to_le32(le32_to_cpu(regs->ctrl.cc) & 0xFE);
60
/* Wait for CSTS.RDY = 0. */
61
deadline = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ms * SCALE_MS;
62
- while (le32_to_cpu(s->regs->ctrl.csts) & 0x1) {
63
+ while (le32_to_cpu(regs->ctrl.csts) & 0x1) {
64
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
65
error_setg(errp, "Timeout while waiting for device to reset (%"
66
PRId64 " ms)",
67
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
68
}
69
s->nr_queues = 1;
70
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
71
- s->regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
72
- s->regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
73
- s->regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
74
+ regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
75
+ regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
76
+ regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
77
78
/* After setting up all control registers we can enable device now. */
79
- s->regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
80
+ regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
81
(ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
82
0x1);
83
/* Wait for CSTS.RDY = 1. */
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
--
111
2.26.2
17
112
18
diff --git a/block/qcow2.c b/block/qcow2.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.c
21
+++ b/block/qcow2.c
22
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
23
offset, bytes, qiov, qiov_offset);
24
25
case QCOW2_CLUSTER_NORMAL:
26
- if ((file_cluster_offset & 511) != 0) {
27
- return -EIO;
28
- }
29
-
30
+ assert(offset_into_cluster(s, file_cluster_offset) == 0);
31
if (bs->encrypted) {
32
return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
33
offset, bytes, qiov, qiov_offset);
34
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
35
goto out_locked;
36
}
37
38
- assert((cluster_offset & 511) == 0);
39
+ assert(offset_into_cluster(s, cluster_offset) == 0);
40
41
ret = qcow2_pre_write_overlap_check(bs, 0,
42
cluster_offset + offset_in_cluster,
43
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
44
goto fail;
45
}
46
47
- assert((cluster_offset & 511) == 0);
48
+ assert(offset_into_cluster(s, cluster_offset) == 0);
49
50
ret = qcow2_pre_write_overlap_check(bs, 0,
51
cluster_offset + offset_in_cluster, cur_bytes, true);
52
--
53
2.24.1
54
55
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
The L1 table is read from disk using the byte-based bdrv_pread() and
3
NVMeRegs only contains NvmeBar. Simplify the code by using NvmeBar
4
is never accessed beyond its last element, so there's no need to
4
directly.
5
allocate more memory than that.
6
5
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
This triggers a checkpatch.pl error:
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
9
Message-id: b2e27214ec7b03a585931bcf383ee1ac3a641a10.1579374329.git.berto@igalia.com
8
ERROR: Use of volatile is usually wrong, please add a comment
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
#30: FILE: block/nvme.c:691:
10
+ volatile NvmeBar *regs;
11
12
This is a false positive as in our case we are using I/O registers,
13
so the 'volatile' use is justified.
14
15
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-Id: <20200922083821.578519-5-philmd@redhat.com>
11
---
18
---
12
block/qcow2-cluster.c | 5 ++---
19
block/nvme.c | 23 +++++++++--------------
13
block/qcow2-refcount.c | 2 +-
20
1 file changed, 9 insertions(+), 14 deletions(-)
14
block/qcow2-snapshot.c | 3 +--
15
block/qcow2.c | 2 +-
16
4 files changed, 5 insertions(+), 7 deletions(-)
17
21
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
22
diff --git a/block/nvme.c b/block/nvme.c
19
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2-cluster.c
24
--- a/block/nvme.c
21
+++ b/block/qcow2-cluster.c
25
+++ b/block/nvme.c
22
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
26
@@ -XXX,XX +XXX,XX @@ typedef struct {
23
#endif
27
QEMUBH *completion_bh;
24
28
} NVMeQueuePair;
25
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
29
26
- new_l1_table = qemu_try_blockalign(bs->file->bs,
30
-/* Memory mapped registers */
27
- ROUND_UP(new_l1_size2, 512));
31
-typedef volatile struct {
28
+ new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_size2);
32
- NvmeBar ctrl;
29
if (new_l1_table == NULL) {
33
-} NVMeRegs;
30
return -ENOMEM;
34
-
35
#define INDEX_ADMIN 0
36
#define INDEX_IO(n) (1 + n)
37
38
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
39
uint64_t timeout_ms;
40
uint64_t deadline, now;
41
Error *local_err = NULL;
42
- NVMeRegs *regs;
43
+ volatile NvmeBar *regs = NULL;
44
45
qemu_co_mutex_init(&s->dma_map_lock);
46
qemu_co_queue_init(&s->dma_flush_queue);
47
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
48
/* Perform initialize sequence as described in NVMe spec "7.6.1
49
* Initialization". */
50
51
- cap = le64_to_cpu(regs->ctrl.cap);
52
+ cap = le64_to_cpu(regs->cap);
53
if (!(cap & (1ULL << 37))) {
54
error_setg(errp, "Device doesn't support NVMe command set");
55
ret = -EINVAL;
56
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
57
timeout_ms = MIN(500 * ((cap >> 24) & 0xFF), 30000);
58
59
/* Reset device to get a clean state. */
60
- regs->ctrl.cc = cpu_to_le32(le32_to_cpu(regs->ctrl.cc) & 0xFE);
61
+ regs->cc = cpu_to_le32(le32_to_cpu(regs->cc) & 0xFE);
62
/* Wait for CSTS.RDY = 0. */
63
deadline = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ms * SCALE_MS;
64
- while (le32_to_cpu(regs->ctrl.csts) & 0x1) {
65
+ while (le32_to_cpu(regs->csts) & 0x1) {
66
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
67
error_setg(errp, "Timeout while waiting for device to reset (%"
68
PRId64 " ms)",
69
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
31
}
70
}
32
- memset(new_l1_table, 0, ROUND_UP(new_l1_size2, 512));
71
s->nr_queues = 1;
33
+ memset(new_l1_table, 0, new_l1_size2);
72
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
34
73
- regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
35
if (s->l1_size) {
74
- regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
36
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
75
- regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
37
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
76
+ regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
38
index XXXXXXX..XXXXXXX 100644
77
+ regs->asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
39
--- a/block/qcow2-refcount.c
78
+ regs->acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
40
+++ b/block/qcow2-refcount.c
79
41
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
80
/* After setting up all control registers we can enable device now. */
42
* l1_table_offset when it is the current s->l1_table_offset! Be careful
81
- regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
43
* when changing this! */
82
+ regs->cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
44
if (l1_table_offset != s->l1_table_offset) {
83
(ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
45
- l1_table = g_try_malloc0(ROUND_UP(l1_size2, 512));
84
0x1);
46
+ l1_table = g_try_malloc0(l1_size2);
85
/* Wait for CSTS.RDY = 1. */
47
if (l1_size2 && l1_table == NULL) {
86
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
48
ret = -ENOMEM;
87
deadline = now + timeout_ms * 1000000;
49
goto fail;
88
- while (!(le32_to_cpu(regs->ctrl.csts) & 0x1)) {
50
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
89
+ while (!(le32_to_cpu(regs->csts) & 0x1)) {
51
index XXXXXXX..XXXXXXX 100644
90
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
52
--- a/block/qcow2-snapshot.c
91
error_setg(errp, "Timeout while waiting for device to start (%"
53
+++ b/block/qcow2-snapshot.c
92
PRId64 " ms)",
54
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
55
return ret;
56
}
57
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
58
- new_l1_table = qemu_try_blockalign(bs->file->bs,
59
- ROUND_UP(new_l1_bytes, 512));
60
+ new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_bytes);
61
if (new_l1_table == NULL) {
62
return -ENOMEM;
63
}
64
diff --git a/block/qcow2.c b/block/qcow2.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/qcow2.c
67
+++ b/block/qcow2.c
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
69
70
if (s->l1_size > 0) {
71
s->l1_table = qemu_try_blockalign(bs->file->bs,
72
- ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
73
+ s->l1_size * sizeof(uint64_t));
74
if (s->l1_table == NULL) {
75
error_setg(errp, "Could not allocate L1 table");
76
ret = -ENOMEM;
77
--
93
--
78
2.24.1
94
2.26.2
79
95
80
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
According to Kevin, tests 030, 040 and 041 are among the most valuable
3
Use the NVMe register definitions from "block/nvme.h" which
4
tests that we have, so we should always run them if possible, even if
4
ease a bit reviewing the code while matching the datasheet.
5
they take a little bit longer.
6
5
7
According to Max, it would be good to have a test for iothreads and
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
migration. 127 and 256 seem to be good candidates for iothreads. For
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
migration, let's enable 181 and 203 (which also tests iothreads).
8
Message-Id: <20200922083821.578519-6-philmd@redhat.com>
10
(091 would be a good candidate for migration, too, but Alex Bennée
9
---
11
reported that this test fails on ZFS file systems, so it can't be
10
block/nvme.c | 21 +++++++++++----------
12
included yet)
11
1 file changed, 11 insertions(+), 10 deletions(-)
13
12
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
diff --git a/block/nvme.c b/block/nvme.c
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
14
index XXXXXXX..XXXXXXX 100644
16
Message-id: 20200121095205.26323-7-thuth@redhat.com
15
--- a/block/nvme.c
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
+++ b/block/nvme.c
18
---
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
19
tests/qemu-iotests/group | 14 +++++++-------
18
* Initialization". */
20
1 file changed, 7 insertions(+), 7 deletions(-)
19
20
cap = le64_to_cpu(regs->cap);
21
- if (!(cap & (1ULL << 37))) {
22
+ if (!NVME_CAP_CSS(cap)) {
23
error_setg(errp, "Device doesn't support NVMe command set");
24
ret = -EINVAL;
25
goto out;
26
}
27
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
--
71
2.26.2
21
72
22
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
23
index XXXXXXX..XXXXXXX 100644
24
--- a/tests/qemu-iotests/group
25
+++ b/tests/qemu-iotests/group
26
@@ -XXX,XX +XXX,XX @@
27
027 rw auto quick
28
028 rw backing quick
29
029 rw auto quick
30
-030 rw backing
31
+030 rw auto backing
32
031 rw auto quick
33
032 rw auto quick
34
033 rw auto quick
35
@@ -XXX,XX +XXX,XX @@
36
037 rw auto backing quick
37
038 rw auto backing quick
38
039 rw auto quick
39
-040 rw
40
-041 rw backing
41
+040 rw auto
42
+041 rw auto backing
43
042 rw auto quick
44
043 rw auto backing
45
044 rw
46
@@ -XXX,XX +XXX,XX @@
47
124 rw backing
48
125 rw
49
126 rw auto backing
50
-127 rw backing quick
51
+127 rw auto backing quick
52
128 rw quick
53
129 rw quick
54
130 rw quick
55
@@ -XXX,XX +XXX,XX @@
56
177 rw auto quick
57
178 img
58
179 rw auto quick
59
-181 rw migration
60
+181 rw auto migration
61
182 rw quick
62
183 rw migration
63
184 rw auto quick
64
@@ -XXX,XX +XXX,XX @@
65
200 rw
66
201 rw migration
67
202 rw quick
68
-203 rw migration
69
+203 rw auto migration
70
204 rw quick
71
205 rw quick
72
206 rw
73
@@ -XXX,XX +XXX,XX @@
74
253 rw quick
75
254 rw backing quick
76
255 rw quick
77
-256 rw quick
78
+256 rw auto quick
79
257 rw
80
258 rw quick
81
260 rw quick
82
--
83
2.24.1
84
85
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
We are going to enable some of the python-based tests in the "auto" group,
3
Use self-explicit SCALE_MS definition instead of magic value
4
and these tests require virtio-blk to work properly. Running iotests
4
(missed in similar commit e4f310fe7f5).
5
without virtio-blk likely does not make too much sense anyway, so instead
6
of adding a check for the availability of virtio-blk to each and every
7
test (which does not sound very appealing), let's rather add a check for
8
this a central spot in the "check" script instead (so that it is still
9
possible to run "make check" for qemu-system-tricore for example).
10
5
11
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20200121095205.26323-6-thuth@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200922083821.578519-7-philmd@redhat.com>
14
---
9
---
15
tests/qemu-iotests/check | 12 ++++++++++--
10
block/nvme.c | 2 +-
16
1 file changed, 10 insertions(+), 2 deletions(-)
11
1 file changed, 1 insertion(+), 1 deletion(-)
17
12
18
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
13
diff --git a/block/nvme.c b/block/nvme.c
19
index XXXXXXX..XXXXXXX 100755
14
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/check
15
--- a/block/nvme.c
21
+++ b/tests/qemu-iotests/check
16
+++ b/block/nvme.c
22
@@ -XXX,XX +XXX,XX @@ fi
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
23
python_usable=false
18
CC_EN_MASK);
24
if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)'
19
/* Wait for CSTS.RDY = 1. */
25
then
20
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
26
- python_usable=true
21
- deadline = now + timeout_ms * 1000000;
27
+ # Our python framework also requires virtio-blk
22
+ deadline = now + timeout_ms * SCALE_MS;
28
+ if "$QEMU_PROG" -M none -device help | grep -q virtio-blk >/dev/null 2>&1
23
while (!NVME_CSTS_RDY(le32_to_cpu(regs->csts))) {
29
+ then
24
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
30
+ python_usable=true
25
error_setg(errp, "Timeout while waiting for device to start (%"
31
+ else
32
+ python_unusable_because="Missing virtio-blk in QEMU binary"
33
+ fi
34
+else
35
+ python_unusable_because="Unsupported Python version"
36
fi
37
38
default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
39
@@ -XXX,XX +XXX,XX @@ do
40
run_command="$PYTHON $seq"
41
else
42
run_command="false"
43
- echo "Unsupported Python version" > $seq.notrun
44
+ echo "$python_unusable_because" > $seq.notrun
45
fi
46
else
47
run_command="./$seq"
48
--
26
--
49
2.24.1
27
2.26.2
50
28
51
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This is a bit more efficient than having to allocate and free memory
3
This is the only coroutine wrapper from block.c and block/io.c which
4
for each item.
4
doesn't return a value, so let's convert it to the common behavior, to
5
simplify moving to generated coroutine wrappers in a further commit.
5
6
6
The default size (60) is enough for all the existing incompatible
7
Also, bdrv_invalidate_cache is a void function, returning error only
7
features or the "Unknown incompatible feature" message.
8
through **errp parameter, which is considered to be bad practice, as
9
it forces callers to define and propagate local_err variable, so
10
conversion is good anyway.
8
11
9
Suggested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
This patch leaves the conversion of .bdrv_co_invalidate_cache() driver
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
callbacks and bdrv_invalidate_cache_all() for another day.
11
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
14
12
Message-id: 20200115135626.19442-1-berto@igalia.com
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
18
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Message-Id: <20200924185414.28642-2-vsementsov@virtuozzo.com>
16
---
21
---
17
block/qcow2.c | 23 +++++++++++------------
22
include/block/block.h | 2 +-
18
1 file changed, 11 insertions(+), 12 deletions(-)
23
block.c | 32 ++++++++++++++++++--------------
24
2 files changed, 19 insertions(+), 15 deletions(-)
19
25
20
diff --git a/block/qcow2.c b/block/qcow2.c
26
diff --git a/include/block/block.h b/include/block/block.h
21
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qcow2.c
28
--- a/include/block/block.h
23
+++ b/block/qcow2.c
29
+++ b/include/block/block.h
24
@@ -XXX,XX +XXX,XX @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
30
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb);
25
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
31
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
26
uint64_t mask)
32
33
/* Invalidate any cached metadata used by image formats */
34
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
35
+int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
36
void bdrv_invalidate_cache_all(Error **errp);
37
int bdrv_inactivate_all(void);
38
39
diff --git a/block.c b/block.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block.c
42
+++ b/block.c
43
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
44
bdrv_init();
45
}
46
47
-static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
48
- Error **errp)
49
+static int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
50
+ Error **errp)
27
{
51
{
28
- char *features = g_strdup("");
52
BdrvChild *child, *parent;
29
- char *old;
53
uint64_t perm, shared_perm;
30
+ g_autoptr(GString) features = g_string_sized_new(60);
54
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
31
55
BdrvDirtyBitmap *bm;
32
while (table && table->name[0] != '\0') {
56
33
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
57
if (!bs->drv) {
34
if (mask & (1ULL << table->bit)) {
58
- return;
35
- old = features;
59
+ return -ENOMEDIUM;
36
- features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
60
}
37
- table->name);
61
38
- g_free(old);
62
QLIST_FOREACH(child, &bs->children, next) {
39
+ if (features->len > 0) {
63
bdrv_co_invalidate_cache(child->bs, &local_err);
40
+ g_string_append(features, ", ");
64
if (local_err) {
41
+ }
65
error_propagate(errp, local_err);
42
+ g_string_append_printf(features, "%.46s", table->name);
66
- return;
43
mask &= ~(1ULL << table->bit);
67
+ return -EINVAL;
68
}
69
}
70
71
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
72
ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, errp);
73
if (ret < 0) {
74
bs->open_flags |= BDRV_O_INACTIVE;
75
- return;
76
+ return ret;
77
}
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;
44
}
86
}
45
}
87
}
46
@@ -XXX,XX +XXX,XX @@ static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
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
}
47
}
96
}
48
97
49
if (mask) {
98
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
50
- old = features;
99
if (local_err) {
51
- features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
100
bs->open_flags |= BDRV_O_INACTIVE;
52
- old, *old ? ", " : "", mask);
101
error_propagate(errp, local_err);
53
- g_free(old);
102
- return;
54
+ if (features->len > 0) {
103
+ return -EINVAL;
55
+ g_string_append(features, ", ");
104
}
56
+ }
105
}
57
+ g_string_append_printf(features,
58
+ "Unknown incompatible feature: %" PRIx64, mask);
59
}
106
}
60
107
+
61
- error_setg(errp, "Unsupported qcow2 feature(s): %s", features);
108
+ return 0;
62
- g_free(features);
63
+ error_setg(errp, "Unsupported qcow2 feature(s): %s", features->str);
64
}
109
}
65
110
66
/*
111
typedef struct InvalidateCacheCo {
112
BlockDriverState *bs;
113
Error **errp;
114
bool done;
115
+ int ret;
116
} InvalidateCacheCo;
117
118
static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
119
{
120
InvalidateCacheCo *ico = opaque;
121
- bdrv_co_invalidate_cache(ico->bs, ico->errp);
122
+ ico->ret = bdrv_co_invalidate_cache(ico->bs, ico->errp);
123
ico->done = true;
124
aio_wait_kick();
125
}
126
127
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
128
+int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
129
{
130
Coroutine *co;
131
InvalidateCacheCo ico = {
132
@@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
133
bdrv_coroutine_enter(bs, co);
134
BDRV_POLL_WHILE(bs, !ico.done);
135
}
136
+
137
+ return ico.ret;
138
}
139
140
void bdrv_invalidate_cache_all(Error **errp)
141
{
142
BlockDriverState *bs;
143
- Error *local_err = NULL;
144
BdrvNextIterator it;
145
146
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
147
AioContext *aio_context = bdrv_get_aio_context(bs);
148
+ int ret;
149
150
aio_context_acquire(aio_context);
151
- bdrv_invalidate_cache(bs, &local_err);
152
+ ret = bdrv_invalidate_cache(bs, errp);
153
aio_context_release(aio_context);
154
- if (local_err) {
155
- error_propagate(errp, local_err);
156
+ if (ret < 0) {
157
bdrv_next_cleanup(&it);
158
return;
159
}
67
--
160
--
68
2.24.1
161
2.26.2
69
162
70
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
When updating an L1 entry the qcow2 driver writes a (512-byte) sector
3
Most of our coroutine wrappers already follow this convention:
4
worth of data to avoid a read-modify-write cycle. Instead of always
5
writing 512 bytes we should follow the alignment requirements of the
6
storage backend.
7
4
8
(the only exception is when the alignment is larger than the cluster
5
We have 'coroutine_fn bdrv_co_<something>(<normal argument list>)' as
9
size because then we could be overwriting data after the L1 table)
6
the core function, and a wrapper 'bdrv_<something>(<same argument
7
list>)' which does parameter packing and calls bdrv_run_co().
10
8
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
The only outsiders are the bdrv_prwv_co and
12
Message-id: 71f34d4ae4b367b32fb36134acbf4f4f7ee681f4.1579374329.git.berto@igalia.com
10
bdrv_common_block_status_above wrappers. Let's refactor them to behave
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
as the others, it simplifies further conversion of coroutine wrappers.
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
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
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Message-Id: <20200924185414.28642-3-vsementsov@virtuozzo.com>
15
---
23
---
16
block/qcow2-cluster.c | 25 +++++++++++++++----------
24
block/io.c | 60 +++++++++++++++++++++++++++++-------------------------
17
1 file changed, 15 insertions(+), 10 deletions(-)
25
1 file changed, 32 insertions(+), 28 deletions(-)
18
26
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
27
diff --git a/block/io.c b/block/io.c
20
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
29
--- a/block/io.c
22
+++ b/block/qcow2-cluster.c
30
+++ b/block/io.c
23
@@ -XXX,XX +XXX,XX @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
31
@@ -XXX,XX +XXX,XX @@ typedef struct RwCo {
32
BdrvRequestFlags flags;
33
} RwCo;
34
35
+static int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
36
+ QEMUIOVector *qiov, bool is_write,
37
+ BdrvRequestFlags flags)
38
+{
39
+ if (is_write) {
40
+ return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
41
+ } else {
42
+ return bdrv_co_preadv(child, offset, qiov->size, qiov, flags);
43
+ }
44
+}
45
+
46
static int coroutine_fn bdrv_rw_co_entry(void *opaque)
47
{
48
RwCo *rwco = opaque;
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);
24
}
61
}
25
62
26
/*
63
/*
27
- * Writes one sector of the L1 table to the disk (can't update single entries
64
* Process a vectored synchronous request using coroutines
28
- * and we really don't want bdrv_pread to perform a read-modify-write)
29
+ * Writes an L1 entry to disk (note that depending on the alignment
30
+ * requirements this function may write more that just one entry in
31
+ * order to prevent bdrv_pwrite from performing a read-modify-write)
32
*/
65
*/
33
-#define L1_ENTRIES_PER_SECTOR (512 / 8)
66
-static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
34
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
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)
35
{
72
{
36
BDRVQcow2State *s = bs->opaque;
73
RwCo rwco = {
37
- uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
74
.child = child,
38
int l1_start_index;
75
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
39
int i, ret;
76
{
40
+ int bufsize = MAX(sizeof(uint64_t),
77
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
41
+ MIN(bs->file->bs->bl.request_alignment, s->cluster_size));
78
42
+ int nentries = bufsize / sizeof(uint64_t);
79
- return bdrv_prwv_co(child, offset, &qiov, true,
43
+ g_autofree uint64_t *buf = g_try_new0(uint64_t, nentries);
80
- BDRV_REQ_ZERO_WRITE | flags);
44
81
+ return bdrv_prwv(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags);
45
- l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
82
}
46
- for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
83
47
- i++)
84
/*
48
- {
85
@@ -XXX,XX +XXX,XX @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
49
+ if (buf == NULL) {
86
{
50
+ return -ENOMEM;
87
int ret;
51
+ }
88
52
+
89
- ret = bdrv_prwv_co(child, offset, qiov, false, 0);
53
+ l1_start_index = QEMU_ALIGN_DOWN(l1_index, nentries);
90
+ ret = bdrv_prwv(child, offset, qiov, false, 0);
54
+ for (i = 0; i < MIN(nentries, s->l1_size - l1_start_index); i++) {
55
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
56
}
57
58
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
59
- s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false);
60
+ s->l1_table_offset + 8 * l1_start_index, bufsize, false);
61
if (ret < 0) {
91
if (ret < 0) {
62
return ret;
92
return ret;
63
}
93
}
64
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
94
@@ -XXX,XX +XXX,XX @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
65
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
95
{
66
ret = bdrv_pwrite_sync(bs->file,
96
int ret;
67
s->l1_table_offset + 8 * l1_start_index,
97
68
- buf, sizeof(buf));
98
- ret = bdrv_prwv_co(child, offset, qiov, true, 0);
69
+ buf, bufsize);
99
+ ret = bdrv_prwv(child, offset, qiov, true, 0);
70
if (ret < 0) {
100
if (ret < 0) {
71
return ret;
101
return ret;
72
}
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
/*
73
--
142
--
74
2.24.1
143
2.26.2
75
144
76
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This is a bit more efficient than having to allocate and free memory
3
We are going to keep coroutine-wrappers code (structure-packing
4
for each new permission.
4
parameters, BDRV_POLL wrapper functions) in separate auto-generated
5
5
files. So, we'll need a header with declaration of original _co_
6
The default size (30) is enough for "consistent read, write, resize".
6
functions, for those which are static now. As well, we'll need
7
7
declarations for wrapper functions. Do these declarations now, as a
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
preparation step.
9
Message-id: 20200110171518.22168-1-berto@igalia.com
9
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-Id: <20200924185414.28642-4-vsementsov@virtuozzo.com>
12
---
16
---
13
block.c | 11 ++++++-----
17
block/coroutines.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++
14
1 file changed, 6 insertions(+), 5 deletions(-)
18
block.c | 8 +++---
15
19
block/io.c | 34 +++++++++++------------
20
3 files changed, 88 insertions(+), 21 deletions(-)
21
create mode 100644 block/coroutines.h
22
23
diff --git a/block/coroutines.h b/block/coroutines.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 */
16
diff --git a/block.c b/block.c
96
diff --git a/block.c b/block.c
17
index XXXXXXX..XXXXXXX 100644
97
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
98
--- a/block.c
19
+++ b/block.c
99
+++ b/block.c
20
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
100
@@ -XXX,XX +XXX,XX @@
21
{ 0, NULL }
101
#include "qemu/timer.h"
22
};
102
#include "qemu/cutils.h"
23
103
#include "qemu/id.h"
24
- char *result = g_strdup("");
104
+#include "block/coroutines.h"
25
+ GString *result = g_string_sized_new(30);
105
26
struct perm_name *p;
106
#ifdef CONFIG_BSD
27
107
#include <sys/ioctl.h>
28
for (p = permissions; p->name; p++) {
108
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
29
if (perm & p->perm) {
109
* free of errors) or -errno when an internal error occurred. The results of the
30
- char *old = result;
110
* check are stored in res.
31
- result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
111
*/
32
- g_free(old);
112
-static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
33
+ if (result->len > 0) {
113
- BdrvCheckResult *res, BdrvCheckMode fix)
34
+ g_string_append(result, ", ");
114
+int coroutine_fn bdrv_co_check(BlockDriverState *bs,
35
+ }
115
+ BdrvCheckResult *res, BdrvCheckMode fix)
36
+ g_string_append(result, p->name);
116
{
37
}
117
if (bs->drv == NULL) {
38
}
118
return -ENOMEDIUM;
39
119
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
40
- return result;
120
bdrv_init();
41
+ return g_string_free(result, FALSE);
42
}
121
}
43
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
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/io.c
132
+++ b/block/io.c
133
@@ -XXX,XX +XXX,XX @@
134
#include "block/blockjob.h"
135
#include "block/blockjob_int.h"
136
#include "block/block_int.h"
137
+#include "block/coroutines.h"
138
#include "qemu/cutils.h"
139
#include "qapi/error.h"
140
#include "qemu/error-report.h"
141
@@ -XXX,XX +XXX,XX @@ typedef struct RwCo {
142
BdrvRequestFlags flags;
143
} RwCo;
144
145
-static int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
146
- QEMUIOVector *qiov, bool is_write,
147
- BdrvRequestFlags flags)
148
+int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
149
+ QEMUIOVector *qiov, bool is_write,
150
+ BdrvRequestFlags flags)
151
{
152
if (is_write) {
153
return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
154
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_rw_co_entry(void *opaque)
44
/*
155
/*
156
* Process a vectored synchronous request using coroutines
157
*/
158
-static int bdrv_prwv(BdrvChild *child, int64_t offset,
159
- QEMUIOVector *qiov, bool is_write,
160
- BdrvRequestFlags flags)
161
+int bdrv_prwv(BdrvChild *child, int64_t offset,
162
+ QEMUIOVector *qiov, bool is_write,
163
+ BdrvRequestFlags flags)
164
{
165
RwCo rwco = {
166
.child = child,
167
@@ -XXX,XX +XXX,XX @@ early_out:
168
return ret;
169
}
170
171
-static int coroutine_fn
172
+int coroutine_fn
173
bdrv_co_common_block_status_above(BlockDriverState *bs,
174
BlockDriverState *base,
175
bool want_zero,
176
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
177
*
178
* See bdrv_co_block_status_above() for details.
179
*/
180
-static int bdrv_common_block_status_above(BlockDriverState *bs,
181
- BlockDriverState *base,
182
- bool want_zero, int64_t offset,
183
- int64_t bytes, int64_t *pnum,
184
- int64_t *map,
185
- BlockDriverState **file)
186
+int bdrv_common_block_status_above(BlockDriverState *bs,
187
+ BlockDriverState *base,
188
+ bool want_zero, int64_t offset,
189
+ int64_t bytes, int64_t *pnum,
190
+ int64_t *map,
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,
45
--
216
--
46
2.24.1
217
2.26.2
47
218
48
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 test checks that bug is really fixed by previous commit.
3
We have a very frequent pattern of creating a coroutine from a function
4
4
with several arguments:
5
Cc: qemu-stable@nongnu.org # v4.2.0
5
6
- create a structure to pack parameters
7
- create _entry function to call original function taking parameters
8
from struct
9
- do different magic to handle completion: set ret to NOT_DONE or
10
EINPROGRESS or use separate bool field
11
- fill the struct and create coroutine from _entry function with this
12
struct as a parameter
13
- do coroutine enter and BDRV_POLL_WHILE loop
14
15
Let's reduce code duplication by generating coroutine wrappers.
16
17
This patch adds scripts/block-coroutine-wrapper.py together with some
18
friends, which will generate functions with declared prototypes marked
19
by the 'generated_co_wrapper' specifier.
20
21
The usage of new code generation is as follows:
22
23
1. define the coroutine function somewhere
24
25
int coroutine_fn bdrv_co_NAME(...) {...}
26
27
2. declare in some header file
28
29
int generated_co_wrapper bdrv_NAME(...);
30
31
with same list of parameters (generated_co_wrapper is
32
defined in "include/block/block.h").
33
34
3. Make sure the block_gen_c declaration in block/meson.build
35
mentions the file with your marker function.
36
37
Still, no function is now marked, this work is for the following
38
commit.
39
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
40
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20200121142802.21467-3-vsementsov@virtuozzo.com
41
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
42
Message-Id: <20200924185414.28642-5-vsementsov@virtuozzo.com>
43
[Added encoding='utf-8' to open() calls as requested by Vladimir. Fixed
44
typo and grammar issues pointed out by Eric Blake. Removed clang-format
45
dependency that caused build test issues.
46
--Stefan]
47
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
48
---
10
tests/qemu-iotests/283 | 92 ++++++++++++++++++++++++++++++++++++++
49
block/block-gen.h | 49 ++++++++
11
tests/qemu-iotests/283.out | 8 ++++
50
include/block/block.h | 10 ++
12
tests/qemu-iotests/group | 1 +
51
block/meson.build | 8 ++
13
3 files changed, 101 insertions(+)
52
docs/devel/block-coroutine-wrapper.rst | 54 ++++++++
14
create mode 100644 tests/qemu-iotests/283
53
docs/devel/index.rst | 1 +
15
create mode 100644 tests/qemu-iotests/283.out
54
scripts/block-coroutine-wrapper.py | 167 +++++++++++++++++++++++++
16
55
6 files changed, 289 insertions(+)
17
diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283
56
create mode 100644 block/block-gen.h
57
create mode 100644 docs/devel/block-coroutine-wrapper.rst
58
create mode 100644 scripts/block-coroutine-wrapper.py
59
60
diff --git a/block/block-gen.h b/block/block-gen.h
18
new file mode 100644
61
new file mode 100644
19
index XXXXXXX..XXXXXXX
62
index XXXXXXX..XXXXXXX
20
--- /dev/null
63
--- /dev/null
21
+++ b/tests/qemu-iotests/283
64
+++ b/block/block-gen.h
22
@@ -XXX,XX +XXX,XX @@
65
@@ -XXX,XX +XXX,XX @@
23
+#!/usr/bin/env python
66
+/*
24
+#
67
+ * Block coroutine wrapping core, used by auto-generated block/block-gen.c
25
+# Test for backup-top filter permission activation failure
68
+ *
26
+#
69
+ * Copyright (c) 2003 Fabrice Bellard
27
+# Copyright (c) 2019 Virtuozzo International GmbH.
70
+ * Copyright (c) 2020 Virtuozzo International GmbH
28
+#
71
+ *
29
+# This program is free software; you can redistribute it and/or modify
72
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
30
+# it under the terms of the GNU General Public License as published by
73
+ * of this software and associated documentation files (the "Software"), to deal
31
+# the Free Software Foundation; either version 2 of the License, or
74
+ * in the Software without restriction, including without limitation the rights
32
+# (at your option) any later version.
75
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+#
76
+ * copies of the Software, and to permit persons to whom the Software is
34
+# This program is distributed in the hope that it will be useful,
77
+ * furnished to do so, subject to the following conditions:
35
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
78
+ *
36
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79
+ * The above copyright notice and this permission notice shall be included in
37
+# GNU General Public License for more details.
80
+ * all copies or substantial portions of the Software.
38
+#
81
+ *
39
+# You should have received a copy of the GNU General Public License
82
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
83
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+#
84
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42
+
85
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+import iotests
86
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+
87
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
88
+ * THE SOFTWARE.
46
+iotests.verify_image_format(supported_fmts=['qcow2'])
89
+ */
47
+
90
+
48
+size = 1024 * 1024
91
+#ifndef BLOCK_BLOCK_GEN_H
49
+
92
+#define BLOCK_BLOCK_GEN_H
50
+""" Test description
93
+
51
+
94
+#include "block/block_int.h"
52
+When performing a backup, all writes on the source subtree must go through the
95
+
53
+backup-top filter so it can copy all data to the target before it is changed.
96
+/* Base structure for argument packing structures */
54
+backup-top filter is appended above source node, to achieve this thing, so all
97
+typedef struct BdrvPollCo {
55
+parents of source node are handled. A configuration with side parents of source
98
+ BlockDriverState *bs;
56
+sub-tree with write permission is unsupported (we'd have append several
99
+ bool in_progress;
57
+backup-top filter like nodes to handle such parents). The test create an
100
+ int ret;
58
+example of such configuration and checks that a backup is then not allowed
101
+ Coroutine *co; /* Keep pointer here for debugging */
59
+(blockdev-backup command should fail).
102
+} BdrvPollCo;
60
+
103
+
61
+The configuration:
104
+static inline int bdrv_poll_co(BdrvPollCo *s)
62
+
105
+{
63
+ ┌────────┐ target ┌─────────────┐
106
+ assert(!qemu_in_coroutine());
64
+ │ target │ ◀─────── │ backup_top │
107
+
65
+ └────────┘ └─────────────┘
108
+ bdrv_coroutine_enter(s->bs, s->co);
66
+ │
109
+ BDRV_POLL_WHILE(s->bs, s->in_progress);
67
+ │ backing
110
+
68
+ ▼
111
+ return s->ret;
69
+ ┌─────────────┐
112
+}
70
+ │ source │
113
+
71
+ └─────────────┘
114
+#endif /* BLOCK_BLOCK_GEN_H */
72
+ │
115
diff --git a/include/block/block.h b/include/block/block.h
73
+ │ file
116
index XXXXXXX..XXXXXXX 100644
74
+ ▼
117
--- a/include/block/block.h
75
+ ┌─────────────┐ write perm ┌───────┐
118
+++ b/include/block/block.h
76
+ │ base │ ◀──────────── │ other │
119
@@ -XXX,XX +XXX,XX @@
77
+ └─────────────┘ └───────┘
120
#include "block/blockjob.h"
78
+
121
#include "qemu/hbitmap.h"
79
+On activation (see .active field of backup-top state in block/backup-top.c),
122
80
+backup-top is going to unshare write permission on its source child. Write
123
+/*
81
+unsharing will be propagated to the "source->base" link and will conflict with
124
+ * generated_co_wrapper
82
+other node write permission. So permission update will fail and backup job will
125
+ *
83
+not be started.
126
+ * Function specifier, which does nothing but mark functions to be
84
+
127
+ * generated by scripts/block-coroutine-wrapper.py
85
+Note, that the only thing which prevents backup of running on such
128
+ *
86
+configuration is default permission propagation scheme. It may be altered by
129
+ * Read more in docs/devel/block-coroutine-wrapper.rst
87
+different block drivers, so backup will run in invalid configuration. But
130
+ */
88
+something is better than nothing. Also, before the previous commit (commit
131
+#define generated_co_wrapper
89
+preceding this test creation), starting backup on such configuration led to
132
+
90
+crash, so current "something" is a lot better, and this test actual goal is
133
/* block.c */
91
+to check that crash is fixed :)
134
typedef struct BlockDriver BlockDriver;
92
+"""
135
typedef struct BdrvChild BdrvChild;
93
+
136
diff --git a/block/meson.build b/block/meson.build
94
+vm = iotests.VM()
137
index XXXXXXX..XXXXXXX 100644
95
+vm.launch()
138
--- a/block/meson.build
96
+
139
+++ b/block/meson.build
97
+vm.qmp_log('blockdev-add', **{'node-name': 'target', 'driver': 'null-co'})
140
@@ -XXX,XX +XXX,XX @@ module_block_h = custom_target('module_block.h',
98
+
141
command: [module_block_py, '@OUTPUT0@', modsrc])
99
+vm.qmp_log('blockdev-add', **{
142
block_ss.add(module_block_h)
100
+ 'node-name': 'source',
143
101
+ 'driver': 'blkdebug',
144
+wrapper_py = find_program('../scripts/block-coroutine-wrapper.py')
102
+ 'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
145
+block_gen_c = custom_target('block-gen.c',
103
+})
146
+ output: 'block-gen.c',
104
+
147
+ input: files('../include/block/block.h',
105
+vm.qmp_log('blockdev-add', **{
148
+ 'coroutines.h'),
106
+ 'node-name': 'other',
149
+ command: [wrapper_py, '@OUTPUT@', '@INPUT@'])
107
+ 'driver': 'blkdebug',
150
+block_ss.add(block_gen_c)
108
+ 'image': 'base',
151
+
109
+ 'take-child-perms': ['write']
152
block_ss.add(files('stream.c'))
110
+})
153
111
+
154
softmmu_ss.add(files('qapi-sysemu.c'))
112
+vm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
155
diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst
113
+
114
+vm.shutdown()
115
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
116
new file mode 100644
156
new file mode 100644
117
index XXXXXXX..XXXXXXX
157
index XXXXXXX..XXXXXXX
118
--- /dev/null
158
--- /dev/null
119
+++ b/tests/qemu-iotests/283.out
159
+++ b/docs/devel/block-coroutine-wrapper.rst
120
@@ -XXX,XX +XXX,XX @@
160
@@ -XXX,XX +XXX,XX @@
121
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}}
161
+=======================
122
+{"return": {}}
162
+block-coroutine-wrapper
123
+{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": {"driver": "null-co", "node-name": "base", "size": 1048576}, "node-name": "source"}}
163
+=======================
124
+{"return": {}}
164
+
125
+{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}}
165
+A lot of functions in QEMU block layer (see ``block/*``) can only be
126
+{"return": {}}
166
+called in coroutine context. Such functions are normally marked by the
127
+{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
167
+coroutine_fn specifier. Still, sometimes we need to call them from
128
+{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}}
168
+non-coroutine context; for this we need to start a coroutine, run the
129
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
169
+needed function from it and wait for the coroutine to finish in a
170
+BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one
171
+void* argument. So for each coroutine_fn function which needs a
172
+non-coroutine interface, we should define a structure to pack the
173
+parameters, define a separate function to unpack the parameters and
174
+call the original function and finally define a new interface function
175
+with same list of arguments as original one, which will pack the
176
+parameters into a struct, create a coroutine, run it and wait in
177
+BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand,
178
+so we have a script to generate them.
179
+
180
+Usage
181
+=====
182
+
183
+Assume we have defined the ``coroutine_fn`` function
184
+``bdrv_co_foo(<some args>)`` and need a non-coroutine interface for it,
185
+called ``bdrv_foo(<same args>)``. In this case the script can help. To
186
+trigger the generation:
187
+
188
+1. You need ``bdrv_foo`` declaration somewhere (for example, in
189
+ ``block/coroutines.h``) with the ``generated_co_wrapper`` mark,
190
+ like this:
191
+
192
+.. code-block:: c
193
+
194
+ int generated_co_wrapper bdrv_foo(<some args>);
195
+
196
+2. You need to feed this declaration to block-coroutine-wrapper script.
197
+ For this, add the .h (or .c) file with the declaration to the
198
+ ``input: files(...)`` list of ``block_gen_c`` target declaration in
199
+ ``block/meson.build``
200
+
201
+You are done. During the build, coroutine wrappers will be generated in
202
+``<BUILD_DIR>/block/block-gen.c``.
203
+
204
+Links
205
+=====
206
+
207
+1. The script location is ``scripts/block-coroutine-wrapper.py``.
208
+
209
+2. Generic place for private ``generated_co_wrapper`` declarations is
210
+ ``block/coroutines.h``, for public declarations:
211
+ ``include/block/block.h``
212
+
213
+3. The core API of generated coroutine wrappers is placed in
214
+ (not generated) ``block/block-gen.h``
215
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
130
index XXXXXXX..XXXXXXX 100644
216
index XXXXXXX..XXXXXXX 100644
131
--- a/tests/qemu-iotests/group
217
--- a/docs/devel/index.rst
132
+++ b/tests/qemu-iotests/group
218
+++ b/docs/devel/index.rst
219
@@ -XXX,XX +XXX,XX @@ Contents:
220
s390-dasd-ipl
221
clocks
222
qom
223
+ block-coroutine-wrapper
224
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
225
new file mode 100644
226
index XXXXXXX..XXXXXXX
227
--- /dev/null
228
+++ b/scripts/block-coroutine-wrapper.py
133
@@ -XXX,XX +XXX,XX @@
229
@@ -XXX,XX +XXX,XX @@
134
279 rw backing quick
230
+#! /usr/bin/env python3
135
280 rw migration quick
231
+"""Generate coroutine wrappers for block subsystem.
136
281 rw quick
232
+
137
+283 auto quick
233
+The program parses one or several concatenated c files from stdin,
234
+searches for functions with the 'generated_co_wrapper' specifier
235
+and generates corresponding wrappers on stdout.
236
+
237
+Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
238
+
239
+Copyright (c) 2020 Virtuozzo International GmbH.
240
+
241
+This program is free software; you can redistribute it and/or modify
242
+it under the terms of the GNU General Public License as published by
243
+the Free Software Foundation; either version 2 of the License, or
244
+(at your option) any later version.
245
+
246
+This program is distributed in the hope that it will be useful,
247
+but WITHOUT ANY WARRANTY; without even the implied warranty of
248
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
249
+GNU General Public License for more details.
250
+
251
+You should have received a copy of the GNU General Public License
252
+along with this program. If not, see <http://www.gnu.org/licenses/>.
253
+"""
254
+
255
+import sys
256
+import re
257
+from typing import Iterator
258
+
259
+
260
+def gen_header():
261
+ copyright = re.sub('^.*Copyright', 'Copyright', __doc__, flags=re.DOTALL)
262
+ copyright = re.sub('^(?=.)', ' * ', copyright.strip(), flags=re.MULTILINE)
263
+ copyright = re.sub('^$', ' *', copyright, flags=re.MULTILINE)
264
+ return f"""\
265
+/*
266
+ * File is generated by scripts/block-coroutine-wrapper.py
267
+ *
268
+{copyright}
269
+ */
270
+
271
+#include "qemu/osdep.h"
272
+#include "block/coroutines.h"
273
+#include "block/block-gen.h"
274
+#include "block/block_int.h"\
275
+"""
276
+
277
+
278
+class ParamDecl:
279
+ param_re = re.compile(r'(?P<decl>'
280
+ r'(?P<type>.*[ *])'
281
+ r'(?P<name>[a-z][a-z0-9_]*)'
282
+ r')')
283
+
284
+ def __init__(self, param_decl: str) -> None:
285
+ m = self.param_re.match(param_decl.strip())
286
+ if m is None:
287
+ raise ValueError(f'Wrong parameter declaration: "{param_decl}"')
288
+ self.decl = m.group('decl')
289
+ self.type = m.group('type')
290
+ self.name = m.group('name')
291
+
292
+
293
+class FuncDecl:
294
+ def __init__(self, return_type: str, name: str, args: str) -> None:
295
+ self.return_type = return_type.strip()
296
+ self.name = name.strip()
297
+ self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
298
+
299
+ def gen_list(self, format: str) -> str:
300
+ return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
301
+
302
+ def gen_block(self, format: str) -> str:
303
+ return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
304
+
305
+
306
+# Match wrappers declared with a generated_co_wrapper mark
307
+func_decl_re = re.compile(r'^int\s*generated_co_wrapper\s*'
308
+ r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
309
+ r'\((?P<args>[^)]*)\);$', re.MULTILINE)
310
+
311
+
312
+def func_decl_iter(text: str) -> Iterator:
313
+ for m in func_decl_re.finditer(text):
314
+ yield FuncDecl(return_type='int',
315
+ name=m.group('wrapper_name'),
316
+ args=m.group('args'))
317
+
318
+
319
+def snake_to_camel(func_name: str) -> str:
320
+ """
321
+ Convert underscore names like 'some_function_name' to camel-case like
322
+ 'SomeFunctionName'
323
+ """
324
+ words = func_name.split('_')
325
+ words = [w[0].upper() + w[1:] for w in words]
326
+ return ''.join(words)
327
+
328
+
329
+def gen_wrapper(func: FuncDecl) -> str:
330
+ assert func.name.startswith('bdrv_')
331
+ assert not func.name.startswith('bdrv_co_')
332
+ assert func.return_type == 'int'
333
+ assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *']
334
+
335
+ name = 'bdrv_co_' + func.name[5:]
336
+ bs = 'bs' if func.args[0].type == 'BlockDriverState *' else 'child->bs'
337
+ struct_name = snake_to_camel(name)
338
+
339
+ return f"""\
340
+/*
341
+ * Wrappers for {name}
342
+ */
343
+
344
+typedef struct {struct_name} {{
345
+ BdrvPollCo poll_state;
346
+{ func.gen_block(' {decl};') }
347
+}} {struct_name};
348
+
349
+static void coroutine_fn {name}_entry(void *opaque)
350
+{{
351
+ {struct_name} *s = opaque;
352
+
353
+ s->poll_state.ret = {name}({ func.gen_list('s->{name}') });
354
+ s->poll_state.in_progress = false;
355
+
356
+ aio_wait_kick();
357
+}}
358
+
359
+int {func.name}({ func.gen_list('{decl}') })
360
+{{
361
+ if (qemu_in_coroutine()) {{
362
+ return {name}({ func.gen_list('{name}') });
363
+ }} else {{
364
+ {struct_name} s = {{
365
+ .poll_state.bs = {bs},
366
+ .poll_state.in_progress = true,
367
+
368
+{ func.gen_block(' .{name} = {name},') }
369
+ }};
370
+
371
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
372
+
373
+ return bdrv_poll_co(&s.poll_state);
374
+ }}
375
+}}"""
376
+
377
+
378
+def gen_wrappers(input_code: str) -> str:
379
+ res = ''
380
+ for func in func_decl_iter(input_code):
381
+ res += '\n\n\n'
382
+ res += gen_wrapper(func)
383
+
384
+ return res
385
+
386
+
387
+if __name__ == '__main__':
388
+ if len(sys.argv) < 3:
389
+ exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...')
390
+
391
+ with open(sys.argv[1], 'w', encoding='utf-8') as f_out:
392
+ f_out.write(gen_header())
393
+ for fname in sys.argv[2:]:
394
+ with open(fname, encoding='utf-8') as f_in:
395
+ f_out.write(gen_wrappers(f_in.read()))
396
+ f_out.write('\n')
138
--
397
--
139
2.24.1
398
2.26.2
140
399
141
diff view generated by jsdifflib
1
From: Pan Nengyuan <pannengyuan@huawei.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
If we call the qmp 'query-block' while qemu is working on
3
Use code generation implemented in previous commit to generated
4
'block-commit', it will cause memleaks, the memory leak stack is as
4
coroutine wrappers in block.c and block/io.c
5
follow:
6
5
7
Indirect leak of 12360 byte(s) in 3 object(s) allocated from:
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu-4.2.0-rc0/qobject/qdict.c:29
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6427
10
Message-Id: <20200924185414.28642-6-vsementsov@virtuozzo.com>
12
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
11
---
13
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
12
block/coroutines.h | 6 +-
14
#6 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
13
include/block/block.h | 16 ++--
15
#7 0x55ea958818ea in bdrv_block_device_info /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:56
14
block.c | 73 ---------------
16
#8 0x55ea958879de in bdrv_query_info /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:392
15
block/io.c | 212 ------------------------------------------
17
#9 0x55ea9588b58f in qmp_query_block /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:578
16
4 files changed, 13 insertions(+), 294 deletions(-)
18
#10 0x55ea95567392 in qmp_marshal_query_block qapi/qapi-commands-block-core.c:95
19
17
20
Indirect leak of 4120 byte(s) in 1 object(s) allocated from:
18
diff --git a/block/coroutines.h b/block/coroutines.h
21
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
19
index XXXXXXX..XXXXXXX 100644
22
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
20
--- a/block/coroutines.h
23
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu-4.2.0-rc0/qobject/qdict.c:29
21
+++ b/block/coroutines.h
24
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6427
22
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
25
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
23
int coroutine_fn
26
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
24
bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
27
#6 0x55ea9569f301 in bdrv_backing_attach /mnt/sdb/qemu-4.2.0-rc0/block.c:1064
25
bool is_write, BdrvRequestFlags flags);
28
#7 0x55ea956a99dd in bdrv_replace_child_noperm /mnt/sdb/qemu-4.2.0-rc0/block.c:2283
26
-int
29
#8 0x55ea956b9b53 in bdrv_replace_node /mnt/sdb/qemu-4.2.0-rc0/block.c:4196
27
+int generated_co_wrapper
30
#9 0x55ea956b9e49 in bdrv_append /mnt/sdb/qemu-4.2.0-rc0/block.c:4236
28
bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
31
#10 0x55ea958c3472 in commit_start /mnt/sdb/qemu-4.2.0-rc0/block/commit.c:306
29
bool is_write, BdrvRequestFlags flags);
32
#11 0x55ea94b68ab0 in qmp_block_commit /mnt/sdb/qemu-4.2.0-rc0/blockdev.c:3459
30
33
#12 0x55ea9556a7a7 in qmp_marshal_block_commit qapi/qapi-commands-block-core.c:407
31
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
34
32
int64_t *pnum,
35
Fixes: bb808d5f5c0978828a974d547e6032402c339555
33
int64_t *map,
36
Reported-by: Euler Robot <euler.robot@huawei.com>
34
BlockDriverState **file);
37
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
35
-int
38
Message-id: 20200116085600.24056-1-pannengyuan@huawei.com
36
+int generated_co_wrapper
39
Signed-off-by: Max Reitz <mreitz@redhat.com>
37
bdrv_common_block_status_above(BlockDriverState *bs,
40
---
38
BlockDriverState *base,
41
block.c | 1 +
39
bool want_zero,
42
1 file changed, 1 insertion(+)
40
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
43
41
int coroutine_fn
42
bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
43
bool is_read);
44
-int
45
+int generated_co_wrapper
46
bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
47
bool is_read);
48
49
diff --git a/include/block/block.h b/include/block/block.h
50
index XXXXXXX..XXXXXXX 100644
51
--- a/include/block/block.h
52
+++ b/include/block/block.h
53
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs);
54
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
55
PreallocMode prealloc, BdrvRequestFlags flags,
56
Error **errp);
57
-int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
58
- PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
59
+int generated_co_wrapper
60
+bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
61
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
62
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);
44
diff --git a/block.c b/block.c
101
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
102
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
103
--- a/block.c
47
+++ b/block.c
104
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
105
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
49
child->bs->exact_filename);
106
return bs->drv->bdrv_co_check(bs, res, fix);
50
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
107
}
51
108
52
+ qobject_unref(bs->full_open_options);
109
-typedef struct CheckCo {
53
bs->full_open_options = qobject_ref(child->bs->full_open_options);
110
- BlockDriverState *bs;
54
111
- BdrvCheckResult *res;
55
return;
112
- BdrvCheckMode fix;
113
- int ret;
114
-} CheckCo;
115
-
116
-static void coroutine_fn bdrv_check_co_entry(void *opaque)
117
-{
118
- CheckCo *cco = opaque;
119
- cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
120
- aio_wait_kick();
121
-}
122
-
123
-int bdrv_check(BlockDriverState *bs,
124
- BdrvCheckResult *res, BdrvCheckMode fix)
125
-{
126
- Coroutine *co;
127
- CheckCo cco = {
128
- .bs = bs,
129
- .res = res,
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
- }
142
-
143
- return cco.ret;
144
-}
145
-
146
/*
147
* Return values:
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
{
191
BlockDriverState *bs;
192
diff --git a/block/io.c b/block/io.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/io.c
195
+++ b/block/io.c
196
@@ -XXX,XX +XXX,XX @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
197
return 0;
198
}
199
200
-typedef int coroutine_fn BdrvRequestEntry(void *opaque);
201
-typedef struct BdrvRunCo {
202
- BdrvRequestEntry *entry;
203
- void *opaque;
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,
331
- .bytes = bytes,
332
- .pnum = pnum,
333
- .map = map,
334
- .file = file,
335
- };
336
-
337
- return bdrv_run_co(bs, bdrv_block_status_above_co_entry, &data);
338
-}
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
}
346
347
-typedef struct BdrvVmstateCo {
348
- BlockDriverState *bs;
349
- QEMUIOVector *qiov;
350
- int64_t pos;
351
- bool is_read;
352
-} BdrvVmstateCo;
353
-
354
int coroutine_fn
355
bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
356
bool is_read)
357
@@ -XXX,XX +XXX,XX @@ bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
358
return ret;
359
}
360
361
-static int coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque)
362
-{
363
- BdrvVmstateCo *co = opaque;
364
-
365
- return bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read);
366
-}
367
-
368
-int bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
369
- bool is_read)
370
-{
371
- BdrvVmstateCo data = {
372
- .bs = bs,
373
- .qiov = qiov,
374
- .pos = pos,
375
- .is_read = is_read,
376
- };
377
-
378
- return bdrv_run_co(bs, bdrv_co_rw_vmstate_entry, &data);
379
-}
380
-
381
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
382
int64_t pos, int size)
383
{
384
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb)
385
/**************************************************************/
386
/* Coroutine block device emulation */
387
388
-static int coroutine_fn bdrv_flush_co_entry(void *opaque)
389
-{
390
- return bdrv_co_flush(opaque);
391
-}
392
-
393
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
394
{
395
BdrvChild *primary_child = bdrv_primary_child(bs);
396
@@ -XXX,XX +XXX,XX @@ early_exit:
397
return ret;
398
}
399
400
-int bdrv_flush(BlockDriverState *bs)
401
-{
402
- return bdrv_run_co(bs, bdrv_flush_co_entry, bs);
403
-}
404
-
405
-typedef struct DiscardCo {
406
- BdrvChild *child;
407
- int64_t offset;
408
- int64_t bytes;
409
-} DiscardCo;
410
-
411
-static int coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
412
-{
413
- DiscardCo *rwco = opaque;
414
-
415
- return bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
416
-}
417
-
418
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
419
int64_t bytes)
420
{
421
@@ -XXX,XX +XXX,XX @@ out:
422
return ret;
423
}
424
425
-int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
426
-{
427
- DiscardCo rwco = {
428
- .child = child,
429
- .offset = offset,
430
- .bytes = bytes,
431
- };
432
-
433
- return bdrv_run_co(child->bs, bdrv_pdiscard_co_entry, &rwco);
434
-}
435
-
436
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
437
{
438
BlockDriver *drv = bs->drv;
439
@@ -XXX,XX +XXX,XX @@ out:
440
441
return ret;
442
}
443
-
444
-typedef struct TruncateCo {
445
- BdrvChild *child;
446
- int64_t offset;
447
- bool exact;
448
- PreallocMode prealloc;
449
- BdrvRequestFlags flags;
450
- Error **errp;
451
-} TruncateCo;
452
-
453
-static int coroutine_fn bdrv_truncate_co_entry(void *opaque)
454
-{
455
- TruncateCo *tco = opaque;
456
-
457
- return bdrv_co_truncate(tco->child, tco->offset, tco->exact,
458
- tco->prealloc, tco->flags, tco->errp);
459
-}
460
-
461
-int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
462
- PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
463
-{
464
- TruncateCo tco = {
465
- .child = child,
466
- .offset = offset,
467
- .exact = exact,
468
- .prealloc = prealloc,
469
- .flags = flags,
470
- .errp = errp,
471
- };
472
-
473
- return bdrv_run_co(child->bs, bdrv_truncate_co_entry, &tco);
474
-}
56
--
475
--
57
2.24.1
476
2.26.2
58
477
59
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
In the long run, we might want to add test 183 to the "auto" group
3
Now that we are not maintaining boilerplate code for coroutine
4
(but it still fails occasionally, so we cannot do that yet). However,
4
wrappers, there is no more sense in keeping the extra indirection layer
5
when running 183 in Cirrus-CI on macOS, or with our vm-build-openbsd
5
of bdrv_prwv(). Let's drop it and instead generate pure bdrv_preadv()
6
target, it currently always fails with an "Timeout waiting for return
6
and bdrv_pwritev().
7
on handle 0" error.
8
7
9
Let's mark it as supported only on systems where the test is working
8
Currently, bdrv_pwritev() and bdrv_preadv() are returning bytes on
10
most of the time (i.e. Linux, FreeBSD and NetBSD).
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.
11
16
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Of course, it would be great to convert bdrv_pread() and bdrv_pwrite()
13
Signed-off-by: Thomas Huth <thuth@redhat.com>
18
to return 0 on success. But this requires audit (and probably
14
Message-id: 20200121095205.26323-4-thuth@redhat.com
19
conversion) of all their users, let's leave it for another day
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
refactoring.
21
22
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
26
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-Id: <20200924185414.28642-7-vsementsov@virtuozzo.com>
16
---
28
---
17
tests/qemu-iotests/183 | 1 +
29
block/coroutines.h | 10 ++++-----
18
1 file changed, 1 insertion(+)
30
include/block/block.h | 2 --
31
block/io.c | 49 ++++++++---------------------------------
32
tests/test-bdrv-drain.c | 2 +-
33
4 files changed, 15 insertions(+), 48 deletions(-)
19
34
20
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
35
diff --git a/block/coroutines.h b/block/coroutines.h
21
index XXXXXXX..XXXXXXX 100755
36
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/183
37
--- a/block/coroutines.h
23
+++ b/tests/qemu-iotests/183
38
+++ b/block/coroutines.h
24
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
39
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
25
. ./common.filter
40
BdrvCheckResult *res, BdrvCheckMode fix);
26
. ./common.qemu
41
int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
27
42
28
+_supported_os Linux FreeBSD NetBSD
43
-int coroutine_fn
29
_supported_fmt qcow2 raw qed quorum
44
-bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
30
_supported_proto file
45
- bool is_write, BdrvRequestFlags flags);
31
46
int generated_co_wrapper
47
-bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
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
59
--- a/include/block/block.h
60
+++ b/include/block/block.h
61
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, 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
}
103
}
104
105
-/* return < 0 if error. See bdrv_pwrite() for the return codes */
106
-int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
107
-{
108
- int ret;
109
-
110
- ret = bdrv_prwv(child, offset, qiov, false, 0);
111
- if (ret < 0) {
112
- return ret;
113
- }
114
-
115
- return qiov->size;
116
-}
117
-
118
/* See bdrv_pwrite() for the return codes */
119
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
120
{
121
+ int ret;
122
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
123
124
if (bytes < 0) {
125
return -EINVAL;
126
}
127
128
- return bdrv_preadv(child, offset, &qiov);
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 */
32
--
177
--
33
2.24.1
178
2.26.2
34
179
35
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
041 works fine on Linux, FreeBSD, NetBSD and OpenBSD, but fails on macOS.
3
Like for read/write in a previous commit, drop extra indirection layer,
4
Let's mark it as only supported on the systems where we know that it is
4
generate directly bdrv_readv_vmstate() and bdrv_writev_vmstate().
5
working fine.
6
5
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 20200121095205.26323-3-thuth@redhat.com
8
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-Id: <20200924185414.28642-8-vsementsov@virtuozzo.com>
11
---
11
---
12
tests/qemu-iotests/041 | 3 ++-
12
block/coroutines.h | 10 +++----
13
1 file changed, 2 insertions(+), 1 deletion(-)
13
include/block/block.h | 6 ++--
14
block/io.c | 70 ++++++++++++++++++++++---------------------
15
3 files changed, 44 insertions(+), 42 deletions(-)
14
16
15
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
17
diff --git a/block/coroutines.h b/block/coroutines.h
16
index XXXXXXX..XXXXXXX 100755
18
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/041
19
--- a/block/coroutines.h
18
+++ b/tests/qemu-iotests/041
20
+++ b/block/coroutines.h
19
@@ -XXX,XX +XXX,XX @@ class TestOrphanedSource(iotests.QMPTestCase):
21
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
20
22
int64_t *map,
21
if __name__ == '__main__':
23
BlockDriverState **file);
22
iotests.main(supported_fmts=['qcow2', 'qed'],
24
23
- supported_protocols=['file'])
25
-int coroutine_fn
24
+ supported_protocols=['file'],
26
-bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
25
+ supported_platforms=['linux', 'freebsd', 'netbsd', 'openbsd'])
27
- bool is_read);
28
-int generated_co_wrapper
29
-bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
30
- bool is_read);
31
+int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs,
32
+ QEMUIOVector *qiov, int64_t pos);
33
+int coroutine_fn bdrv_co_writev_vmstate(BlockDriverState *bs,
34
+ QEMUIOVector *qiov, int64_t pos);
35
36
#endif /* BLOCK_COROUTINES_INT_H */
37
diff --git a/include/block/block.h b/include/block/block.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block.h
40
+++ b/include/block/block.h
41
@@ -XXX,XX +XXX,XX @@ int path_has_protocol(const char *path);
42
int path_is_absolute(const char *path);
43
char *path_combine(const char *base_path, const char *filename);
44
45
-int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
46
-int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
47
+int generated_co_wrapper
48
+bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
49
+int generated_co_wrapper
50
+bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
51
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
52
int64_t pos, int size);
53
54
diff --git a/block/io.c b/block/io.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/io.c
57
+++ b/block/io.c
58
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top,
59
}
60
61
int coroutine_fn
62
-bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
63
- bool is_read)
64
+bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
65
{
66
BlockDriver *drv = bs->drv;
67
BlockDriverState *child_bs = bdrv_primary_bs(bs);
68
int ret = -ENOTSUP;
69
70
+ if (!drv) {
71
+ return -ENOMEDIUM;
72
+ }
73
+
74
bdrv_inc_in_flight(bs);
75
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
+ }
81
+
82
+ bdrv_dec_in_flight(bs);
83
+
84
+ return ret;
85
+}
86
+
87
+int coroutine_fn
88
+bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
89
+{
90
+ BlockDriver *drv = bs->drv;
91
+ BlockDriverState *child_bs = bdrv_primary_bs(bs);
92
+ int ret = -ENOTSUP;
93
+
94
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;
103
+ }
104
+
105
+ bdrv_inc_in_flight(bs);
106
+
107
+ if (drv->bdrv_save_vmstate) {
108
+ ret = drv->bdrv_save_vmstate(bs, qiov, pos);
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
+
116
return ret;
117
}
118
119
@@ -XXX,XX +XXX,XX @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
120
int64_t pos, int size)
121
{
122
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size);
123
- int ret;
124
+ int ret = bdrv_writev_vmstate(bs, &qiov, pos);
125
126
- ret = bdrv_writev_vmstate(bs, &qiov, pos);
127
- if (ret < 0) {
128
- return ret;
129
- }
130
-
131
- return size;
132
-}
133
-
134
-int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
135
-{
136
- return bdrv_rw_vmstate(bs, qiov, pos, false);
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
/**************************************************************/
26
--
162
--
27
2.24.1
163
2.26.2
28
164
29
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 can't access top after call bdrv_backup_top_drop, as it is already
3
This is the only non-ascii character in the file and it doesn't really
4
freed at this time.
4
needed here. Let's use normal "'" symbol for consistency with the rest
5
11 occurrences of "'" in the file.
5
6
6
Also, no needs to unref target child by hand, it will be unrefed on
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
bdrv_close() automatically.
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
include/block/block.h | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
8
13
9
So, just do bdrv_backup_top_drop if append succeed and one bdrv_unref
14
diff --git a/include/block/block.h b/include/block/block.h
10
otherwise.
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
17
+++ b/include/block/block.h
18
@@ -XXX,XX +XXX,XX @@ enum BdrvChildRoleBits {
19
BDRV_CHILD_FILTERED = (1 << 2),
20
21
/*
22
- * Child from which to read all data that isn’t allocated in the
23
+ * Child from which to read all data that isn't allocated in the
24
* parent (i.e., the backing child); such data is copied to the
25
* parent through COW (and optionally COR).
26
* This field is mutually exclusive with DATA, METADATA, and
27
--
28
2.26.2
11
29
12
Note, that in !appended case bdrv_unref(top) moved into drained section
13
on source. It doesn't really matter, but just for code simplicity.
14
15
Fixes: 7df7868b96404
16
Cc: qemu-stable@nongnu.org # v4.2.0
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Message-id: 20200121142802.21467-2-vsementsov@virtuozzo.com
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
block/backup-top.c | 21 ++++++++++++---------
23
1 file changed, 12 insertions(+), 9 deletions(-)
24
25
diff --git a/block/backup-top.c b/block/backup-top.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block/backup-top.c
28
+++ b/block/backup-top.c
29
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
30
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
31
filter_node_name,
32
BDRV_O_RDWR, errp);
33
+ bool appended = false;
34
35
if (!top) {
36
return NULL;
37
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
38
bdrv_append(top, source, &local_err);
39
if (local_err) {
40
error_prepend(&local_err, "Cannot append backup-top filter: ");
41
- goto append_failed;
42
+ goto fail;
43
}
44
+ appended = true;
45
46
/*
47
* bdrv_append() finished successfully, now we can require permissions
48
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
49
if (local_err) {
50
error_prepend(&local_err,
51
"Cannot set permissions for backup-top filter: ");
52
- goto failed_after_append;
53
+ goto fail;
54
}
55
56
state->bcs = block_copy_state_new(top->backing, state->target,
57
cluster_size, write_flags, &local_err);
58
if (local_err) {
59
error_prepend(&local_err, "Cannot create block-copy-state: ");
60
- goto failed_after_append;
61
+ goto fail;
62
}
63
*bcs = state->bcs;
64
65
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
66
67
return top;
68
69
-failed_after_append:
70
- state->active = false;
71
- bdrv_backup_top_drop(top);
72
+fail:
73
+ if (appended) {
74
+ state->active = false;
75
+ bdrv_backup_top_drop(top);
76
+ } else {
77
+ bdrv_unref(top);
78
+ }
79
80
-append_failed:
81
bdrv_drained_end(source);
82
- bdrv_unref_child(top, state->target);
83
- bdrv_unref(top);
84
error_propagate(errp, local_err);
85
86
return NULL;
87
--
88
2.24.1
89
90
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
verify_platform will check an explicit whitelist and blacklist instead.
3
When we added io_uring AIO engine, we forgot to update qemu-options.hx,
4
The default will now be assumed to be allowed to run anywhere.
4
so qemu(1) man page and qemu help were outdated.
5
5
6
For tests that do not specify their platforms explicitly, this has the effect of
6
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
7
enabling these tests on non-linux platforms. For tests that always specified
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
linux explicitly, there is no change.
8
Reviewed-by: Julia Suvorova <jusual@redhat.com>
9
Reviewed-by: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
10
Message-Id: <20200924151511.131471-1-sgarzare@redhat.com>
11
---
12
qemu-options.hx | 10 ++++++----
13
1 file changed, 6 insertions(+), 4 deletions(-)
9
14
10
For Python tests on FreeBSD at least; only seven python tests fail:
15
diff --git a/qemu-options.hx b/qemu-options.hx
11
045 147 149 169 194 199 211
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-options.hx
18
+++ b/qemu-options.hx
19
@@ -XXX,XX +XXX,XX @@ SRST
20
The path to the image file in the local filesystem
21
22
``aio``
23
- Specifies the AIO backend (threads/native, default: threads)
24
+ Specifies the AIO backend (threads/native/io_uring,
25
+ default: threads)
26
27
``locking``
28
Specifies whether the image file is protected with Linux OFD
29
@@ -XXX,XX +XXX,XX @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
30
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
31
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
32
" [,snapshot=on|off][,rerror=ignore|stop|report]\n"
33
- " [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
34
+ " [,werror=ignore|stop|report|enospc][,id=name]\n"
35
+ " [,aio=threads|native|io_uring]\n"
36
" [,readonly=on|off][,copy-on-read=on|off]\n"
37
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
38
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
39
@@ -XXX,XX +XXX,XX @@ SRST
40
The default mode is ``cache=writeback``.
41
42
``aio=aio``
43
- aio is "threads", or "native" and selects between pthread based
44
- disk I/O and native Linux AIO.
45
+ aio is "threads", "native", or "io_uring" and selects between pthread
46
+ based disk I/O, native Linux AIO, or Linux io_uring API.
47
48
``format=format``
49
Specify which disk format will be used rather than detecting the
50
--
51
2.26.2
12
52
13
045 and 149 appear to be misconfigurations,
14
147 and 194 are the AF_UNIX path too long error,
15
169 and 199 are bitmap migration bugs, and
16
211 is a bug that shows up on Linux platforms, too.
17
18
This is at least good evidence that these tests are not Linux-only. If
19
they aren't suitable for other platforms, they should be disabled on a
20
per-platform basis as appropriate.
21
22
Therefore, let's switch these on and deal with the failures.
23
24
Reviewed-by: Max Reitz <mreitz@redhat.com>
25
Signed-off-by: John Snow <jsnow@redhat.com>
26
Message-id: 20200121095205.26323-2-thuth@redhat.com
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
28
---
29
tests/qemu-iotests/iotests.py | 16 +++++++++++-----
30
1 file changed, 11 insertions(+), 5 deletions(-)
31
32
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/qemu-iotests/iotests.py
35
+++ b/tests/qemu-iotests/iotests.py
36
@@ -XXX,XX +XXX,XX @@ def verify_protocol(supported=[], unsupported=[]):
37
if not_sup or (imgproto in unsupported):
38
notrun('not suitable for this protocol: %s' % imgproto)
39
40
-def verify_platform(supported_oses=['linux']):
41
- if True not in [sys.platform.startswith(x) for x in supported_oses]:
42
- notrun('not suitable for this OS: %s' % sys.platform)
43
+def verify_platform(supported=None, unsupported=None):
44
+ if unsupported is not None:
45
+ if any((sys.platform.startswith(x) for x in unsupported)):
46
+ notrun('not suitable for this OS: %s' % sys.platform)
47
+
48
+ if supported is not None:
49
+ if not any((sys.platform.startswith(x) for x in supported)):
50
+ notrun('not suitable for this OS: %s' % sys.platform)
51
52
def verify_cache_mode(supported_cache_modes=[]):
53
if supported_cache_modes and (cachemode not in supported_cache_modes):
54
@@ -XXX,XX +XXX,XX @@ def execute_unittest(output, verbosity, debug):
55
sys.stderr.write(out)
56
57
def execute_test(test_function=None,
58
- supported_fmts=[], supported_oses=['linux'],
59
+ supported_fmts=[],
60
+ supported_platforms=None,
61
supported_cache_modes=[], supported_aio_modes={},
62
unsupported_fmts=[], supported_protocols=[],
63
unsupported_protocols=[]):
64
@@ -XXX,XX +XXX,XX @@ def execute_test(test_function=None,
65
verbosity = 1
66
verify_image_format(supported_fmts, unsupported_fmts)
67
verify_protocol(supported_protocols, unsupported_protocols)
68
- verify_platform(supported_oses)
69
+ verify_platform(supported=supported_platforms)
70
verify_cache_mode(supported_cache_modes)
71
verify_aio_mode(supported_aio_modes)
72
73
--
74
2.24.1
75
76
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Eric Auger <eric.auger@redhat.com>
2
2
3
The standard cluster descriptor in L2 table entries has a field to
3
The IOVA allocator currently ignores host reserved regions.
4
store the host cluster offset. When we need to get that offset from an
4
As a result some chosen IOVAs may collide with some of them,
5
entry we use L2E_OFFSET_MASK to ensure that we only use the bits that
5
resulting in VFIO MAP_DMA errors later on. This happens on ARM
6
belong to that field.
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.
7
10
8
But while that mask is used every time we read from an L2 entry, it
11
Signed-off-by: Eric Auger <eric.auger@redhat.com>
9
is never used when we write to it. Due to the QCOW_MAX_CLUSTER_OFFSET
12
Message-id: 20200929085550.30926-2-eric.auger@redhat.com
10
limit set in the cluster allocation code QEMU can never produce
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
offsets that don't fit in that field so any such offset would indicate
14
---
12
a bug in QEMU.
15
util/vfio-helpers.c | 72 +++++++++++++++++++++++++++++++++++++++++++--
16
1 file changed, 70 insertions(+), 2 deletions(-)
13
17
14
Compressed cluster descriptors contain two fields (host cluster offset
18
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
15
and size of the compressed data) and the situation with them is
19
index XXXXXXX..XXXXXXX 100644
16
similar. In this case the masks are not constant but are stored in the
20
--- a/util/vfio-helpers.c
17
csize_mask and cluster_offset_mask fields of BDRVQcow2State.
21
+++ b/util/vfio-helpers.c
22
@@ -XXX,XX +XXX,XX @@ typedef struct {
23
uint64_t iova;
24
} IOVAMapping;
25
26
+struct IOVARange {
27
+ uint64_t start;
28
+ uint64_t end;
29
+};
30
+
31
struct QEMUVFIOState {
32
QemuMutex lock;
33
34
@@ -XXX,XX +XXX,XX @@ struct QEMUVFIOState {
35
int device;
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
}
46
47
+static void collect_usable_iova_ranges(QEMUVFIOState *s, void *buf)
48
+{
49
+ struct vfio_iommu_type1_info *info = (struct vfio_iommu_type1_info *)buf;
50
+ struct vfio_info_cap_header *cap = (void *)buf + info->cap_offset;
51
+ struct vfio_iommu_type1_info_cap_iova_range *cap_iova_range;
52
+ int i;
53
+
54
+ while (cap->id != VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE) {
55
+ if (!cap->next) {
56
+ return;
57
+ }
58
+ cap = (struct vfio_info_cap_header *)(buf + cap->next);
59
+ }
60
+
61
+ cap_iova_range = (struct vfio_iommu_type1_info_cap_iova_range *)cap;
62
+
63
+ s->nb_iova_ranges = cap_iova_range->nr_iovas;
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
+ }
69
+
70
+ for (i = 0; i < s->nb_iova_ranges; i++) {
71
+ s->usable_iova_ranges[i].start = cap_iova_range->iova_ranges[i].start;
72
+ s->usable_iova_ranges[i].end = cap_iova_range->iova_ranges[i].end;
73
+ }
74
+}
75
+
76
static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
77
Error **errp)
78
{
79
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
80
int i;
81
uint16_t pci_cmd;
82
struct vfio_group_status group_status = { .argsz = sizeof(group_status) };
83
- struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };
84
+ struct vfio_iommu_type1_info *iommu_info = NULL;
85
+ size_t iommu_info_size = sizeof(*iommu_info);
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
}
97
98
+ iommu_info = g_malloc0(iommu_info_size);
99
+ iommu_info->argsz = iommu_info_size;
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
+ }
127
+
128
s->device = ioctl(s->group, VFIO_GROUP_GET_DEVICE_FD, device);
129
130
if (s->device < 0) {
131
@@ -XXX,XX +XXX,XX @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
132
if (ret) {
133
goto fail;
134
}
135
+ g_free(iommu_info);
136
return 0;
137
fail:
138
+ g_free(s->usable_iova_ranges);
139
+ s->usable_iova_ranges = NULL;
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
--
155
2.26.2
18
156
19
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Message-id: 20200113161146.20099-1-berto@igalia.com
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
block/qcow2-cluster.c | 14 ++++++++++++--
25
1 file changed, 12 insertions(+), 2 deletions(-)
26
27
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2-cluster.c
30
+++ b/block/qcow2-cluster.c
31
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
32
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
33
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
34
35
+ /* The offset and size must fit in their fields of the L2 table entry */
36
+ assert((cluster_offset & s->cluster_offset_mask) == cluster_offset);
37
+ assert((nb_csectors & s->csize_mask) == nb_csectors);
38
+
39
cluster_offset |= QCOW_OFLAG_COMPRESSED |
40
((uint64_t)nb_csectors << s->csize_shift);
41
42
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
43
44
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
45
for (i = 0; i < m->nb_clusters; i++) {
46
+ uint64_t offset = cluster_offset + (i << s->cluster_bits);
47
/* if two concurrent writes happen to the same unallocated cluster
48
* each write allocates separate cluster and writes data concurrently.
49
* The first one to complete updates l2 table with pointer to its
50
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
51
old_cluster[j++] = l2_slice[l2_index + i];
52
}
53
54
- l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
55
- (i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
56
+ /* The offset must fit in the offset field of the L2 table entry */
57
+ assert((offset & L2E_OFFSET_MASK) == offset);
58
+
59
+ l2_slice[l2_index + i] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
60
}
61
62
63
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
64
goto fail;
65
}
66
67
+ /* The offset must fit in the offset field */
68
+ assert((offset & L2E_OFFSET_MASK) == offset);
69
+
70
if (l2_refcount > 1) {
71
/* For shared L2 tables, set the refcount accordingly
72
* (it is already 1 and needs to be l2_refcount) */
73
--
74
2.24.1
75
76
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Eric Auger <eric.auger@redhat.com>
2
2
3
We are going to enable 127 in the "auto" group, but it only works if
3
Introduce the qemu_vfio_find_fixed/temp_iova helpers which
4
virtio-scsi and scsi-hd are available - which is not the case with
4
respectively allocate IOVAs from the bottom/top parts of the
5
QEMU binaries like qemu-system-tricore for example, so we need a
5
usable IOVA range, without picking within host IOVA reserved
6
proper check for the availability of these devices here.
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.
7
9
8
A very similar problem exists in iotest 267 - it has been added to
10
Signed-off-by: Eric Auger <eric.auger@redhat.com>
9
the "auto" group already, but requires virtio-blk and thus currently
11
Message-id: 20200929085550.30926-3-eric.auger@redhat.com
10
fails with qemu-system-tricore for example. Let's also add aproper
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
check there.
13
---
14
util/vfio-helpers.c | 57 +++++++++++++++++++++++++++++++++++++++++----
15
1 file changed, 53 insertions(+), 4 deletions(-)
12
16
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
14
Signed-off-by: Thomas Huth <thuth@redhat.com>
18
index XXXXXXX..XXXXXXX 100644
15
Message-id: 20200121095205.26323-5-thuth@redhat.com
19
--- a/util/vfio-helpers.c
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
+++ b/util/vfio-helpers.c
17
---
21
@@ -XXX,XX +XXX,XX @@ static bool qemu_vfio_verify_mappings(QEMUVFIOState *s)
18
tests/qemu-iotests/127 | 2 ++
22
return true;
19
tests/qemu-iotests/267 | 2 ++
23
}
20
tests/qemu-iotests/common.rc | 14 ++++++++++++++
24
21
3 files changed, 18 insertions(+)
25
+static int
22
26
+qemu_vfio_find_fixed_iova(QEMUVFIOState *s, size_t size, uint64_t *iova)
23
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
27
+{
24
index XXXXXXX..XXXXXXX 100755
28
+ int i;
25
--- a/tests/qemu-iotests/127
26
+++ b/tests/qemu-iotests/127
27
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
28
_supported_fmt qcow2
29
_supported_proto file
30
31
+_require_devices virtio-scsi scsi-hd
32
+
29
+
33
IMG_SIZE=64K
30
+ for (i = 0; i < s->nb_iova_ranges; i++) {
34
31
+ if (s->usable_iova_ranges[i].end < s->low_water_mark) {
35
_make_test_img $IMG_SIZE
32
+ continue;
36
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
33
+ }
37
index XXXXXXX..XXXXXXX 100755
34
+ s->low_water_mark =
38
--- a/tests/qemu-iotests/267
35
+ MAX(s->low_water_mark, s->usable_iova_ranges[i].start);
39
+++ b/tests/qemu-iotests/267
40
@@ -XXX,XX +XXX,XX @@ _require_drivers copy-on-read
41
# and generally impossible with external data files
42
_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
43
44
+_require_devices virtio-blk
45
+
36
+
46
do_run_qemu()
37
+ if (s->usable_iova_ranges[i].end - s->low_water_mark + 1 >= size ||
47
{
38
+ s->usable_iova_ranges[i].end - s->low_water_mark + 1 == 0) {
48
echo Testing: "$@"
39
+ *iova = s->low_water_mark;
49
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
40
+ s->low_water_mark += size;
50
index XXXXXXX..XXXXXXX 100644
41
+ return 0;
51
--- a/tests/qemu-iotests/common.rc
42
+ }
52
+++ b/tests/qemu-iotests/common.rc
43
+ }
53
@@ -XXX,XX +XXX,XX @@ _require_large_file()
44
+ return -ENOMEM;
54
rm "$TEST_IMG"
55
}
56
57
+# Check that a set of devices is available in the QEMU binary
58
+#
59
+_require_devices()
60
+{
61
+ available=$($QEMU -M none -device help | \
62
+ grep ^name | sed -e 's/^name "//' -e 's/".*$//')
63
+ for device
64
+ do
65
+ if ! echo "$available" | grep -q "$device" ; then
66
+ _notrun "$device not available"
67
+ fi
68
+ done
69
+}
45
+}
70
+
46
+
71
# make sure this script returns success
47
+static int
72
true
48
+qemu_vfio_find_temp_iova(QEMUVFIOState *s, size_t size, uint64_t *iova)
49
+{
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) {
73
--
105
--
74
2.24.1
106
2.26.2
75
107
76
diff view generated by jsdifflib