1
The following changes since commit b150cb8f67bf491a49a1cb1c7da151eeacbdbcc9:
1
The following changes since commit 8c5f94cd4182753959c8be8de415120dc879d8f0:
2
2
3
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging (2020-09-29 13:18:54 +0100)
3
Merge tag 'pull-loong-20211221-2' of https://gitlab.com/rth7680/qemu into staging (2021-12-21 13:30:35 -0800)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/hreitz/qemu.git tags/pull-block-2021-12-22
8
8
9
for you to fetch changes up to bc47831ff28d6f5830c9c8d74220131dc54c5253:
9
for you to fetch changes up to 722f87df2545b308aec49b459b028f0802b4fd9e:
10
10
11
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved regions (2020-09-30 10:23:05 +0100)
11
iotests: check: multiprocessing support (2021-12-22 16:29:48 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Block patches:
15
15
- Added support to the iotests for running tests in several parallel
16
Note I have switched from GitHub to GitLab.
16
jobs (using the new -j parameter)
17
17
18
----------------------------------------------------------------
18
----------------------------------------------------------------
19
Vladimir Sementsov-Ogievskiy (3):
20
iotests/testrunner.py: add doc string for run_test()
21
iotests/testrunner.py: move updating last_elapsed to run_tests
22
iotests: check: multiprocessing support
19
23
20
Eric Auger (2):
24
tests/qemu-iotests/check | 4 +-
21
util/vfio-helpers: Collect IOVA reserved regions
25
tests/qemu-iotests/testrunner.py | 86 ++++++++++++++++++++++++++++----
22
util/vfio-helpers: Rework the IOVA allocator to avoid IOVA reserved
26
2 files changed, 80 insertions(+), 10 deletions(-)
23
regions
24
25
Philippe Mathieu-Daudé (6):
26
util/vfio-helpers: Pass page protections to qemu_vfio_pci_map_bar()
27
block/nvme: Map doorbells pages write-only
28
block/nvme: Reduce I/O registers scope
29
block/nvme: Drop NVMeRegs structure, directly use NvmeBar
30
block/nvme: Use register definitions from 'block/nvme.h'
31
block/nvme: Replace magic value by SCALE_MS definition
32
33
Stefano Garzarella (1):
34
docs: add 'io_uring' option to 'aio' param in qemu-options.hx
35
36
Vladimir Sementsov-Ogievskiy (8):
37
block: return error-code from bdrv_invalidate_cache
38
block/io: refactor coroutine wrappers
39
block: declare some coroutine functions in block/coroutines.h
40
scripts: add block-coroutine-wrapper.py
41
block: generate coroutine-wrapper code
42
block: drop bdrv_prwv
43
block/io: refactor save/load vmstate
44
include/block/block.h: drop non-ascii quotation mark
45
46
block/block-gen.h | 49 ++++
47
block/coroutines.h | 65 +++++
48
include/block/block.h | 36 ++-
49
include/qemu/vfio-helpers.h | 2 +-
50
block.c | 97 +------
51
block/io.c | 339 ++++---------------------
52
block/nvme.c | 73 +++---
53
tests/test-bdrv-drain.c | 2 +-
54
util/vfio-helpers.c | 133 +++++++++-
55
block/meson.build | 8 +
56
docs/devel/block-coroutine-wrapper.rst | 54 ++++
57
docs/devel/index.rst | 1 +
58
qemu-options.hx | 10 +-
59
scripts/block-coroutine-wrapper.py | 188 ++++++++++++++
60
14 files changed, 629 insertions(+), 428 deletions(-)
61
create mode 100644 block/block-gen.h
62
create mode 100644 block/coroutines.h
63
create mode 100644 docs/devel/block-coroutine-wrapper.rst
64
create mode 100644 scripts/block-coroutine-wrapper.py
65
27
66
--
28
--
67
2.26.2
29
2.33.1
68
30
31
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Pages are currently mapped READ/WRITE. To be able to use different
4
protections, add a new argument to qemu_vfio_pci_map_bar().
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20200922083821.578519-2-philmd@redhat.com>
9
---
10
include/qemu/vfio-helpers.h | 2 +-
11
block/nvme.c | 3 ++-
12
util/vfio-helpers.c | 4 ++--
13
3 files changed, 5 insertions(+), 4 deletions(-)
14
15
diff --git a/include/qemu/vfio-helpers.h b/include/qemu/vfio-helpers.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/qemu/vfio-helpers.h
18
+++ b/include/qemu/vfio-helpers.h
19
@@ -XXX,XX +XXX,XX @@ int qemu_vfio_dma_map(QEMUVFIOState *s, void *host, size_t size,
20
int qemu_vfio_dma_reset_temporary(QEMUVFIOState *s);
21
void qemu_vfio_dma_unmap(QEMUVFIOState *s, void *host);
22
void *qemu_vfio_pci_map_bar(QEMUVFIOState *s, int index,
23
- uint64_t offset, uint64_t size,
24
+ uint64_t offset, uint64_t size, int prot,
25
Error **errp);
26
void qemu_vfio_pci_unmap_bar(QEMUVFIOState *s, int index, void *bar,
27
uint64_t offset, uint64_t size);
28
diff --git a/block/nvme.c b/block/nvme.c
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");
62
--
63
2.26.2
64
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Per the datasheet sections 3.1.13/3.1.14:
4
"The host should not read the doorbell registers."
5
6
As we don't need read access, map the doorbells with write-only
7
permission. We keep a reference to this mapped address in the
8
BDRVNVMeState structure.
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>
13
---
14
block/nvme.c | 29 +++++++++++++++++++----------
15
1 file changed, 19 insertions(+), 10 deletions(-)
16
17
diff --git a/block/nvme.c b/block/nvme.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/nvme.c
20
+++ b/block/nvme.c
21
@@ -XXX,XX +XXX,XX @@
22
#define NVME_SQ_ENTRY_BYTES 64
23
#define NVME_CQ_ENTRY_BYTES 16
24
#define NVME_QUEUE_SIZE 128
25
-#define NVME_BAR_SIZE 8192
26
+#define NVME_DOORBELL_SIZE 4096
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) {
78
ret = -EINVAL;
79
goto out;
80
}
81
-
82
/* Perform initialize sequence as described in NVMe spec "7.6.1
83
* Initialization". */
84
85
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
86
}
87
}
88
89
+ s->doorbells = qemu_vfio_pci_map_bar(s->vfio, 0, sizeof(NvmeBar),
90
+ NVME_DOORBELL_SIZE, PROT_WRITE, errp);
91
+ if (!s->doorbells) {
92
+ ret = -EINVAL;
93
+ goto out;
94
+ }
95
+
96
/* Set up admin queue. */
97
s->queues = g_new(NVMeQueuePair *, 1);
98
s->queues[INDEX_ADMIN] = nvme_create_queue_pair(s, aio_context, 0,
99
@@ -XXX,XX +XXX,XX @@ static void nvme_close(BlockDriverState *bs)
100
&s->irq_notifier[MSIX_SHARED_IRQ_IDX],
101
false, NULL, NULL);
102
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
103
- qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE);
104
+ qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->doorbells,
105
+ sizeof(NvmeBar), NVME_DOORBELL_SIZE);
106
+ qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, sizeof(NvmeBar));
107
qemu_vfio_close(s->vfio);
108
109
g_free(s->device);
110
--
111
2.26.2
112
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
We only access the I/O register in nvme_init().
4
Remove the reference in BDRVNVMeState and reduce its scope.
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
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(-)
12
13
diff --git a/block/nvme.c b/block/nvme.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
16
+++ b/block/nvme.c
17
@@ -XXX,XX +XXX,XX @@ enum {
18
struct BDRVNVMeState {
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
112
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
NVMeRegs only contains NvmeBar. Simplify the code by using NvmeBar
4
directly.
5
6
This triggers a checkpatch.pl error:
7
8
ERROR: Use of volatile is usually wrong, please add a comment
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>
18
---
19
block/nvme.c | 23 +++++++++--------------
20
1 file changed, 9 insertions(+), 14 deletions(-)
21
22
diff --git a/block/nvme.c b/block/nvme.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/nvme.c
25
+++ b/block/nvme.c
26
@@ -XXX,XX +XXX,XX @@ typedef struct {
27
QEMUBH *completion_bh;
28
} NVMeQueuePair;
29
30
-/* Memory mapped registers */
31
-typedef volatile struct {
32
- NvmeBar ctrl;
33
-} NVMeRegs;
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,
70
}
71
s->nr_queues = 1;
72
QEMU_BUILD_BUG_ON(NVME_QUEUE_SIZE & 0xF000);
73
- regs->ctrl.aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
74
- regs->ctrl.asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
75
- regs->ctrl.acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
76
+ regs->aqa = cpu_to_le32((NVME_QUEUE_SIZE << 16) | NVME_QUEUE_SIZE);
77
+ regs->asq = cpu_to_le64(s->queues[INDEX_ADMIN]->sq.iova);
78
+ regs->acq = cpu_to_le64(s->queues[INDEX_ADMIN]->cq.iova);
79
80
/* After setting up all control registers we can enable device now. */
81
- regs->ctrl.cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
82
+ regs->cc = cpu_to_le32((ctz32(NVME_CQ_ENTRY_BYTES) << 20) |
83
(ctz32(NVME_SQ_ENTRY_BYTES) << 16) |
84
0x1);
85
/* Wait for CSTS.RDY = 1. */
86
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
87
deadline = now + timeout_ms * 1000000;
88
- while (!(le32_to_cpu(regs->ctrl.csts) & 0x1)) {
89
+ while (!(le32_to_cpu(regs->csts) & 0x1)) {
90
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
91
error_setg(errp, "Timeout while waiting for device to start (%"
92
PRId64 " ms)",
93
--
94
2.26.2
95
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Use the NVMe register definitions from "block/nvme.h" which
4
ease a bit reviewing the code while matching the datasheet.
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20200922083821.578519-6-philmd@redhat.com>
9
---
10
block/nvme.c | 21 +++++++++++----------
11
1 file changed, 11 insertions(+), 10 deletions(-)
12
13
diff --git a/block/nvme.c b/block/nvme.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
16
+++ b/block/nvme.c
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
18
* Initialization". */
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
72
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Use self-explicit SCALE_MS definition instead of magic value
4
(missed in similar commit e4f310fe7f5).
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20200922083821.578519-7-philmd@redhat.com>
9
---
10
block/nvme.c | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
diff --git a/block/nvme.c b/block/nvme.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/nvme.c
16
+++ b/block/nvme.c
17
@@ -XXX,XX +XXX,XX @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
18
CC_EN_MASK);
19
/* Wait for CSTS.RDY = 1. */
20
now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
21
- deadline = now + timeout_ms * 1000000;
22
+ deadline = now + timeout_ms * SCALE_MS;
23
while (!NVME_CSTS_RDY(le32_to_cpu(regs->csts))) {
24
if (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) > deadline) {
25
error_setg(errp, "Timeout while waiting for device to start (%"
26
--
27
2.26.2
28
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We are going to keep coroutine-wrappers code (structure-packing
3
We are going to modify these methods and will add more documentation in
4
parameters, BDRV_POLL wrapper functions) in separate auto-generated
4
further commit. As a preparation add basic documentation.
5
files. So, we'll need a header with declaration of original _co_
6
functions, for those which are static now. As well, we'll need
7
declarations for wrapper functions. Do these declarations now, as a
8
preparation step.
9
5
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-Id: <20211203122223.2780098-2-vsementsov@virtuozzo.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Tested-by: John Snow <jsnow@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
Message-Id: <20200924185414.28642-4-vsementsov@virtuozzo.com>
16
---
11
---
17
block/coroutines.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++
12
tests/qemu-iotests/testrunner.py | 13 +++++++++++++
18
block.c | 8 +++---
13
1 file changed, 13 insertions(+)
19
block/io.c | 34 +++++++++++------------
20
3 files changed, 88 insertions(+), 21 deletions(-)
21
create mode 100644 block/coroutines.h
22
14
23
diff --git a/block/coroutines.h b/block/coroutines.h
15
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
24
new file mode 100644
16
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX
17
--- a/tests/qemu-iotests/testrunner.py
26
--- /dev/null
18
+++ b/tests/qemu-iotests/testrunner.py
27
+++ b/block/coroutines.h
19
@@ -XXX,XX +XXX,XX @@ def find_reference(self, test: str) -> str:
28
@@ -XXX,XX +XXX,XX @@
20
return f'{test}.out'
29
+/*
21
30
+ * Block layer I/O functions
22
def do_run_test(self, test: str) -> TestResult:
31
+ *
23
+ """
32
+ * Copyright (c) 2003 Fabrice Bellard
24
+ Run one test
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
+
25
+
53
+#ifndef BLOCK_COROUTINES_INT_H
26
+ :param test: test file path
54
+#define BLOCK_COROUTINES_INT_H
27
+ """
55
+
28
+
56
+#include "block/block_int.h"
29
f_test = Path(test)
30
f_bad = Path(f_test.name + '.out.bad')
31
f_notrun = Path(f_test.name + '.notrun')
32
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
33
34
def run_test(self, test: str,
35
test_field_width: Optional[int] = None) -> TestResult:
36
+ """
37
+ Run one test and print short status
57
+
38
+
58
+int coroutine_fn bdrv_co_check(BlockDriverState *bs,
39
+ :param test: test file path
59
+ BdrvCheckResult *res, BdrvCheckMode fix);
40
+ :param test_field_width: width for first field of status format
60
+int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
41
+ """
61
+
42
+
62
+int coroutine_fn
43
last_el = self.last_elapsed.get(test)
63
+bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
44
start = datetime.datetime.now().strftime('%H:%M:%S')
64
+ bool is_write, BdrvRequestFlags flags);
45
65
+int
66
+bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
67
+ bool is_write, BdrvRequestFlags flags);
68
+
69
+int coroutine_fn
70
+bdrv_co_common_block_status_above(BlockDriverState *bs,
71
+ BlockDriverState *base,
72
+ bool want_zero,
73
+ int64_t offset,
74
+ int64_t bytes,
75
+ int64_t *pnum,
76
+ int64_t *map,
77
+ BlockDriverState **file);
78
+int
79
+bdrv_common_block_status_above(BlockDriverState *bs,
80
+ BlockDriverState *base,
81
+ bool want_zero,
82
+ int64_t offset,
83
+ int64_t bytes,
84
+ int64_t *pnum,
85
+ int64_t *map,
86
+ BlockDriverState **file);
87
+
88
+int coroutine_fn
89
+bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
90
+ bool is_read);
91
+int
92
+bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
93
+ bool is_read);
94
+
95
+#endif /* BLOCK_COROUTINES_INT_H */
96
diff --git a/block.c b/block.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block.c
99
+++ b/block.c
100
@@ -XXX,XX +XXX,XX @@
101
#include "qemu/timer.h"
102
#include "qemu/cutils.h"
103
#include "qemu/id.h"
104
+#include "block/coroutines.h"
105
106
#ifdef CONFIG_BSD
107
#include <sys/ioctl.h>
108
@@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs)
109
* free of errors) or -errno when an internal error occurred. The results of the
110
* check are stored in res.
111
*/
112
-static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
113
- BdrvCheckResult *res, BdrvCheckMode fix)
114
+int coroutine_fn bdrv_co_check(BlockDriverState *bs,
115
+ BdrvCheckResult *res, BdrvCheckMode fix)
116
{
117
if (bs->drv == NULL) {
118
return -ENOMEDIUM;
119
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
120
bdrv_init();
121
}
122
123
-static int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
124
- Error **errp)
125
+int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp)
126
{
127
BdrvChild *child, *parent;
128
uint64_t perm, shared_perm;
129
diff --git a/block/io.c b/block/io.c
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)
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,
216
--
46
--
217
2.26.2
47
2.33.1
218
48
49
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Most of our coroutine wrappers already follow this convention:
3
We are going to use do_run_test() in multiprocessing environment, where
4
we'll not be able to change original runner object.
4
5
5
We have 'coroutine_fn bdrv_co_<something>(<normal argument list>)' as
6
Happily, the only thing we change is that last_elapsed and it's simple
6
the core function, and a wrapper 'bdrv_<something>(<same argument
7
to do it in run_tests() instead. All other accesses to self in
7
list>)' which does parameter packing and calls bdrv_run_co().
8
do_runt_test() and in run_test() are read-only.
8
9
The only outsiders are the bdrv_prwv_co and
10
bdrv_common_block_status_above wrappers. Let's refactor them to behave
11
as the others, it simplifies further conversion of coroutine wrappers.
12
13
This patch adds an indirection layer, but it will be compensated by
14
a further commit, which will drop bdrv_co_prwv together with the
15
is_write logic, to keep the read and write paths separate.
16
9
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20211203122223.2780098-3-vsementsov@virtuozzo.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: John Snow <jsnow@redhat.com>
20
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
Tested-by: John Snow <jsnow@redhat.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
22
Message-Id: <20200924185414.28642-3-vsementsov@virtuozzo.com>
23
---
15
---
24
block/io.c | 60 +++++++++++++++++++++++++++++-------------------------
16
tests/qemu-iotests/testrunner.py | 4 +++-
25
1 file changed, 32 insertions(+), 28 deletions(-)
17
1 file changed, 3 insertions(+), 1 deletion(-)
26
18
27
diff --git a/block/io.c b/block/io.c
19
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
28
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
29
--- a/block/io.c
21
--- a/tests/qemu-iotests/testrunner.py
30
+++ b/block/io.c
22
+++ b/tests/qemu-iotests/testrunner.py
31
@@ -XXX,XX +XXX,XX @@ typedef struct RwCo {
23
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
32
BdrvRequestFlags flags;
24
diff=diff, casenotrun=casenotrun)
33
} RwCo;
25
else:
34
26
f_bad.unlink()
35
+static int coroutine_fn bdrv_co_prwv(BdrvChild *child, int64_t offset,
27
- self.last_elapsed.update(test, elapsed)
36
+ QEMUIOVector *qiov, bool is_write,
28
return TestResult(status='pass', elapsed=elapsed,
37
+ BdrvRequestFlags flags)
29
casenotrun=casenotrun)
38
+{
30
39
+ if (is_write) {
31
@@ -XXX,XX +XXX,XX @@ def run_tests(self, tests: List[str]) -> bool:
40
+ return bdrv_co_pwritev(child, offset, qiov->size, qiov, flags);
32
print('\n'.join(res.diff))
41
+ } else {
33
elif res.status == 'not run':
42
+ return bdrv_co_preadv(child, offset, qiov->size, qiov, flags);
34
notrun.append(name)
43
+ }
35
+ elif res.status == 'pass':
44
+}
36
+ assert res.elapsed is not None
45
+
37
+ self.last_elapsed.update(t, res.elapsed)
46
static int coroutine_fn bdrv_rw_co_entry(void *opaque)
38
47
{
39
sys.stdout.flush()
48
RwCo *rwco = opaque;
40
if res.interrupted:
49
50
- if (!rwco->is_write) {
51
- return bdrv_co_preadv(rwco->child, rwco->offset,
52
- rwco->qiov->size, rwco->qiov,
53
- rwco->flags);
54
- } else {
55
- return bdrv_co_pwritev(rwco->child, rwco->offset,
56
- rwco->qiov->size, rwco->qiov,
57
- rwco->flags);
58
- }
59
+ return bdrv_co_prwv(rwco->child, rwco->offset, rwco->qiov,
60
+ rwco->is_write, rwco->flags);
61
}
62
63
/*
64
* Process a vectored synchronous request using coroutines
65
*/
66
-static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
67
- QEMUIOVector *qiov, bool is_write,
68
- BdrvRequestFlags flags)
69
+static int bdrv_prwv(BdrvChild *child, int64_t offset,
70
+ QEMUIOVector *qiov, bool is_write,
71
+ BdrvRequestFlags flags)
72
{
73
RwCo rwco = {
74
.child = child,
75
@@ -XXX,XX +XXX,XX @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
76
{
77
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
78
79
- return bdrv_prwv_co(child, offset, &qiov, true,
80
- BDRV_REQ_ZERO_WRITE | flags);
81
+ return bdrv_prwv(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags);
82
}
83
84
/*
85
@@ -XXX,XX +XXX,XX @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
86
{
87
int ret;
88
89
- ret = bdrv_prwv_co(child, offset, qiov, false, 0);
90
+ ret = bdrv_prwv(child, offset, qiov, false, 0);
91
if (ret < 0) {
92
return ret;
93
}
94
@@ -XXX,XX +XXX,XX @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
95
{
96
int ret;
97
98
- ret = bdrv_prwv_co(child, offset, qiov, true, 0);
99
+ ret = bdrv_prwv(child, offset, qiov, true, 0);
100
if (ret < 0) {
101
return ret;
102
}
103
@@ -XXX,XX +XXX,XX @@ early_out:
104
return ret;
105
}
106
107
-static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
108
- BlockDriverState *base,
109
- bool want_zero,
110
- int64_t offset,
111
- int64_t bytes,
112
- int64_t *pnum,
113
- int64_t *map,
114
- BlockDriverState **file)
115
+static int coroutine_fn
116
+bdrv_co_common_block_status_above(BlockDriverState *bs,
117
+ BlockDriverState *base,
118
+ bool want_zero,
119
+ int64_t offset,
120
+ int64_t bytes,
121
+ int64_t *pnum,
122
+ int64_t *map,
123
+ BlockDriverState **file)
124
{
125
BlockDriverState *p;
126
int ret = 0;
127
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
128
{
129
BdrvCoBlockStatusData *data = opaque;
130
131
- return bdrv_co_block_status_above(data->bs, data->base,
132
- data->want_zero,
133
- data->offset, data->bytes,
134
- data->pnum, data->map, data->file);
135
+ return bdrv_co_common_block_status_above(data->bs, data->base,
136
+ data->want_zero,
137
+ data->offset, data->bytes,
138
+ data->pnum, data->map, data->file);
139
}
140
141
/*
142
--
41
--
143
2.26.2
42
2.33.1
144
43
44
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This is the only coroutine wrapper from block.c and block/io.c which
3
Add -j <JOBS> parameter, to run tests in several jobs simultaneously.
4
doesn't return a value, so let's convert it to the common behavior, to
4
For realization - simply utilize multiprocessing.Pool class.
5
simplify moving to generated coroutine wrappers in a further commit.
6
5
7
Also, bdrv_invalidate_cache is a void function, returning error only
6
Notes:
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.
11
7
12
This patch leaves the conversion of .bdrv_co_invalidate_cache() driver
8
1. Of course, tests can't run simultaneously in same TEST_DIR. So,
13
callbacks and bdrv_invalidate_cache_all() for another day.
9
use subdirectories TEST_DIR/testname/ and SOCK_DIR/testname/
10
instead of simply TEST_DIR and SOCK_DIR
11
12
2. multiprocessing.Pool.starmap function doesn't support passing
13
context managers, so we can't simply pass "self". Happily, we need
14
self only for read-only access, and it just works if it is defined
15
in global space. So, add a temporary link TestRunner.shared_self
16
during run_tests().
14
17
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-Id: <20211203122223.2780098-4-vsementsov@virtuozzo.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reviewed-by: John Snow <jsnow@redhat.com>
18
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
21
Tested-by: John Snow <jsnow@redhat.com>
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
20
Message-Id: <20200924185414.28642-2-vsementsov@virtuozzo.com>
21
---
23
---
22
include/block/block.h | 2 +-
24
tests/qemu-iotests/check | 4 +-
23
block.c | 32 ++++++++++++++++++--------------
25
tests/qemu-iotests/testrunner.py | 69 ++++++++++++++++++++++++++++----
24
2 files changed, 19 insertions(+), 15 deletions(-)
26
2 files changed, 64 insertions(+), 9 deletions(-)
25
27
26
diff --git a/include/block/block.h b/include/block/block.h
28
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
29
index XXXXXXX..XXXXXXX 100755
30
--- a/tests/qemu-iotests/check
31
+++ b/tests/qemu-iotests/check
32
@@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser:
33
help='show me, do not run tests')
34
p.add_argument('-makecheck', action='store_true',
35
help='pretty print output for make check')
36
+ p.add_argument('-j', dest='jobs', type=int, default=1,
37
+ help='run tests in multiple parallel jobs')
38
39
p.add_argument('-d', dest='debug', action='store_true', help='debug')
40
p.add_argument('-p', dest='print', action='store_true',
41
@@ -XXX,XX +XXX,XX @@ if __name__ == '__main__':
42
with TestRunner(env, makecheck=args.makecheck,
43
color=args.color) as tr:
44
paths = [os.path.join(env.source_iotests, t) for t in tests]
45
- ok = tr.run_tests(paths)
46
+ ok = tr.run_tests(paths, args.jobs)
47
if not ok:
48
sys.exit(1)
49
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
27
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block.h
51
--- a/tests/qemu-iotests/testrunner.py
29
+++ b/include/block/block.h
52
+++ b/tests/qemu-iotests/testrunner.py
30
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel_async(BlockAIOCB *acb);
53
@@ -XXX,XX +XXX,XX @@
31
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
54
import json
32
55
import termios
33
/* Invalidate any cached metadata used by image formats */
56
import sys
34
-void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
57
+from multiprocessing import Pool
35
+int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
58
from contextlib import contextmanager
36
void bdrv_invalidate_cache_all(Error **errp);
59
from typing import List, Optional, Iterator, Any, Sequence, Dict, \
37
int bdrv_inactivate_all(void);
60
ContextManager
38
61
@@ -XXX,XX +XXX,XX @@ def __init__(self, status: str, description: str = '',
39
diff --git a/block.c b/block.c
62
40
index XXXXXXX..XXXXXXX 100644
63
41
--- a/block.c
64
class TestRunner(ContextManager['TestRunner']):
42
+++ b/block.c
65
+ shared_self = None
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)
51
{
52
BdrvChild *child, *parent;
53
uint64_t perm, shared_perm;
54
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
55
BdrvDirtyBitmap *bm;
56
57
if (!bs->drv) {
58
- return;
59
+ return -ENOMEDIUM;
60
}
61
62
QLIST_FOREACH(child, &bs->children, next) {
63
bdrv_co_invalidate_cache(child->bs, &local_err);
64
if (local_err) {
65
error_propagate(errp, local_err);
66
- return;
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;
86
}
87
}
88
89
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
90
if (ret < 0) {
91
bs->open_flags |= BDRV_O_INACTIVE;
92
error_setg_errno(errp, -ret, "Could not refresh total sector count");
93
- return;
94
+ return ret;
95
}
96
}
97
98
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
99
if (local_err) {
100
bs->open_flags |= BDRV_O_INACTIVE;
101
error_propagate(errp, local_err);
102
- return;
103
+ return -EINVAL;
104
}
105
}
106
}
107
+
66
+
108
+ return 0;
67
+ @staticmethod
109
}
68
+ def proc_run_test(test: str, test_field_width: int) -> TestResult:
110
69
+ # We are in a subprocess, we can't change the runner object!
111
typedef struct InvalidateCacheCo {
70
+ runner = TestRunner.shared_self
112
BlockDriverState *bs;
71
+ assert runner is not None
113
Error **errp;
72
+ return runner.run_test(test, test_field_width, mp=True)
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
+
73
+
137
+ return ico.ret;
74
+ def run_tests_pool(self, tests: List[str],
138
}
75
+ test_field_width: int, jobs: int) -> List[TestResult]:
139
76
+
140
void bdrv_invalidate_cache_all(Error **errp)
77
+ # passing self directly to Pool.starmap() just doesn't work, because
141
{
78
+ # it's a context manager.
142
BlockDriverState *bs;
79
+ assert TestRunner.shared_self is None
143
- Error *local_err = NULL;
80
+ TestRunner.shared_self = self
144
BdrvNextIterator it;
81
+
145
82
+ with Pool(jobs) as p:
146
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
83
+ results = p.starmap(self.proc_run_test,
147
AioContext *aio_context = bdrv_get_aio_context(bs);
84
+ zip(tests, [test_field_width] * len(tests)))
148
+ int ret;
85
+
149
86
+ TestRunner.shared_self = None
150
aio_context_acquire(aio_context);
87
+
151
- bdrv_invalidate_cache(bs, &local_err);
88
+ return results
152
+ ret = bdrv_invalidate_cache(bs, errp);
89
+
153
aio_context_release(aio_context);
90
def __init__(self, env: TestEnv, makecheck: bool = False,
154
- if (local_err) {
91
color: str = 'auto') -> None:
155
- error_propagate(errp, local_err);
92
self.env = env
156
+ if (ret < 0) {
93
@@ -XXX,XX +XXX,XX @@ def find_reference(self, test: str) -> str:
157
bdrv_next_cleanup(&it);
94
158
return;
95
return f'{test}.out'
159
}
96
97
- def do_run_test(self, test: str) -> TestResult:
98
+ def do_run_test(self, test: str, mp: bool) -> TestResult:
99
"""
100
Run one test
101
102
:param test: test file path
103
+ :param mp: if true, we are in a multiprocessing environment, use
104
+ personal subdirectories for test run
105
+
106
+ Note: this method may be called from subprocess, so it does not
107
+ change ``self`` object in any way!
108
"""
109
110
f_test = Path(test)
111
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
112
113
args = [str(f_test.resolve())]
114
env = self.env.prepare_subprocess(args)
115
+ if mp:
116
+ # Split test directories, so that tests running in parallel don't
117
+ # break each other.
118
+ for d in ['TEST_DIR', 'SOCK_DIR']:
119
+ env[d] = os.path.join(env[d], f_test.name)
120
+ Path(env[d]).mkdir(parents=True, exist_ok=True)
121
122
t0 = time.time()
123
with f_bad.open('w', encoding="utf-8") as f:
124
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
125
casenotrun=casenotrun)
126
127
def run_test(self, test: str,
128
- test_field_width: Optional[int] = None) -> TestResult:
129
+ test_field_width: Optional[int] = None,
130
+ mp: bool = False) -> TestResult:
131
"""
132
Run one test and print short status
133
134
:param test: test file path
135
:param test_field_width: width for first field of status format
136
+ :param mp: if true, we are in a multiprocessing environment, don't try
137
+ to rewrite things in stdout
138
+
139
+ Note: this method may be called from subprocess, so it does not
140
+ change ``self`` object in any way!
141
"""
142
143
last_el = self.last_elapsed.get(test)
144
start = datetime.datetime.now().strftime('%H:%M:%S')
145
146
if not self.makecheck:
147
- self.test_print_one_line(test=test, starttime=start,
148
- lasttime=last_el, end='\r',
149
+ self.test_print_one_line(test=test,
150
+ status = 'started' if mp else '...',
151
+ starttime=start,
152
+ lasttime=last_el,
153
+ end = '\n' if mp else '\r',
154
test_field_width=test_field_width)
155
156
- res = self.do_run_test(test)
157
+ res = self.do_run_test(test, mp)
158
159
end = datetime.datetime.now().strftime('%H:%M:%S')
160
self.test_print_one_line(test=test, status=res.status,
161
@@ -XXX,XX +XXX,XX @@ def run_test(self, test: str,
162
163
return res
164
165
- def run_tests(self, tests: List[str]) -> bool:
166
+ def run_tests(self, tests: List[str], jobs: int = 1) -> bool:
167
n_run = 0
168
failed = []
169
notrun = []
170
@@ -XXX,XX +XXX,XX @@ def run_tests(self, tests: List[str]) -> bool:
171
172
test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
173
174
- for t in tests:
175
+ if jobs > 1:
176
+ results = self.run_tests_pool(tests, test_field_width, jobs)
177
+
178
+ for i, t in enumerate(tests):
179
name = os.path.basename(t)
180
- res = self.run_test(t, test_field_width=test_field_width)
181
+
182
+ if jobs > 1:
183
+ res = results[i]
184
+ else:
185
+ res = self.run_test(t, test_field_width)
186
187
assert res.status in ('pass', 'fail', 'not run')
188
160
--
189
--
161
2.26.2
190
2.33.1
162
191
192
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
We have a very frequent pattern of creating a coroutine from a function
4
with several arguments:
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
40
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
41
Reviewed-by: Eric Blake <eblake@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.
45
--Stefan]
46
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
47
---
48
block/block-gen.h | 49 +++++++
49
include/block/block.h | 10 ++
50
block/meson.build | 8 ++
51
docs/devel/block-coroutine-wrapper.rst | 54 +++++++
52
docs/devel/index.rst | 1 +
53
scripts/block-coroutine-wrapper.py | 188 +++++++++++++++++++++++++
54
6 files changed, 310 insertions(+)
55
create mode 100644 block/block-gen.h
56
create mode 100644 docs/devel/block-coroutine-wrapper.rst
57
create mode 100644 scripts/block-coroutine-wrapper.py
58
59
diff --git a/block/block-gen.h b/block/block-gen.h
60
new file mode 100644
61
index XXXXXXX..XXXXXXX
62
--- /dev/null
63
+++ b/block/block-gen.h
64
@@ -XXX,XX +XXX,XX @@
65
+/*
66
+ * Block coroutine wrapping core, used by auto-generated block/block-gen.c
67
+ *
68
+ * Copyright (c) 2003 Fabrice Bellard
69
+ * Copyright (c) 2020 Virtuozzo International GmbH
70
+ *
71
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
72
+ * of this software and associated documentation files (the "Software"), to deal
73
+ * in the Software without restriction, including without limitation the rights
74
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
75
+ * copies of the Software, and to permit persons to whom the Software is
76
+ * furnished to do so, subject to the following conditions:
77
+ *
78
+ * The above copyright notice and this permission notice shall be included in
79
+ * all copies or substantial portions of the Software.
80
+ *
81
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
82
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
83
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
84
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
85
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
86
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
87
+ * THE SOFTWARE.
88
+ */
89
+
90
+#ifndef BLOCK_BLOCK_GEN_H
91
+#define BLOCK_BLOCK_GEN_H
92
+
93
+#include "block/block_int.h"
94
+
95
+/* Base structure for argument packing structures */
96
+typedef struct BdrvPollCo {
97
+ BlockDriverState *bs;
98
+ bool in_progress;
99
+ int ret;
100
+ Coroutine *co; /* Keep pointer here for debugging */
101
+} BdrvPollCo;
102
+
103
+static inline int bdrv_poll_co(BdrvPollCo *s)
104
+{
105
+ assert(!qemu_in_coroutine());
106
+
107
+ bdrv_coroutine_enter(s->bs, s->co);
108
+ BDRV_POLL_WHILE(s->bs, s->in_progress);
109
+
110
+ return s->ret;
111
+}
112
+
113
+#endif /* BLOCK_BLOCK_GEN_H */
114
diff --git a/include/block/block.h b/include/block/block.h
115
index XXXXXXX..XXXXXXX 100644
116
--- a/include/block/block.h
117
+++ b/include/block/block.h
118
@@ -XXX,XX +XXX,XX @@
119
#include "block/blockjob.h"
120
#include "qemu/hbitmap.h"
121
122
+/*
123
+ * generated_co_wrapper
124
+ *
125
+ * Function specifier, which does nothing but mark functions to be
126
+ * generated by scripts/block-coroutine-wrapper.py
127
+ *
128
+ * Read more in docs/devel/block-coroutine-wrapper.rst
129
+ */
130
+#define generated_co_wrapper
131
+
132
/* block.c */
133
typedef struct BlockDriver BlockDriver;
134
typedef struct BdrvChild BdrvChild;
135
diff --git a/block/meson.build b/block/meson.build
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/meson.build
138
+++ b/block/meson.build
139
@@ -XXX,XX +XXX,XX @@ module_block_h = custom_target('module_block.h',
140
command: [module_block_py, '@OUTPUT0@', modsrc])
141
block_ss.add(module_block_h)
142
143
+wrapper_py = find_program('../scripts/block-coroutine-wrapper.py')
144
+block_gen_c = custom_target('block-gen.c',
145
+ output: 'block-gen.c',
146
+ input: files('../include/block/block.h',
147
+ 'coroutines.h'),
148
+ command: [wrapper_py, '@OUTPUT@', '@INPUT@'])
149
+block_ss.add(block_gen_c)
150
+
151
block_ss.add(files('stream.c'))
152
153
softmmu_ss.add(files('qapi-sysemu.c'))
154
diff --git a/docs/devel/block-coroutine-wrapper.rst b/docs/devel/block-coroutine-wrapper.rst
155
new file mode 100644
156
index XXXXXXX..XXXXXXX
157
--- /dev/null
158
+++ b/docs/devel/block-coroutine-wrapper.rst
159
@@ -XXX,XX +XXX,XX @@
160
+=======================
161
+block-coroutine-wrapper
162
+=======================
163
+
164
+A lot of functions in QEMU block layer (see ``block/*``) can only be
165
+called in coroutine context. Such functions are normally marked by the
166
+coroutine_fn specifier. Still, sometimes we need to call them from
167
+non-coroutine context; for this we need to start a coroutine, run the
168
+needed function from it and wait for the coroutine to finish in a
169
+BDRV_POLL_WHILE() loop. To run a coroutine we need a function with one
170
+void* argument. So for each coroutine_fn function which needs a
171
+non-coroutine interface, we should define a structure to pack the
172
+parameters, define a separate function to unpack the parameters and
173
+call the original function and finally define a new interface function
174
+with same list of arguments as original one, which will pack the
175
+parameters into a struct, create a coroutine, run it and wait in
176
+BDRV_POLL_WHILE() loop. It's boring to create such wrappers by hand,
177
+so we have a script to generate them.
178
+
179
+Usage
180
+=====
181
+
182
+Assume we have defined the ``coroutine_fn`` function
183
+``bdrv_co_foo(<some args>)`` and need a non-coroutine interface for it,
184
+called ``bdrv_foo(<same args>)``. In this case the script can help. To
185
+trigger the generation:
186
+
187
+1. You need ``bdrv_foo`` declaration somewhere (for example, in
188
+ ``block/coroutines.h``) with the ``generated_co_wrapper`` mark,
189
+ like this:
190
+
191
+.. code-block:: c
192
+
193
+ int generated_co_wrapper bdrv_foo(<some args>);
194
+
195
+2. You need to feed this declaration to block-coroutine-wrapper script.
196
+ For this, add the .h (or .c) file with the declaration to the
197
+ ``input: files(...)`` list of ``block_gen_c`` target declaration in
198
+ ``block/meson.build``
199
+
200
+You are done. During the build, coroutine wrappers will be generated in
201
+``<BUILD_DIR>/block/block-gen.c``.
202
+
203
+Links
204
+=====
205
+
206
+1. The script location is ``scripts/block-coroutine-wrapper.py``.
207
+
208
+2. Generic place for private ``generated_co_wrapper`` declarations is
209
+ ``block/coroutines.h``, for public declarations:
210
+ ``include/block/block.h``
211
+
212
+3. The core API of generated coroutine wrappers is placed in
213
+ (not generated) ``block/block-gen.h``
214
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
215
index XXXXXXX..XXXXXXX 100644
216
--- a/docs/devel/index.rst
217
+++ b/docs/devel/index.rst
218
@@ -XXX,XX +XXX,XX @@ Contents:
219
reset
220
s390-dasd-ipl
221
clocks
222
+ block-coroutine-wrapper
223
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
224
new file mode 100644
225
index XXXXXXX..XXXXXXX
226
--- /dev/null
227
+++ b/scripts/block-coroutine-wrapper.py
228
@@ -XXX,XX +XXX,XX @@
229
+#! /usr/bin/env python3
230
+"""Generate coroutine wrappers for block subsystem.
231
+
232
+The program parses one or several concatenated c files from stdin,
233
+searches for functions with the 'generated_co_wrapper' specifier
234
+and generates corresponding wrappers on stdout.
235
+
236
+Usage: block-coroutine-wrapper.py generated-file.c FILE.[ch]...
237
+
238
+Copyright (c) 2020 Virtuozzo International GmbH.
239
+
240
+This program is free software; you can redistribute it and/or modify
241
+it under the terms of the GNU General Public License as published by
242
+the Free Software Foundation; either version 2 of the License, or
243
+(at your option) any later version.
244
+
245
+This program is distributed in the hope that it will be useful,
246
+but WITHOUT ANY WARRANTY; without even the implied warranty of
247
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
248
+GNU General Public License for more details.
249
+
250
+You should have received a copy of the GNU General Public License
251
+along with this program. If not, see <http://www.gnu.org/licenses/>.
252
+"""
253
+
254
+import sys
255
+import re
256
+import subprocess
257
+import json
258
+from typing import Iterator
259
+
260
+
261
+def prettify(code: str) -> str:
262
+ """Prettify code using clang-format if available"""
263
+
264
+ try:
265
+ style = json.dumps({
266
+ 'IndentWidth': 4,
267
+ 'BraceWrapping': {'AfterFunction': True},
268
+ 'BreakBeforeBraces': 'Custom',
269
+ 'SortIncludes': False,
270
+ 'MaxEmptyLinesToKeep': 2,
271
+ })
272
+ p = subprocess.run(['clang-format', f'-style={style}'], check=True,
273
+ encoding='utf-8', input=code,
274
+ stdout=subprocess.PIPE)
275
+ return p.stdout
276
+ except FileNotFoundError:
277
+ return code
278
+
279
+
280
+def gen_header():
281
+ copyright = re.sub('^.*Copyright', 'Copyright', __doc__, flags=re.DOTALL)
282
+ copyright = re.sub('^(?=.)', ' * ', copyright.strip(), flags=re.MULTILINE)
283
+ copyright = re.sub('^$', ' *', copyright, flags=re.MULTILINE)
284
+ return f"""\
285
+/*
286
+ * File is generated by scripts/block-coroutine-wrapper.py
287
+ *
288
+{copyright}
289
+ */
290
+
291
+#include "qemu/osdep.h"
292
+#include "block/coroutines.h"
293
+#include "block/block-gen.h"
294
+#include "block/block_int.h"\
295
+"""
296
+
297
+
298
+class ParamDecl:
299
+ param_re = re.compile(r'(?P<decl>'
300
+ r'(?P<type>.*[ *])'
301
+ r'(?P<name>[a-z][a-z0-9_]*)'
302
+ r')')
303
+
304
+ def __init__(self, param_decl: str) -> None:
305
+ m = self.param_re.match(param_decl.strip())
306
+ if m is None:
307
+ raise ValueError(f'Wrong parameter declaration: "{param_decl}"')
308
+ self.decl = m.group('decl')
309
+ self.type = m.group('type')
310
+ self.name = m.group('name')
311
+
312
+
313
+class FuncDecl:
314
+ def __init__(self, return_type: str, name: str, args: str) -> None:
315
+ self.return_type = return_type.strip()
316
+ self.name = name.strip()
317
+ self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
318
+
319
+ def gen_list(self, format: str) -> str:
320
+ return ', '.join(format.format_map(arg.__dict__) for arg in self.args)
321
+
322
+ def gen_block(self, format: str) -> str:
323
+ return '\n'.join(format.format_map(arg.__dict__) for arg in self.args)
324
+
325
+
326
+# Match wrappers declared with a generated_co_wrapper mark
327
+func_decl_re = re.compile(r'^int\s*generated_co_wrapper\s*'
328
+ r'(?P<wrapper_name>[a-z][a-z0-9_]*)'
329
+ r'\((?P<args>[^)]*)\);$', re.MULTILINE)
330
+
331
+
332
+def func_decl_iter(text: str) -> Iterator:
333
+ for m in func_decl_re.finditer(text):
334
+ yield FuncDecl(return_type='int',
335
+ name=m.group('wrapper_name'),
336
+ args=m.group('args'))
337
+
338
+
339
+def snake_to_camel(func_name: str) -> str:
340
+ """
341
+ Convert underscore names like 'some_function_name' to camel-case like
342
+ 'SomeFunctionName'
343
+ """
344
+ words = func_name.split('_')
345
+ words = [w[0].upper() + w[1:] for w in words]
346
+ return ''.join(words)
347
+
348
+
349
+def gen_wrapper(func: FuncDecl) -> str:
350
+ assert func.name.startswith('bdrv_')
351
+ assert not func.name.startswith('bdrv_co_')
352
+ assert func.return_type == 'int'
353
+ assert func.args[0].type in ['BlockDriverState *', 'BdrvChild *']
354
+
355
+ name = 'bdrv_co_' + func.name[5:]
356
+ bs = 'bs' if func.args[0].type == 'BlockDriverState *' else 'child->bs'
357
+ struct_name = snake_to_camel(name)
358
+
359
+ return f"""\
360
+/*
361
+ * Wrappers for {name}
362
+ */
363
+
364
+typedef struct {struct_name} {{
365
+ BdrvPollCo poll_state;
366
+{ func.gen_block(' {decl};') }
367
+}} {struct_name};
368
+
369
+static void coroutine_fn {name}_entry(void *opaque)
370
+{{
371
+ {struct_name} *s = opaque;
372
+
373
+ s->poll_state.ret = {name}({ func.gen_list('s->{name}') });
374
+ s->poll_state.in_progress = false;
375
+
376
+ aio_wait_kick();
377
+}}
378
+
379
+int {func.name}({ func.gen_list('{decl}') })
380
+{{
381
+ if (qemu_in_coroutine()) {{
382
+ return {name}({ func.gen_list('{name}') });
383
+ }} else {{
384
+ {struct_name} s = {{
385
+ .poll_state.bs = {bs},
386
+ .poll_state.in_progress = true,
387
+
388
+{ func.gen_block(' .{name} = {name},') }
389
+ }};
390
+
391
+ s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
392
+
393
+ return bdrv_poll_co(&s.poll_state);
394
+ }}
395
+}}"""
396
+
397
+
398
+def gen_wrappers(input_code: str) -> str:
399
+ res = ''
400
+ for func in func_decl_iter(input_code):
401
+ res += '\n\n\n'
402
+ res += gen_wrapper(func)
403
+
404
+ return prettify(res) # prettify to wrap long lines
405
+
406
+
407
+if __name__ == '__main__':
408
+ if len(sys.argv) < 3:
409
+ exit(f'Usage: {sys.argv[0]} OUT_FILE.c IN_FILE.[ch]...')
410
+
411
+ with open(sys.argv[1], 'w', encoding='utf-8') as f_out:
412
+ f_out.write(gen_header())
413
+ for fname in sys.argv[2:]:
414
+ with open(fname, encoding='utf-8') as f_in:
415
+ f_out.write(gen_wrappers(f_in.read()))
416
+ f_out.write('\n')
417
--
418
2.26.2
419
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Use code generation implemented in previous commit to generated
4
coroutine wrappers in block.c and block/io.c
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-Id: <20200924185414.28642-6-vsementsov@virtuozzo.com>
11
---
12
block/coroutines.h | 6 +-
13
include/block/block.h | 16 ++--
14
block.c | 73 ---------------
15
block/io.c | 212 ------------------------------------------
16
4 files changed, 13 insertions(+), 294 deletions(-)
17
18
diff --git a/block/coroutines.h b/block/coroutines.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/coroutines.h
21
+++ b/block/coroutines.h
22
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
23
int coroutine_fn
24
bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
25
bool is_write, BdrvRequestFlags flags);
26
-int
27
+int generated_co_wrapper
28
bdrv_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
29
bool is_write, BdrvRequestFlags flags);
30
31
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
32
int64_t *pnum,
33
int64_t *map,
34
BlockDriverState **file);
35
-int
36
+int generated_co_wrapper
37
bdrv_common_block_status_above(BlockDriverState *bs,
38
BlockDriverState *base,
39
bool want_zero,
40
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
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);
101
diff --git a/block.c b/block.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block.c
104
+++ b/block.c
105
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
106
return bs->drv->bdrv_co_check(bs, res, fix);
107
}
108
109
-typedef struct CheckCo {
110
- BlockDriverState *bs;
111
- BdrvCheckResult *res;
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
-}
475
--
476
2.26.2
477
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Now that we are not maintaining boilerplate code for coroutine
4
wrappers, there is no more sense in keeping the extra indirection layer
5
of bdrv_prwv(). Let's drop it and instead generate pure bdrv_preadv()
6
and bdrv_pwritev().
7
8
Currently, bdrv_pwritev() and bdrv_preadv() are returning bytes on
9
success, auto generated functions will instead return zero, as their
10
_co_ prototype. Still, it's simple to make the conversion safe: the
11
only external user of bdrv_pwritev() is test-bdrv-drain, and it is
12
comfortable enough with bdrv_co_pwritev() instead. So prototypes are
13
moved to local block/coroutines.h. Next, the only internal use is
14
bdrv_pread() and bdrv_pwrite(), which are modified to return bytes on
15
success.
16
17
Of course, it would be great to convert bdrv_pread() and bdrv_pwrite()
18
to return 0 on success. But this requires audit (and probably
19
conversion) of all their users, let's leave it for another day
20
refactoring.
21
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>
28
---
29
block/coroutines.h | 10 ++++-----
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(-)
34
35
diff --git a/block/coroutines.h b/block/coroutines.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/coroutines.h
38
+++ b/block/coroutines.h
39
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
40
BdrvCheckResult *res, BdrvCheckMode fix);
41
int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
42
43
-int coroutine_fn
44
-bdrv_co_prwv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov,
45
- bool is_write, BdrvRequestFlags flags);
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 */
177
--
178
2.26.2
179
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Like for read/write in a previous commit, drop extra indirection layer,
4
generate directly bdrv_readv_vmstate() and bdrv_writev_vmstate().
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-Id: <20200924185414.28642-8-vsementsov@virtuozzo.com>
11
---
12
block/coroutines.h | 10 +++----
13
include/block/block.h | 6 ++--
14
block/io.c | 70 ++++++++++++++++++++++---------------------
15
3 files changed, 44 insertions(+), 42 deletions(-)
16
17
diff --git a/block/coroutines.h b/block/coroutines.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/coroutines.h
20
+++ b/block/coroutines.h
21
@@ -XXX,XX +XXX,XX @@ bdrv_common_block_status_above(BlockDriverState *bs,
22
int64_t *map,
23
BlockDriverState **file);
24
25
-int coroutine_fn
26
-bdrv_co_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
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
/**************************************************************/
162
--
163
2.26.2
164
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
This is the only non-ascii character in the file and it doesn't really
4
needed here. Let's use normal "'" symbol for consistency with the rest
5
11 occurrences of "'" in the file.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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(-)
13
14
diff --git a/include/block/block.h b/include/block/block.h
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
29
diff view generated by jsdifflib
Deleted patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
1
3
When we added io_uring AIO engine, we forgot to update qemu-options.hx,
4
so qemu(1) man page and qemu help were outdated.
5
6
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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(-)
14
15
diff --git a/qemu-options.hx b/qemu-options.hx
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
52
diff view generated by jsdifflib
Deleted patch
1
From: Eric Auger <eric.auger@redhat.com>
2
1
3
The IOVA allocator currently ignores host reserved regions.
4
As a result some chosen IOVAs may collide with some of them,
5
resulting in VFIO MAP_DMA errors later on. This happens on ARM
6
where the MSI reserved window quickly is encountered:
7
[0x8000000, 0x8100000]. since 5.4 kernel, VFIO returns the usable
8
IOVA regions. So let's enumerate them in the prospect to avoid
9
them, later on.
10
11
Signed-off-by: Eric Auger <eric.auger@redhat.com>
12
Message-id: 20200929085550.30926-2-eric.auger@redhat.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
util/vfio-helpers.c | 72 +++++++++++++++++++++++++++++++++++++++++++--
16
1 file changed, 70 insertions(+), 2 deletions(-)
17
18
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/util/vfio-helpers.c
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
156
diff view generated by jsdifflib
Deleted patch
1
From: Eric Auger <eric.auger@redhat.com>
2
1
3
Introduce the qemu_vfio_find_fixed/temp_iova helpers which
4
respectively allocate IOVAs from the bottom/top parts of the
5
usable IOVA range, without picking within host IOVA reserved
6
windows. The allocation remains basic: if the size is too big
7
for the remaining of the current usable IOVA range, we jump
8
to the next one, leaving a hole in the address map.
9
10
Signed-off-by: Eric Auger <eric.auger@redhat.com>
11
Message-id: 20200929085550.30926-3-eric.auger@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
util/vfio-helpers.c | 57 +++++++++++++++++++++++++++++++++++++++++----
15
1 file changed, 53 insertions(+), 4 deletions(-)
16
17
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/util/vfio-helpers.c
20
+++ b/util/vfio-helpers.c
21
@@ -XXX,XX +XXX,XX @@ static bool qemu_vfio_verify_mappings(QEMUVFIOState *s)
22
return true;
23
}
24
25
+static int
26
+qemu_vfio_find_fixed_iova(QEMUVFIOState *s, size_t size, uint64_t *iova)
27
+{
28
+ int i;
29
+
30
+ for (i = 0; i < s->nb_iova_ranges; i++) {
31
+ if (s->usable_iova_ranges[i].end < s->low_water_mark) {
32
+ continue;
33
+ }
34
+ s->low_water_mark =
35
+ MAX(s->low_water_mark, s->usable_iova_ranges[i].start);
36
+
37
+ if (s->usable_iova_ranges[i].end - s->low_water_mark + 1 >= size ||
38
+ s->usable_iova_ranges[i].end - s->low_water_mark + 1 == 0) {
39
+ *iova = s->low_water_mark;
40
+ s->low_water_mark += size;
41
+ return 0;
42
+ }
43
+ }
44
+ return -ENOMEM;
45
+}
46
+
47
+static int
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) {
105
--
106
2.26.2
107
diff view generated by jsdifflib