1
The following changes since commit af352675efb7e92a1f5f6461a042a12015ab3d12:
1
The following changes since commit 7b1db0908d88f0c9cfac24e214ff72a860692e23:
2
2
3
Merge remote-tracking branch 'remotes/aurel/tags/pull-target-sh4-20171218' into staging (2017-12-19 19:11:11 +0000)
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180323' into staging (2018-03-25 13:51:33 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to b4d526c87b26aff6d8b353951aa175a1236ad887:
9
for you to fetch changes up to 0b7e7f66813a7e346e12d47be977a32a530a6316:
10
10
11
nvme: Add tracing (2017-12-20 11:05:49 +0100)
11
qemu-iotests: Test vhdx image creation with QMP (2018-03-26 12:17:43 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
----------------------------------------------------------------
16
----------------------------------------------------------------
17
Doug Gale (1):
17
Alberto Garcia (1):
18
nvme: Add tracing
18
qcow2: Reset free_cluster_index when allocating a new refcount block
19
19
20
Edgar Kaziakhmedov (1):
20
Eric Blake (1):
21
qcow2: get rid of qcow2_backing_read1 routine
21
iotests: 163 is not quick
22
22
23
Fam Zheng (1):
23
Fabiano Rosas (5):
24
qemu-img: Document --force-share / -U
24
block/replication: Remove protocol_name field
25
block/quorum: Remove protocol-related fields
26
block/throttle: Remove protocol-related fields
27
block/blkreplay: Remove protocol-related fields
28
include/block/block_int: Document protocol related functions
25
29
26
John Snow (1):
30
Kevin Wolf (12):
27
iotests: fix 197 for vpc
31
vdi: Change 'static' create option to 'preallocation' in QMP
32
vdi: Fix build with CONFIG_VDI_DEBUG
33
qemu-iotests: Test vdi image creation with QMP
34
qemu-iotests: Enable 025 for luks
35
luks: Turn another invalid assertion into check
36
qemu-iotests: Test invalid resize on luks
37
parallels: Check maximum cluster size on create
38
qemu-iotests: Test parallels image creation with QMP
39
vhdx: Require power-of-two block size on create
40
vhdx: Don't use error_setg_errno() with constant errno
41
vhdx: Check for 4 GB maximum log size on creation
42
qemu-iotests: Test vhdx image creation with QMP
28
43
29
Kevin Wolf (9):
44
qapi/block-core.json | 7 +-
30
block: Formats don't need CONSISTENT_READ with NO_IO
45
include/block/block_int.h | 8 ++
31
block: Make bdrv_drain_invoke() recursive
46
replication.h | 1 -
32
block: Call .drain_begin only once in bdrv_drain_all_begin()
47
block/blkreplay.c | 3 +-
33
test-bdrv-drain: Test BlockDriver callbacks for drain
48
block/crypto.c | 6 +-
34
block: bdrv_drain_recurse(): Remove unused begin parameter
49
block/parallels.c | 5 +
35
block: Don't wait for requests in bdrv_drain*_end()
50
block/qcow2-refcount.c | 7 +
36
block: Unify order in drain functions
51
block/quorum.c | 3 +-
37
block: Don't acquire AioContext in hmp_qemu_io()
52
block/replication.c | 1 -
38
block: Document that x-blockdev-change breaks quorum children list
53
block/throttle.c | 3 +-
54
block/vdi.c | 46 ++++--
55
block/vhdx.c | 17 ++-
56
tests/qemu-iotests/025 | 9 +-
57
tests/qemu-iotests/026.out | 6 +-
58
tests/qemu-iotests/121 | 20 +++
59
tests/qemu-iotests/121.out | 10 ++
60
tests/qemu-iotests/210 | 37 +++++
61
tests/qemu-iotests/210.out | 16 +++
62
tests/qemu-iotests/211 | 246 ++++++++++++++++++++++++++++++++
63
tests/qemu-iotests/211.out | 97 +++++++++++++
64
tests/qemu-iotests/212 | 326 ++++++++++++++++++++++++++++++++++++++++++
65
tests/qemu-iotests/212.out | 111 ++++++++++++++
66
tests/qemu-iotests/213 | 349 +++++++++++++++++++++++++++++++++++++++++++++
67
tests/qemu-iotests/213.out | 121 ++++++++++++++++
68
tests/qemu-iotests/group | 5 +-
69
25 files changed, 1423 insertions(+), 37 deletions(-)
70
create mode 100755 tests/qemu-iotests/211
71
create mode 100644 tests/qemu-iotests/211.out
72
create mode 100755 tests/qemu-iotests/212
73
create mode 100644 tests/qemu-iotests/212.out
74
create mode 100755 tests/qemu-iotests/213
75
create mode 100644 tests/qemu-iotests/213.out
39
76
40
Mao Zhongyi (1):
41
hw/block/nvme: Convert to realize
42
43
qapi/block-core.json | 4 +
44
block/qcow2.h | 3 -
45
block.c | 6 +-
46
block/io.c | 31 ++--
47
block/qcow2.c | 51 +-----
48
hmp.c | 6 -
49
hw/block/nvme.c | 367 ++++++++++++++++++++++++++++++++-------
50
tests/test-bdrv-drain.c | 137 +++++++++++++++
51
hw/block/trace-events | 93 ++++++++++
52
qemu-img.texi | 9 +
53
tests/Makefile.include | 2 +
54
tests/qemu-iotests/197 | 4 +
55
tests/qemu-iotests/common.filter | 3 +-
56
13 files changed, 591 insertions(+), 125 deletions(-)
57
create mode 100644 tests/test-bdrv-drain.c
58
diff view generated by jsdifflib
New patch
1
From: Eric Blake <eblake@redhat.com>
1
2
3
Testing on ext4, most 'quick' qcow2 tests took less than 5 seconds,
4
but 163 took more than 20. Let's remove it from the quick set.
5
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/group | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/group
15
+++ b/tests/qemu-iotests/group
16
@@ -XXX,XX +XXX,XX @@
17
159 rw auto quick
18
160 rw auto quick
19
162 auto quick
20
-163 rw auto quick
21
+163 rw auto
22
165 rw auto quick
23
169 rw auto quick
24
170 rw auto quick
25
--
26
2.13.6
27
28
diff view generated by jsdifflib
New patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
1
2
3
The protocol_name field is used when selecting a driver via protocol
4
syntax (i.e. <protocol_name>:<filename:options:...>). Drivers that are
5
only selected explicitly (e.g. driver=replication,mode=primary,...)
6
should not have a protocol_name.
7
8
This patch removes the protocol_name field from the brdv_replication
9
structure so that attempts to invoke this driver using protocol syntax
10
will fail gracefully:
11
12
$ qemu-img info replication:foo
13
qemu-img: Could not open 'replication:': Unknown protocol 'replication'
14
15
Buglink: https://bugs.launchpad.net/qemu/+bug/1726733
16
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
replication.h | 1 -
21
block/replication.c | 1 -
22
2 files changed, 2 deletions(-)
23
24
diff --git a/replication.h b/replication.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/replication.h
27
+++ b/replication.h
28
@@ -XXX,XX +XXX,XX @@ typedef struct ReplicationState ReplicationState;
29
*
30
* BlockDriver bdrv_replication = {
31
* .format_name = "replication",
32
- * .protocol_name = "replication",
33
* .instance_size = sizeof(BDRVReplicationState),
34
*
35
* .bdrv_open = replication_open,
36
diff --git a/block/replication.c b/block/replication.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/replication.c
39
+++ b/block/replication.c
40
@@ -XXX,XX +XXX,XX @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
41
42
BlockDriver bdrv_replication = {
43
.format_name = "replication",
44
- .protocol_name = "replication",
45
.instance_size = sizeof(BDRVReplicationState),
46
47
.bdrv_open = replication_open,
48
--
49
2.13.6
50
51
diff view generated by jsdifflib
New patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
1
2
3
The quorum driver is not a protocol so it should implement bdrv_open
4
instead of bdrv_file_open and not provide a protocol_name.
5
6
Attempts to invoke this driver using protocol syntax
7
(i.e. quorum:<filename:options:...>) will now fail gracefully:
8
9
$ qemu-img info quorum:foo
10
qemu-img: Could not open 'quorum:foo': Unknown protocol 'quorum'
11
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/quorum.c | 3 +--
18
1 file changed, 1 insertion(+), 2 deletions(-)
19
20
diff --git a/block/quorum.c b/block/quorum.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/quorum.c
23
+++ b/block/quorum.c
24
@@ -XXX,XX +XXX,XX @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
25
26
static BlockDriver bdrv_quorum = {
27
.format_name = "quorum",
28
- .protocol_name = "quorum",
29
30
.instance_size = sizeof(BDRVQuorumState),
31
32
- .bdrv_file_open = quorum_open,
33
+ .bdrv_open = quorum_open,
34
.bdrv_close = quorum_close,
35
.bdrv_refresh_filename = quorum_refresh_filename,
36
37
--
38
2.13.6
39
40
diff view generated by jsdifflib
New patch
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
1
2
3
The throttle driver is not a protocol so it should implement bdrv_open
4
instead of bdrv_file_open and not provide a protocol_name.
5
6
Attempts to invoke this driver using protocol syntax
7
(i.e. throttle:<filename:options:...>) will now fail gracefully:
8
9
$ qemu-img info throttle:foo
10
qemu-img: Could not open 'throttle:foo': Unknown protocol 'throttle'
11
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/throttle.c | 3 +--
18
1 file changed, 1 insertion(+), 2 deletions(-)
19
20
diff --git a/block/throttle.c b/block/throttle.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/throttle.c
23
+++ b/block/throttle.c
24
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
25
26
static BlockDriver bdrv_throttle = {
27
.format_name = "throttle",
28
- .protocol_name = "throttle",
29
.instance_size = sizeof(ThrottleGroupMember),
30
31
- .bdrv_file_open = throttle_open,
32
+ .bdrv_open = throttle_open,
33
.bdrv_close = throttle_close,
34
.bdrv_co_flush = throttle_co_flush,
35
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
1
bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2
callback inside its polling loop. This means that how many times it got
3
called for each node depended on long it had to poll the event loop.
4
2
5
This is obviously not right and results in nodes that stay drained even
3
The blkreplay driver is not a protocol so it should implement bdrv_open
6
after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per
4
instead of bdrv_file_open and not provide a protocol_name.
7
node.
8
5
9
Fix bdrv_drain_all_begin() to call the callback only once, too.
6
Attempts to invoke this driver using protocol syntax
7
(i.e. blkreplay:<filename:options:...>) will now fail gracefully:
10
8
11
Cc: qemu-stable@nongnu.org
9
$ qemu-img info blkreplay:foo
10
qemu-img: Could not open 'blkreplay:foo': Unknown protocol 'blkreplay'
11
12
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
13
Reviewed-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
16
---
15
block/io.c | 3 +--
17
block/blkreplay.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
18
1 file changed, 1 insertion(+), 2 deletions(-)
17
19
18
diff --git a/block/io.c b/block/io.c
20
diff --git a/block/blkreplay.c b/block/blkreplay.c
19
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100755
20
--- a/block/io.c
22
--- a/block/blkreplay.c
21
+++ b/block/io.c
23
+++ b/block/blkreplay.c
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
23
aio_context_acquire(aio_context);
25
24
bdrv_parent_drained_begin(bs);
26
static BlockDriver bdrv_blkreplay = {
25
aio_disable_external(aio_context);
27
.format_name = "blkreplay",
26
+ bdrv_drain_invoke(bs, true);
28
- .protocol_name = "blkreplay",
27
aio_context_release(aio_context);
29
.instance_size = 0,
28
30
29
if (!g_slist_find(aio_ctxs, aio_context)) {
31
- .bdrv_file_open = blkreplay_open,
30
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
32
+ .bdrv_open = blkreplay_open,
31
aio_context_acquire(aio_context);
33
.bdrv_close = blkreplay_close,
32
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
34
.bdrv_child_perm = bdrv_filter_default_perms,
33
if (aio_context == bdrv_get_aio_context(bs)) {
35
.bdrv_getlength = blkreplay_getlength,
34
- /* FIXME Calling this multiple times is wrong */
35
- bdrv_drain_invoke(bs, true);
36
waited |= bdrv_drain_recurse(bs, true);
37
}
38
}
39
--
36
--
40
2.13.6
37
2.13.6
41
38
42
39
diff view generated by jsdifflib
1
From: Doug Gale <doug16k@gmail.com>
1
From: Fabiano Rosas <farosas@linux.vnet.ibm.com>
2
2
3
Add trace output for commands, errors, and undefined behavior.
3
Clarify that:
4
Add guest error log output for undefined behavior.
5
Report invalid undefined accesses to MMIO.
6
Annotate unlikely error checks with unlikely.
7
4
8
Signed-off-by: Doug Gale <doug16k@gmail.com>
5
- for protocols the brdv_file_open function is used instead
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
of bdrv_open;
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
8
- when protocol_name is set, a driver should expect
9
to be given only a filename and no other options.
10
11
Signed-off-by: Fabiano Rosas <farosas@linux.vnet.ibm.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
---
13
hw/block/nvme.c | 349 ++++++++++++++++++++++++++++++++++++++++++--------
14
include/block/block_int.h | 8 ++++++++
14
hw/block/trace-events | 93 ++++++++++++++
15
1 file changed, 8 insertions(+)
15
2 files changed, 390 insertions(+), 52 deletions(-)
16
16
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
17
diff --git a/include/block/block_int.h b/include/block/block_int.h
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/nvme.c
19
--- a/include/block/block_int.h
20
+++ b/hw/block/nvme.c
20
+++ b/include/block/block_int.h
21
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
22
#include "qapi/visitor.h"
22
23
#include "sysemu/block-backend.h"
23
int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags,
24
24
Error **errp);
25
+#include "qemu/log.h"
26
+#include "trace.h"
27
#include "nvme.h"
28
29
+#define NVME_GUEST_ERR(trace, fmt, ...) \
30
+ do { \
31
+ (trace_##trace)(__VA_ARGS__); \
32
+ qemu_log_mask(LOG_GUEST_ERROR, #trace \
33
+ " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
34
+ } while (0)
35
+
25
+
36
static void nvme_process_sq(void *opaque);
26
+ /* Protocol drivers should implement this instead of bdrv_open */
37
27
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
38
static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
28
Error **errp);
39
@@ -XXX,XX +XXX,XX @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
29
void (*bdrv_close)(BlockDriverState *bs);
40
{
30
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
41
if (cq->irq_enabled) {
31
*/
42
if (msix_enabled(&(n->parent_obj))) {
32
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
43
+ trace_nvme_irq_msix(cq->vector);
33
44
msix_notify(&(n->parent_obj), cq->vector);
34
+ /*
45
} else {
35
+ * Drivers setting this field must be able to work with just a plain
46
+ trace_nvme_irq_pin();
36
+ * filename with '<protocol_name>:' as a prefix, and no other options.
47
pci_irq_pulse(&n->parent_obj);
37
+ * Options may be extracted from the filename by implementing
48
}
38
+ * bdrv_parse_filename.
49
+ } else {
39
+ */
50
+ trace_nvme_irq_masked();
40
const char *protocol_name;
51
}
41
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
52
}
42
PreallocMode prealloc, Error **errp);
53
54
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
55
trans_len = MIN(len, trans_len);
56
int num_prps = (len >> n->page_bits) + 1;
57
58
- if (!prp1) {
59
+ if (unlikely(!prp1)) {
60
+ trace_nvme_err_invalid_prp();
61
return NVME_INVALID_FIELD | NVME_DNR;
62
} else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
63
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
64
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
65
}
66
len -= trans_len;
67
if (len) {
68
- if (!prp2) {
69
+ if (unlikely(!prp2)) {
70
+ trace_nvme_err_invalid_prp2_missing();
71
goto unmap;
72
}
73
if (len > n->page_size) {
74
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
75
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
76
77
if (i == n->max_prp_ents - 1 && len > n->page_size) {
78
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
79
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
80
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
81
goto unmap;
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
85
prp_ent = le64_to_cpu(prp_list[i]);
86
}
87
88
- if (!prp_ent || prp_ent & (n->page_size - 1)) {
89
+ if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
90
+ trace_nvme_err_invalid_prplist_ent(prp_ent);
91
goto unmap;
92
}
93
94
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
95
i++;
96
}
97
} else {
98
- if (prp2 & (n->page_size - 1)) {
99
+ if (unlikely(prp2 & (n->page_size - 1))) {
100
+ trace_nvme_err_invalid_prp2_align(prp2);
101
goto unmap;
102
}
103
if (qsg->nsg) {
104
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
105
QEMUIOVector iov;
106
uint16_t status = NVME_SUCCESS;
107
108
+ trace_nvme_dma_read(prp1, prp2);
109
+
110
if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
111
return NVME_INVALID_FIELD | NVME_DNR;
112
}
113
if (qsg.nsg > 0) {
114
- if (dma_buf_read(ptr, len, &qsg)) {
115
+ if (unlikely(dma_buf_read(ptr, len, &qsg))) {
116
+ trace_nvme_err_invalid_dma();
117
status = NVME_INVALID_FIELD | NVME_DNR;
118
}
119
qemu_sglist_destroy(&qsg);
120
} else {
121
- if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
122
+ if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
123
+ trace_nvme_err_invalid_dma();
124
status = NVME_INVALID_FIELD | NVME_DNR;
125
}
126
qemu_iovec_destroy(&iov);
127
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
128
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
129
uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
130
131
- if (slba + nlb > ns->id_ns.nsze) {
132
+ if (unlikely(slba + nlb > ns->id_ns.nsze)) {
133
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
134
return NVME_LBA_RANGE | NVME_DNR;
135
}
136
137
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
138
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
139
enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
140
141
- if ((slba + nlb) > ns->id_ns.nsze) {
142
+ trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
143
+
144
+ if (unlikely((slba + nlb) > ns->id_ns.nsze)) {
145
block_acct_invalid(blk_get_stats(n->conf.blk), acct);
146
+ trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
147
return NVME_LBA_RANGE | NVME_DNR;
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
151
NvmeNamespace *ns;
152
uint32_t nsid = le32_to_cpu(cmd->nsid);
153
154
- if (nsid == 0 || nsid > n->num_namespaces) {
155
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
156
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
157
return NVME_INVALID_NSID | NVME_DNR;
158
}
159
160
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
161
case NVME_CMD_READ:
162
return nvme_rw(n, ns, cmd, req);
163
default:
164
+ trace_nvme_err_invalid_opc(cmd->opcode);
165
return NVME_INVALID_OPCODE | NVME_DNR;
166
}
167
}
168
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
169
NvmeCQueue *cq;
170
uint16_t qid = le16_to_cpu(c->qid);
171
172
- if (!qid || nvme_check_sqid(n, qid)) {
173
+ if (unlikely(!qid || nvme_check_sqid(n, qid))) {
174
+ trace_nvme_err_invalid_del_sq(qid);
175
return NVME_INVALID_QID | NVME_DNR;
176
}
177
178
+ trace_nvme_del_sq(qid);
179
+
180
sq = n->sq[qid];
181
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
182
req = QTAILQ_FIRST(&sq->out_req_list);
183
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
184
uint16_t qflags = le16_to_cpu(c->sq_flags);
185
uint64_t prp1 = le64_to_cpu(c->prp1);
186
187
- if (!cqid || nvme_check_cqid(n, cqid)) {
188
+ trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags);
189
+
190
+ if (unlikely(!cqid || nvme_check_cqid(n, cqid))) {
191
+ trace_nvme_err_invalid_create_sq_cqid(cqid);
192
return NVME_INVALID_CQID | NVME_DNR;
193
}
194
- if (!sqid || !nvme_check_sqid(n, sqid)) {
195
+ if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) {
196
+ trace_nvme_err_invalid_create_sq_sqid(sqid);
197
return NVME_INVALID_QID | NVME_DNR;
198
}
199
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
200
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
201
+ trace_nvme_err_invalid_create_sq_size(qsize);
202
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
203
}
204
- if (!prp1 || prp1 & (n->page_size - 1)) {
205
+ if (unlikely(!prp1 || prp1 & (n->page_size - 1))) {
206
+ trace_nvme_err_invalid_create_sq_addr(prp1);
207
return NVME_INVALID_FIELD | NVME_DNR;
208
}
209
- if (!(NVME_SQ_FLAGS_PC(qflags))) {
210
+ if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) {
211
+ trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags));
212
return NVME_INVALID_FIELD | NVME_DNR;
213
}
214
sq = g_malloc0(sizeof(*sq));
215
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd)
216
NvmeCQueue *cq;
217
uint16_t qid = le16_to_cpu(c->qid);
218
219
- if (!qid || nvme_check_cqid(n, qid)) {
220
+ if (unlikely(!qid || nvme_check_cqid(n, qid))) {
221
+ trace_nvme_err_invalid_del_cq_cqid(qid);
222
return NVME_INVALID_CQID | NVME_DNR;
223
}
224
225
cq = n->cq[qid];
226
- if (!QTAILQ_EMPTY(&cq->sq_list)) {
227
+ if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) {
228
+ trace_nvme_err_invalid_del_cq_notempty(qid);
229
return NVME_INVALID_QUEUE_DEL;
230
}
231
+ trace_nvme_del_cq(qid);
232
nvme_free_cq(cq, n);
233
return NVME_SUCCESS;
234
}
235
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
236
uint16_t qflags = le16_to_cpu(c->cq_flags);
237
uint64_t prp1 = le64_to_cpu(c->prp1);
238
239
- if (!cqid || !nvme_check_cqid(n, cqid)) {
240
+ trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags,
241
+ NVME_CQ_FLAGS_IEN(qflags) != 0);
242
+
243
+ if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) {
244
+ trace_nvme_err_invalid_create_cq_cqid(cqid);
245
return NVME_INVALID_CQID | NVME_DNR;
246
}
247
- if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) {
248
+ if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) {
249
+ trace_nvme_err_invalid_create_cq_size(qsize);
250
return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR;
251
}
252
- if (!prp1) {
253
+ if (unlikely(!prp1)) {
254
+ trace_nvme_err_invalid_create_cq_addr(prp1);
255
return NVME_INVALID_FIELD | NVME_DNR;
256
}
257
- if (vector > n->num_queues) {
258
+ if (unlikely(vector > n->num_queues)) {
259
+ trace_nvme_err_invalid_create_cq_vector(vector);
260
return NVME_INVALID_IRQ_VECTOR | NVME_DNR;
261
}
262
- if (!(NVME_CQ_FLAGS_PC(qflags))) {
263
+ if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) {
264
+ trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags));
265
return NVME_INVALID_FIELD | NVME_DNR;
266
}
267
268
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c)
269
uint64_t prp1 = le64_to_cpu(c->prp1);
270
uint64_t prp2 = le64_to_cpu(c->prp2);
271
272
+ trace_nvme_identify_ctrl();
273
+
274
return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl),
275
prp1, prp2);
276
}
277
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c)
278
uint64_t prp1 = le64_to_cpu(c->prp1);
279
uint64_t prp2 = le64_to_cpu(c->prp2);
280
281
- if (nsid == 0 || nsid > n->num_namespaces) {
282
+ trace_nvme_identify_ns(nsid);
283
+
284
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
285
+ trace_nvme_err_invalid_ns(nsid, n->num_namespaces);
286
return NVME_INVALID_NSID | NVME_DNR;
287
}
288
289
ns = &n->namespaces[nsid - 1];
290
+
291
return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns),
292
prp1, prp2);
293
}
294
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
295
uint16_t ret;
296
int i, j = 0;
297
298
+ trace_nvme_identify_nslist(min_nsid);
299
+
300
list = g_malloc0(data_len);
301
for (i = 0; i < n->num_namespaces; i++) {
302
if (i < min_nsid) {
303
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
304
case 0x02:
305
return nvme_identify_nslist(n, c);
306
default:
307
+ trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
308
return NVME_INVALID_FIELD | NVME_DNR;
309
}
310
}
311
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
312
switch (dw10) {
313
case NVME_VOLATILE_WRITE_CACHE:
314
result = blk_enable_write_cache(n->conf.blk);
315
+ trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
316
break;
317
case NVME_NUMBER_OF_QUEUES:
318
result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
319
+ trace_nvme_getfeat_numq(result);
320
break;
321
default:
322
+ trace_nvme_err_invalid_getfeat(dw10);
323
return NVME_INVALID_FIELD | NVME_DNR;
324
}
325
326
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
327
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
328
break;
329
case NVME_NUMBER_OF_QUEUES:
330
+ trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
331
+ ((dw11 >> 16) & 0xFFFF) + 1,
332
+ n->num_queues - 1, n->num_queues - 1);
333
req->cqe.result =
334
cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
335
break;
336
default:
337
+ trace_nvme_err_invalid_setfeat(dw10);
338
return NVME_INVALID_FIELD | NVME_DNR;
339
}
340
return NVME_SUCCESS;
341
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
342
case NVME_ADM_CMD_GET_FEATURES:
343
return nvme_get_feature(n, cmd, req);
344
default:
345
+ trace_nvme_err_invalid_admin_opc(cmd->opcode);
346
return NVME_INVALID_OPCODE | NVME_DNR;
347
}
348
}
349
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
350
uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
351
uint32_t page_size = 1 << page_bits;
352
353
- if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq ||
354
- n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) ||
355
- NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) ||
356
- NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) ||
357
- NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) ||
358
- NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) ||
359
- NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) ||
360
- NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) ||
361
- !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) {
362
+ if (unlikely(n->cq[0])) {
363
+ trace_nvme_err_startfail_cq();
364
+ return -1;
365
+ }
366
+ if (unlikely(n->sq[0])) {
367
+ trace_nvme_err_startfail_sq();
368
+ return -1;
369
+ }
370
+ if (unlikely(!n->bar.asq)) {
371
+ trace_nvme_err_startfail_nbarasq();
372
+ return -1;
373
+ }
374
+ if (unlikely(!n->bar.acq)) {
375
+ trace_nvme_err_startfail_nbaracq();
376
+ return -1;
377
+ }
378
+ if (unlikely(n->bar.asq & (page_size - 1))) {
379
+ trace_nvme_err_startfail_asq_misaligned(n->bar.asq);
380
+ return -1;
381
+ }
382
+ if (unlikely(n->bar.acq & (page_size - 1))) {
383
+ trace_nvme_err_startfail_acq_misaligned(n->bar.acq);
384
+ return -1;
385
+ }
386
+ if (unlikely(NVME_CC_MPS(n->bar.cc) <
387
+ NVME_CAP_MPSMIN(n->bar.cap))) {
388
+ trace_nvme_err_startfail_page_too_small(
389
+ NVME_CC_MPS(n->bar.cc),
390
+ NVME_CAP_MPSMIN(n->bar.cap));
391
+ return -1;
392
+ }
393
+ if (unlikely(NVME_CC_MPS(n->bar.cc) >
394
+ NVME_CAP_MPSMAX(n->bar.cap))) {
395
+ trace_nvme_err_startfail_page_too_large(
396
+ NVME_CC_MPS(n->bar.cc),
397
+ NVME_CAP_MPSMAX(n->bar.cap));
398
+ return -1;
399
+ }
400
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) <
401
+ NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) {
402
+ trace_nvme_err_startfail_cqent_too_small(
403
+ NVME_CC_IOCQES(n->bar.cc),
404
+ NVME_CTRL_CQES_MIN(n->bar.cap));
405
+ return -1;
406
+ }
407
+ if (unlikely(NVME_CC_IOCQES(n->bar.cc) >
408
+ NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) {
409
+ trace_nvme_err_startfail_cqent_too_large(
410
+ NVME_CC_IOCQES(n->bar.cc),
411
+ NVME_CTRL_CQES_MAX(n->bar.cap));
412
+ return -1;
413
+ }
414
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) <
415
+ NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) {
416
+ trace_nvme_err_startfail_sqent_too_small(
417
+ NVME_CC_IOSQES(n->bar.cc),
418
+ NVME_CTRL_SQES_MIN(n->bar.cap));
419
+ return -1;
420
+ }
421
+ if (unlikely(NVME_CC_IOSQES(n->bar.cc) >
422
+ NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) {
423
+ trace_nvme_err_startfail_sqent_too_large(
424
+ NVME_CC_IOSQES(n->bar.cc),
425
+ NVME_CTRL_SQES_MAX(n->bar.cap));
426
+ return -1;
427
+ }
428
+ if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) {
429
+ trace_nvme_err_startfail_asqent_sz_zero();
430
+ return -1;
431
+ }
432
+ if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) {
433
+ trace_nvme_err_startfail_acqent_sz_zero();
434
return -1;
435
}
436
437
@@ -XXX,XX +XXX,XX @@ static int nvme_start_ctrl(NvmeCtrl *n)
438
static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
439
unsigned size)
440
{
441
+ if (unlikely(offset & (sizeof(uint32_t) - 1))) {
442
+ NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32,
443
+ "MMIO write not 32-bit aligned,"
444
+ " offset=0x%"PRIx64"", offset);
445
+ /* should be ignored, fall through for now */
446
+ }
447
+
448
+ if (unlikely(size < sizeof(uint32_t))) {
449
+ NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall,
450
+ "MMIO write smaller than 32-bits,"
451
+ " offset=0x%"PRIx64", size=%u",
452
+ offset, size);
453
+ /* should be ignored, fall through for now */
454
+ }
455
+
456
switch (offset) {
457
- case 0xc:
458
+ case 0xc: /* INTMS */
459
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
460
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
461
+ "undefined access to interrupt mask set"
462
+ " when MSI-X is enabled");
463
+ /* should be ignored, fall through for now */
464
+ }
465
n->bar.intms |= data & 0xffffffff;
466
n->bar.intmc = n->bar.intms;
467
+ trace_nvme_mmio_intm_set(data & 0xffffffff,
468
+ n->bar.intmc);
469
break;
470
- case 0x10:
471
+ case 0x10: /* INTMC */
472
+ if (unlikely(msix_enabled(&(n->parent_obj)))) {
473
+ NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix,
474
+ "undefined access to interrupt mask clr"
475
+ " when MSI-X is enabled");
476
+ /* should be ignored, fall through for now */
477
+ }
478
n->bar.intms &= ~(data & 0xffffffff);
479
n->bar.intmc = n->bar.intms;
480
+ trace_nvme_mmio_intm_clr(data & 0xffffffff,
481
+ n->bar.intmc);
482
break;
483
- case 0x14:
484
+ case 0x14: /* CC */
485
+ trace_nvme_mmio_cfg(data & 0xffffffff);
486
/* Windows first sends data, then sends enable bit */
487
if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) &&
488
!NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc))
489
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
490
491
if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) {
492
n->bar.cc = data;
493
- if (nvme_start_ctrl(n)) {
494
+ if (unlikely(nvme_start_ctrl(n))) {
495
+ trace_nvme_err_startfail();
496
n->bar.csts = NVME_CSTS_FAILED;
497
} else {
498
+ trace_nvme_mmio_start_success();
499
n->bar.csts = NVME_CSTS_READY;
500
}
501
} else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) {
502
+ trace_nvme_mmio_stopped();
503
nvme_clear_ctrl(n);
504
n->bar.csts &= ~NVME_CSTS_READY;
505
}
506
if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) {
507
- nvme_clear_ctrl(n);
508
- n->bar.cc = data;
509
- n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
510
+ trace_nvme_mmio_shutdown_set();
511
+ nvme_clear_ctrl(n);
512
+ n->bar.cc = data;
513
+ n->bar.csts |= NVME_CSTS_SHST_COMPLETE;
514
} else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) {
515
- n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
516
- n->bar.cc = data;
517
+ trace_nvme_mmio_shutdown_cleared();
518
+ n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE;
519
+ n->bar.cc = data;
520
+ }
521
+ break;
522
+ case 0x1C: /* CSTS */
523
+ if (data & (1 << 4)) {
524
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported,
525
+ "attempted to W1C CSTS.NSSRO"
526
+ " but CAP.NSSRS is zero (not supported)");
527
+ } else if (data != 0) {
528
+ NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts,
529
+ "attempted to set a read only bit"
530
+ " of controller status");
531
+ }
532
+ break;
533
+ case 0x20: /* NSSR */
534
+ if (data == 0x4E564D65) {
535
+ trace_nvme_ub_mmiowr_ssreset_unsupported();
536
+ } else {
537
+ /* The spec says that writes of other values have no effect */
538
+ return;
539
}
540
break;
541
- case 0x24:
542
+ case 0x24: /* AQA */
543
n->bar.aqa = data & 0xffffffff;
544
+ trace_nvme_mmio_aqattr(data & 0xffffffff);
545
break;
546
- case 0x28:
547
+ case 0x28: /* ASQ */
548
n->bar.asq = data;
549
+ trace_nvme_mmio_asqaddr(data);
550
break;
551
- case 0x2c:
552
+ case 0x2c: /* ASQ hi */
553
n->bar.asq |= data << 32;
554
+ trace_nvme_mmio_asqaddr_hi(data, n->bar.asq);
555
break;
556
- case 0x30:
557
+ case 0x30: /* ACQ */
558
+ trace_nvme_mmio_acqaddr(data);
559
n->bar.acq = data;
560
break;
561
- case 0x34:
562
+ case 0x34: /* ACQ hi */
563
n->bar.acq |= data << 32;
564
+ trace_nvme_mmio_acqaddr_hi(data, n->bar.acq);
565
break;
566
+ case 0x38: /* CMBLOC */
567
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved,
568
+ "invalid write to reserved CMBLOC"
569
+ " when CMBSZ is zero, ignored");
570
+ return;
571
+ case 0x3C: /* CMBSZ */
572
+ NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
573
+ "invalid write to read only CMBSZ, ignored");
574
+ return;
575
default:
576
+ NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
577
+ "invalid MMIO write,"
578
+ " offset=0x%"PRIx64", data=%"PRIx64"",
579
+ offset, data);
580
break;
581
}
582
}
583
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
584
uint8_t *ptr = (uint8_t *)&n->bar;
585
uint64_t val = 0;
586
587
+ if (unlikely(addr & (sizeof(uint32_t) - 1))) {
588
+ NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32,
589
+ "MMIO read not 32-bit aligned,"
590
+ " offset=0x%"PRIx64"", addr);
591
+ /* should RAZ, fall through for now */
592
+ } else if (unlikely(size < sizeof(uint32_t))) {
593
+ NVME_GUEST_ERR(nvme_ub_mmiord_toosmall,
594
+ "MMIO read smaller than 32-bits,"
595
+ " offset=0x%"PRIx64"", addr);
596
+ /* should RAZ, fall through for now */
597
+ }
598
+
599
if (addr < sizeof(n->bar)) {
600
memcpy(&val, ptr + addr, size);
601
+ } else {
602
+ NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
603
+ "MMIO read beyond last register,"
604
+ " offset=0x%"PRIx64", returning 0", addr);
605
}
606
+
607
return val;
608
}
609
610
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
611
{
612
uint32_t qid;
613
614
- if (addr & ((1 << 2) - 1)) {
615
+ if (unlikely(addr & ((1 << 2) - 1))) {
616
+ NVME_GUEST_ERR(nvme_ub_db_wr_misaligned,
617
+ "doorbell write not 32-bit aligned,"
618
+ " offset=0x%"PRIx64", ignoring", addr);
619
return;
620
}
621
622
if (((addr - 0x1000) >> 2) & 1) {
623
+ /* Completion queue doorbell write */
624
+
625
uint16_t new_head = val & 0xffff;
626
int start_sqs;
627
NvmeCQueue *cq;
628
629
qid = (addr - (0x1000 + (1 << 2))) >> 3;
630
- if (nvme_check_cqid(n, qid)) {
631
+ if (unlikely(nvme_check_cqid(n, qid))) {
632
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq,
633
+ "completion queue doorbell write"
634
+ " for nonexistent queue,"
635
+ " sqid=%"PRIu32", ignoring", qid);
636
return;
637
}
638
639
cq = n->cq[qid];
640
- if (new_head >= cq->size) {
641
+ if (unlikely(new_head >= cq->size)) {
642
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead,
643
+ "completion queue doorbell write value"
644
+ " beyond queue size, sqid=%"PRIu32","
645
+ " new_head=%"PRIu16", ignoring",
646
+ qid, new_head);
647
return;
648
}
649
650
@@ -XXX,XX +XXX,XX @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
651
nvme_isr_notify(n, cq);
652
}
653
} else {
654
+ /* Submission queue doorbell write */
655
+
656
uint16_t new_tail = val & 0xffff;
657
NvmeSQueue *sq;
658
659
qid = (addr - 0x1000) >> 3;
660
- if (nvme_check_sqid(n, qid)) {
661
+ if (unlikely(nvme_check_sqid(n, qid))) {
662
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq,
663
+ "submission queue doorbell write"
664
+ " for nonexistent queue,"
665
+ " sqid=%"PRIu32", ignoring", qid);
666
return;
667
}
668
669
sq = n->sq[qid];
670
- if (new_tail >= sq->size) {
671
+ if (unlikely(new_tail >= sq->size)) {
672
+ NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail,
673
+ "submission queue doorbell write value"
674
+ " beyond queue size, sqid=%"PRIu32","
675
+ " new_tail=%"PRIu16", ignoring",
676
+ qid, new_tail);
677
return;
678
}
679
680
diff --git a/hw/block/trace-events b/hw/block/trace-events
681
index XXXXXXX..XXXXXXX 100644
682
--- a/hw/block/trace-events
683
+++ b/hw/block/trace-events
684
@@ -XXX,XX +XXX,XX @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
685
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
686
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
687
688
+# hw/block/nvme.c
689
+# nvme traces for successful events
690
+nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
691
+nvme_irq_pin(void) "pulsing IRQ pin"
692
+nvme_irq_masked(void) "IRQ is masked"
693
+nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
694
+nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
695
+nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
696
+nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
697
+nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
698
+nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16""
699
+nvme_identify_ctrl(void) "identify controller"
700
+nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
701
+nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
702
+nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s"
703
+nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
704
+nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
705
+nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
706
+nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
707
+nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
708
+nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
709
+nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
710
+nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
711
+nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
712
+nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
713
+nvme_mmio_start_success(void) "setting controller enable bit succeeded"
714
+nvme_mmio_stopped(void) "cleared controller enable bit"
715
+nvme_mmio_shutdown_set(void) "shutdown bit set"
716
+nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
717
+
718
+# nvme traces for error conditions
719
+nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
720
+nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
721
+nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
722
+nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
723
+nvme_err_invalid_field(void) "invalid field"
724
+nvme_err_invalid_prp(void) "invalid PRP"
725
+nvme_err_invalid_sgl(void) "invalid SGL"
726
+nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
727
+nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
728
+nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
729
+nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
730
+nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
731
+nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
732
+nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
733
+nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
734
+nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
735
+nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
736
+nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
737
+nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
738
+nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
739
+nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
740
+nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
741
+nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
742
+nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
743
+nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
744
+nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
745
+nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
746
+nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
747
+nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
748
+nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
749
+nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
750
+nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
751
+nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
752
+nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
753
+nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
754
+nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
755
+nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
756
+nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
757
+nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
758
+nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
759
+nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
760
+nvme_err_startfail(void) "setting controller enable bit failed"
761
+
762
+# Traces for undefined behavior
763
+nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
764
+nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
765
+nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
766
+nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
767
+nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
768
+nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
769
+nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
770
+nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
771
+nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
772
+nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
773
+nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
774
+nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
775
+nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
776
+nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
777
+nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
778
+nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
779
+nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
780
+
781
# hw/block/xen_disk.c
782
xen_disk_alloc(char *name) "%s"
783
xen_disk_init(char *name) "%s"
784
--
43
--
785
2.13.6
44
2.13.6
786
45
787
46
diff view generated by jsdifflib
1
From: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Since bdrv_co_preadv does all neccessary checks including
3
When we try to allocate new clusters we first look for available ones
4
reading after the end of the backing file, avoid duplication
4
starting from s->free_cluster_index and once we find them we increase
5
of verification before bdrv_co_preadv call.
5
their reference counts. Before we get to call update_refcount() to do
6
this last step s->free_cluster_index is already pointing to the next
7
cluster after the ones we are trying to allocate.
6
8
7
Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
9
During update_refcount() it may happen however that we also need to
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
allocate a new refcount block in order to store the refcounts of these
11
new clusters (and to complicate things further that may also require
12
us to grow the refcount table). After all this we don't know if the
13
clusters that we originally tried to allocate are still available, so
14
we return -EAGAIN to ask the caller to restart the search for free
15
clusters.
16
17
This is what can happen in a common scenario:
18
19
1) We want to allocate a new cluster and we see that cluster N is
20
free.
21
22
2) We try to increase N's refcount but all refcount blocks are full,
23
so we allocate a new one at N+1 (where s->free_cluster_index was
24
pointing at).
25
26
3) Once we're done we return -EAGAIN to look again for a free
27
cluster, but now s->free_cluster_index points at N+2, so that's
28
the one we allocate. Cluster N remains unallocated and we have a
29
hole in the qcow2 file.
30
31
This can be reproduced easily:
32
33
qemu-img create -f qcow2 -o cluster_size=512 hd.qcow2 1M
34
qemu-io -c 'write 0 124k' hd.qcow2
35
36
After this the image has 132608 bytes (256 clusters), and the refcount
37
block is full. If we write 512 more bytes it should allocate two new
38
clusters: the data cluster itself and a new refcount block.
39
40
qemu-io -c 'write 124k 512' hd.qcow2
41
42
However the image has now three new clusters (259 in total), and the
43
first one of them is empty (and unallocated):
44
45
dd if=hd.qcow2 bs=512c skip=256 count=1 | hexdump -C
46
47
If we write larger amounts of data in the last step instead of the 512
48
bytes used in this example we can create larger holes in the qcow2
49
file.
50
51
What this patch does is reset s->free_cluster_index to its previous
52
value when alloc_refcount_block() returns -EAGAIN. This way the caller
53
will try to allocate again the original clusters if they are still
54
free.
55
56
The output of iotest 026 also needs to be updated because now that
57
images have no holes some tests fail at a different point and the
58
number of leaked clusters is different.
59
60
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
61
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
62
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
63
---
12
block/qcow2.h | 3 ---
64
block/qcow2-refcount.c | 7 +++++++
13
block/qcow2.c | 51 ++++++++-------------------------------------------
65
tests/qemu-iotests/026.out | 6 +++---
14
2 files changed, 8 insertions(+), 46 deletions(-)
66
tests/qemu-iotests/121 | 20 ++++++++++++++++++++
67
tests/qemu-iotests/121.out | 10 ++++++++++
68
4 files changed, 40 insertions(+), 3 deletions(-)
15
69
16
diff --git a/block/qcow2.h b/block/qcow2.h
70
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
17
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
72
--- a/block/qcow2-refcount.c
19
+++ b/block/qcow2.h
73
+++ b/block/qcow2-refcount.c
20
@@ -XXX,XX +XXX,XX @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
74
@@ -XXX,XX +XXX,XX @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
21
}
75
qcow2_cache_put(s->refcount_block_cache, &refcount_block);
22
76
}
23
/* qcow2.c functions */
77
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
24
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
78
+ /* If the caller needs to restart the search for free clusters,
25
- int64_t sector_num, int nb_sectors);
79
+ * try the same ones first to see if they're still free. */
26
-
80
+ if (ret == -EAGAIN) {
27
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
81
+ if (s->free_cluster_index > (start >> s->cluster_bits)) {
28
int refcount_order, bool generous_increase,
82
+ s->free_cluster_index = (start >> s->cluster_bits);
29
uint64_t *refblock_count);
83
+ }
30
diff --git a/block/qcow2.c b/block/qcow2.c
84
+ }
85
if (ret < 0) {
86
goto fail;
87
}
88
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
31
index XXXXXXX..XXXXXXX 100644
89
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2.c
90
--- a/tests/qemu-iotests/026.out
33
+++ b/block/qcow2.c
91
+++ b/tests/qemu-iotests/026.out
34
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
92
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
35
return status;
93
Failed to flush the refcount block cache: No space left on device
36
}
94
write failed: No space left on device
37
95
38
-/* handle reading after the end of the backing file */
96
-11 leaked clusters were found on the image.
39
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
97
+10 leaked clusters were found on the image.
40
- int64_t offset, int bytes)
98
This means waste of disk space, but no harm to data.
41
-{
99
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
42
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
100
43
- int n1;
101
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
44
-
102
Failed to flush the refcount block cache: No space left on device
45
- if ((offset + bytes) <= bs_size) {
103
write failed: No space left on device
46
- return bytes;
104
47
- }
105
-11 leaked clusters were found on the image.
48
-
106
+10 leaked clusters were found on the image.
49
- if (offset >= bs_size) {
107
This means waste of disk space, but no harm to data.
50
- n1 = 0;
108
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
51
- } else {
109
52
- n1 = bs_size - offset;
110
@@ -XXX,XX +XXX,XX @@ Failed to flush the L2 table cache: No space left on device
53
- }
111
Failed to flush the refcount block cache: No space left on device
54
-
112
write failed: No space left on device
55
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
113
56
-
114
-11 leaked clusters were found on the image.
57
- return n1;
115
+10 leaked clusters were found on the image.
58
-}
116
This means waste of disk space, but no harm to data.
59
-
117
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
60
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
118
61
uint64_t bytes, QEMUIOVector *qiov,
119
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
62
int flags)
120
index XXXXXXX..XXXXXXX 100755
63
{
121
--- a/tests/qemu-iotests/121
64
BDRVQcow2State *s = bs->opaque;
122
+++ b/tests/qemu-iotests/121
65
- int offset_in_cluster, n1;
123
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 63M 130K' "$TEST_IMG" | _filter_qemu_io
66
+ int offset_in_cluster;
124
67
int ret;
125
_check_test_img
68
unsigned int cur_bytes; /* number of bytes in current iteration */
126
69
uint64_t cluster_offset = 0;
127
+echo
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
128
+echo '=== Allocating a new refcount block must not leave holes in the image ==='
71
case QCOW2_CLUSTER_UNALLOCATED:
129
+echo
72
130
+
73
if (bs->backing) {
131
+IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M
74
- /* read from the base image */
132
+
75
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
133
+# This results in an image with 256 used clusters: the qcow2 header,
76
- offset, cur_bytes);
134
+# the refcount table, one refcount block, the L1 table, four L2 tables
77
- if (n1 > 0) {
135
+# and 248 data clusters
78
- QEMUIOVector local_qiov;
136
+$QEMU_IO -c 'write 0 124k' "$TEST_IMG" | _filter_qemu_io
79
-
137
+
80
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
138
+# 256 clusters of 512 bytes each give us a 128K image
81
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
139
+stat -c "size=%s (expected 131072)" $TEST_IMG
82
-
140
+
83
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
141
+# All 256 entries of the refcount block are used, so writing a new
84
- qemu_co_mutex_unlock(&s->lock);
142
+# data cluster also allocates a new refcount block
85
- ret = bdrv_co_preadv(bs->backing, offset, n1,
143
+$QEMU_IO -c 'write 124k 512' "$TEST_IMG" | _filter_qemu_io
86
- &local_qiov, 0);
144
+
87
- qemu_co_mutex_lock(&s->lock);
145
+# Two more clusters, the image size should be 129K now
88
-
146
+stat -c "size=%s (expected 132096)" $TEST_IMG
89
- qemu_iovec_destroy(&local_qiov);
147
90
-
148
# success, all done
91
- if (ret < 0) {
149
echo
92
- goto fail;
150
diff --git a/tests/qemu-iotests/121.out b/tests/qemu-iotests/121.out
93
- }
151
index XXXXXXX..XXXXXXX 100644
94
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
152
--- a/tests/qemu-iotests/121.out
95
+ qemu_co_mutex_unlock(&s->lock);
153
+++ b/tests/qemu-iotests/121.out
96
+ ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
154
@@ -XXX,XX +XXX,XX @@ wrote 133120/133120 bytes at offset 66060288
97
+ &hd_qiov, 0);
155
130 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
98
+ qemu_co_mutex_lock(&s->lock);
156
No errors were found on the image.
99
+ if (ret < 0) {
157
100
+ goto fail;
158
+=== Allocating a new refcount block must not leave holes in the image ===
101
}
159
+
102
} else {
160
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
103
/* Note: in this case, no need to wait */
161
+wrote 126976/126976 bytes at offset 0
162
+124 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
163
+size=131072 (expected 131072)
164
+wrote 512/512 bytes at offset 126976
165
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
166
+size=132096 (expected 132096)
167
+
168
*** done
104
--
169
--
105
2.13.6
170
2.13.6
106
171
107
172
diff view generated by jsdifflib
1
Removing a quorum child node with x-blockdev-change results in a quorum
1
What static=on really does is what we call metadata preallocation for
2
driver state that cannot be recreated with create options because it
2
other block drivers. While we can still change the QMP interface, make
3
would require a list with gaps. This causes trouble in at least
3
it more consistent by using 'preallocation' for VDI, too.
4
.bdrv_refresh_filename().
5
4
6
Document this problem so that we won't accidentally mark the command
5
This doesn't implement any new functionality, so the only supported
7
stable without having addressed it.
6
preallocation modes are 'off' and 'metadata' for now.
8
7
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
10
---
12
qapi/block-core.json | 4 ++++
11
qapi/block-core.json | 7 +++----
13
1 file changed, 4 insertions(+)
12
block/vdi.c | 24 ++++++++++++++++++++++--
13
2 files changed, 25 insertions(+), 6 deletions(-)
14
14
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
17
--- a/qapi/block-core.json
18
+++ b/qapi/block-core.json
18
+++ b/qapi/block-core.json
19
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
20
# does not support all kinds of operations, all kinds of children, nor
21
# all block drivers.
22
#
20
#
23
+# FIXME Removing children from a quorum node means introducing gaps in the
21
# @file Node to create the image format on
24
+# child indices. This cannot be represented in the 'children' list of
22
# @size Size of the virtual disk in bytes
25
+# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename().
23
-# @static Whether to create a statically (true) or
26
+#
24
-# dynamically (false) allocated image
27
# Warning: The data in a new quorum child MUST be consistent with that of
25
-# (default: false, i.e. dynamic)
28
# the rest of the array.
26
+# @preallocation Preallocation mode for the new image (allowed values: off,
27
+# metadata; default: off)
29
#
28
#
29
# Since: 2.12
30
##
31
{ 'struct': 'BlockdevCreateOptionsVdi',
32
'data': { 'file': 'BlockdevRef',
33
'size': 'size',
34
- '*static': 'bool' } }
35
+ '*preallocation': 'PreallocMode' } }
36
37
##
38
# @BlockdevVhdxSubformat:
39
diff --git a/block/vdi.c b/block/vdi.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/vdi.c
42
+++ b/block/vdi.c
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
44
int ret = 0;
45
uint64_t bytes = 0;
46
uint32_t blocks;
47
- uint32_t image_type = VDI_TYPE_DYNAMIC;
48
+ uint32_t image_type;
49
VdiHeader header;
50
size_t i;
51
size_t bmap_size;
52
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
53
54
/* Validate options and set default values */
55
bytes = vdi_opts->size;
56
- if (vdi_opts->q_static) {
57
+
58
+ if (!vdi_opts->has_preallocation) {
59
+ vdi_opts->preallocation = PREALLOC_MODE_OFF;
60
+ }
61
+ switch (vdi_opts->preallocation) {
62
+ case PREALLOC_MODE_OFF:
63
+ image_type = VDI_TYPE_DYNAMIC;
64
+ break;
65
+ case PREALLOC_MODE_METADATA:
66
image_type = VDI_TYPE_STATIC;
67
+ break;
68
+ default:
69
+ error_setg(errp, "Preallocation mode not supported for vdi");
70
+ return -EINVAL;
71
}
72
+
73
#ifndef CONFIG_VDI_STATIC_IMAGE
74
if (image_type == VDI_TYPE_STATIC) {
75
ret = -ENOTSUP;
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
77
BlockdevCreateOptions *create_options = NULL;
78
BlockDriverState *bs_file = NULL;
79
uint64_t block_size = DEFAULT_CLUSTER_SIZE;
80
+ bool is_static = false;
81
Visitor *v;
82
Error *local_err = NULL;
83
int ret;
84
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
85
goto done;
86
}
87
#endif
88
+ if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) {
89
+ is_static = true;
90
+ }
91
92
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
93
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
95
96
qdict_put_str(qdict, "driver", "vdi");
97
qdict_put_str(qdict, "file", bs_file->node_name);
98
+ if (is_static) {
99
+ qdict_put_str(qdict, "preallocation", "metadata");
100
+ }
101
102
/* Get the QAPI object */
103
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
30
--
104
--
31
2.13.6
105
2.13.6
32
106
33
107
diff view generated by jsdifflib
1
The device is drained, so there is no point in waiting for requests at
1
Use qemu_uuid_unparse() instead of uuid_unparse() to make vdi.c compile
2
the end of the drained section. Remove the bdrv_drain_recurse() calls
2
again when CONFIG_VDI_DEBUG is set. In order to prevent future bitrot,
3
there.
3
replace '#ifdef CONFIG_VDI_DEBUG' by 'if (VDI_DEBUG)' so that the
4
4
compiler always sees the code.
5
The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e
6
in order to call the .bdrv_co_drain_end() driver callback. This is now
7
done by a separate bdrv_drain_invoke() call.
8
5
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
8
---
13
block/io.c | 2 --
9
block/vdi.c | 22 ++++++++++------------
14
1 file changed, 2 deletions(-)
10
1 file changed, 10 insertions(+), 12 deletions(-)
15
11
16
diff --git a/block/io.c b/block/io.c
12
diff --git a/block/vdi.c b/block/vdi.c
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/block/io.c
14
--- a/block/vdi.c
19
+++ b/block/io.c
15
+++ b/block/vdi.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
16
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header)
21
17
qemu_uuid_bswap(&header->uuid_parent);
22
bdrv_parent_drained_end(bs);
23
bdrv_drain_invoke(bs, false);
24
- bdrv_drain_recurse(bs);
25
aio_enable_external(bdrv_get_aio_context(bs));
26
}
18
}
27
19
28
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
20
-#if defined(CONFIG_VDI_DEBUG)
29
aio_enable_external(aio_context);
21
static void vdi_header_print(VdiHeader *header)
30
bdrv_parent_drained_end(bs);
22
{
31
bdrv_drain_invoke(bs, false);
23
char uuid[37];
32
- bdrv_drain_recurse(bs);
24
@@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header)
33
aio_context_release(aio_context);
25
logout("block extra 0x%04x\n", header->block_extra);
26
logout("blocks tot. 0x%04x\n", header->blocks_in_image);
27
logout("blocks all. 0x%04x\n", header->blocks_allocated);
28
- uuid_unparse(header->uuid_image, uuid);
29
+ qemu_uuid_unparse(&header->uuid_image, uuid);
30
logout("uuid image %s\n", uuid);
31
- uuid_unparse(header->uuid_last_snap, uuid);
32
+ qemu_uuid_unparse(&header->uuid_last_snap, uuid);
33
logout("uuid snap %s\n", uuid);
34
- uuid_unparse(header->uuid_link, uuid);
35
+ qemu_uuid_unparse(&header->uuid_link, uuid);
36
logout("uuid link %s\n", uuid);
37
- uuid_unparse(header->uuid_parent, uuid);
38
+ qemu_uuid_unparse(&header->uuid_parent, uuid);
39
logout("uuid parent %s\n", uuid);
40
}
41
-#endif
42
43
static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
44
BdrvCheckMode fix)
45
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
34
}
46
}
35
47
48
vdi_header_to_cpu(&header);
49
-#if defined(CONFIG_VDI_DEBUG)
50
- vdi_header_print(&header);
51
-#endif
52
+ if (VDI_DEBUG) {
53
+ vdi_header_print(&header);
54
+ }
55
56
if (header.disk_size > VDI_DISK_SIZE_MAX) {
57
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
59
qemu_uuid_generate(&header.uuid_image);
60
qemu_uuid_generate(&header.uuid_last_snap);
61
/* There is no need to set header.uuid_link or header.uuid_parent here. */
62
-#if defined(CONFIG_VDI_DEBUG)
63
- vdi_header_print(&header);
64
-#endif
65
+ if (VDI_DEBUG) {
66
+ vdi_header_print(&header);
67
+ }
68
vdi_header_to_le(&header);
69
ret = blk_pwrite(blk, offset, &header, sizeof(header), 0);
70
if (ret < 0) {
36
--
71
--
37
2.13.6
72
2.13.6
38
73
39
74
diff view generated by jsdifflib
1
This adds a test case that the BlockDriver callbacks for drain are
2
called in bdrv_drained_all_begin/end(), and that both of them are called
3
exactly once.
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
8
---
3
---
9
tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++
4
tests/qemu-iotests/211 | 246 +++++++++++++++++++++++++++++++++++++++++++++
10
tests/Makefile.include | 2 +
5
tests/qemu-iotests/211.out | 97 ++++++++++++++++++
11
2 files changed, 139 insertions(+)
6
tests/qemu-iotests/group | 1 +
12
create mode 100644 tests/test-bdrv-drain.c
7
3 files changed, 344 insertions(+)
8
create mode 100755 tests/qemu-iotests/211
9
create mode 100644 tests/qemu-iotests/211.out
13
10
14
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
11
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
12
new file mode 100755
13
index XXXXXXX..XXXXXXX
14
--- /dev/null
15
+++ b/tests/qemu-iotests/211
16
@@ -XXX,XX +XXX,XX @@
17
+#!/bin/bash
18
+#
19
+# Test VDI and file image creation
20
+#
21
+# Copyright (C) 2018 Red Hat, Inc.
22
+#
23
+# This program is free software; you can redistribute it and/or modify
24
+# it under the terms of the GNU General Public License as published by
25
+# the Free Software Foundation; either version 2 of the License, or
26
+# (at your option) any later version.
27
+#
28
+# This program is distributed in the hope that it will be useful,
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+# GNU General Public License for more details.
32
+#
33
+# You should have received a copy of the GNU General Public License
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+#
36
+
37
+# creator
38
+owner=kwolf@redhat.com
39
+
40
+seq=`basename $0`
41
+echo "QA output created by $seq"
42
+
43
+here=`pwd`
44
+status=1    # failure is the default!
45
+
46
+# get standard environment, filters and checks
47
+. ./common.rc
48
+. ./common.filter
49
+
50
+_supported_fmt vdi
51
+_supported_proto file
52
+_supported_os Linux
53
+
54
+function do_run_qemu()
55
+{
56
+ echo Testing: "$@"
57
+ $QEMU -nographic -qmp stdio -serial none "$@"
58
+ echo
59
+}
60
+
61
+function run_qemu()
62
+{
63
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
64
+ | _filter_qemu | _filter_imgfmt \
65
+ | _filter_actual_image_size
66
+}
67
+
68
+echo
69
+echo "=== Successful image creation (defaults) ==="
70
+echo
71
+
72
+size=$((128 * 1024 * 1024))
73
+
74
+run_qemu <<EOF
75
+{ "execute": "qmp_capabilities" }
76
+{ "execute": "x-blockdev-create",
77
+ "arguments": {
78
+ "driver": "file",
79
+ "filename": "$TEST_IMG",
80
+ "size": 0
81
+ }
82
+}
83
+{ "execute": "blockdev-add",
84
+ "arguments": {
85
+ "driver": "file",
86
+ "node-name": "imgfile",
87
+ "filename": "$TEST_IMG"
88
+ }
89
+}
90
+{ "execute": "x-blockdev-create",
91
+ "arguments": {
92
+ "driver": "$IMGFMT",
93
+ "file": "imgfile",
94
+ "size": $size
95
+ }
96
+}
97
+{ "execute": "quit" }
98
+EOF
99
+
100
+_img_info --format-specific | _filter_img_info --format-specific
101
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
102
+
103
+echo
104
+echo "=== Successful image creation (explicit defaults) ==="
105
+echo
106
+
107
+# Choose a different size to show that we got a new image
108
+size=$((64 * 1024 * 1024))
109
+
110
+run_qemu <<EOF
111
+{ "execute": "qmp_capabilities" }
112
+{ "execute": "x-blockdev-create",
113
+ "arguments": {
114
+ "driver": "file",
115
+ "filename": "$TEST_IMG",
116
+ "size": 0
117
+ }
118
+}
119
+{ "execute": "x-blockdev-create",
120
+ "arguments": {
121
+ "driver": "$IMGFMT",
122
+ "file": {
123
+ "driver": "file",
124
+ "filename": "$TEST_IMG"
125
+ },
126
+ "size": $size,
127
+ "preallocation": "off"
128
+ }
129
+}
130
+{ "execute": "quit" }
131
+EOF
132
+
133
+_img_info --format-specific | _filter_img_info --format-specific
134
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
135
+
136
+echo
137
+echo "=== Successful image creation (with non-default options) ==="
138
+echo
139
+
140
+# Choose a different size to show that we got a new image
141
+size=$((32 * 1024 * 1024))
142
+
143
+run_qemu <<EOF
144
+{ "execute": "qmp_capabilities" }
145
+{ "execute": "x-blockdev-create",
146
+ "arguments": {
147
+ "driver": "file",
148
+ "filename": "$TEST_IMG",
149
+ "size": 0
150
+ }
151
+}
152
+{ "execute": "x-blockdev-create",
153
+ "arguments": {
154
+ "driver": "$IMGFMT",
155
+ "file": {
156
+ "driver": "file",
157
+ "filename": "$TEST_IMG"
158
+ },
159
+ "size": $size,
160
+ "preallocation": "metadata"
161
+ }
162
+}
163
+{ "execute": "quit" }
164
+EOF
165
+
166
+_img_info --format-specific | _filter_img_info --format-specific
167
+$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
168
+
169
+echo
170
+echo "=== Invalid BlockdevRef ==="
171
+echo
172
+
173
+run_qemu <<EOF
174
+{ "execute": "qmp_capabilities" }
175
+{ "execute": "x-blockdev-create",
176
+ "arguments": {
177
+ "driver": "$IMGFMT",
178
+ "file": "this doesn't exist",
179
+ "size": $size
180
+ }
181
+}
182
+{ "execute": "quit" }
183
+EOF
184
+
185
+echo
186
+echo "=== Zero size ==="
187
+echo
188
+
189
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
190
+{ "execute": "qmp_capabilities" }
191
+{ "execute": "x-blockdev-create",
192
+ "arguments": {
193
+ "driver": "$IMGFMT",
194
+ "file": "node0",
195
+ "size": 0
196
+ }
197
+}
198
+{ "execute": "quit" }
199
+EOF
200
+
201
+_img_info | _filter_img_info
202
+
203
+echo
204
+echo "=== Maximum size ==="
205
+echo
206
+
207
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
208
+{ "execute": "qmp_capabilities" }
209
+{ "execute": "x-blockdev-create",
210
+ "arguments": {
211
+ "driver": "$IMGFMT",
212
+ "file": "node0",
213
+ "size": 562949819203584
214
+ }
215
+}
216
+{ "execute": "quit" }
217
+EOF
218
+
219
+_img_info | _filter_img_info
220
+
221
+echo
222
+echo "=== Invalid sizes ==="
223
+echo
224
+
225
+# TODO Negative image sizes aren't handled correctly, but this is a problem
226
+# with QAPI's implementation of the 'size' type and affects other commands as
227
+# well. Once this is fixed, we may want to add a test case here.
228
+
229
+# 1. 2^64 - 512
230
+# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
231
+# 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
232
+
233
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
234
+{ "execute": "qmp_capabilities" }
235
+{ "execute": "x-blockdev-create",
236
+ "arguments": {
237
+ "driver": "$IMGFMT",
238
+ "file": "node0",
239
+ "size": 18446744073709551104
240
+ }
241
+}
242
+{ "execute": "x-blockdev-create",
243
+ "arguments": {
244
+ "driver": "$IMGFMT",
245
+ "file": "node0",
246
+ "size": 9223372036854775808
247
+ }
248
+}
249
+{ "execute": "x-blockdev-create",
250
+ "arguments": {
251
+ "driver": "$IMGFMT",
252
+ "file": "node0",
253
+ "size": 562949819203585
254
+ }
255
+}
256
+{ "execute": "quit" }
257
+EOF
258
+
259
+# success, all done
260
+echo "*** done"
261
+rm -f $seq.full
262
+status=0
263
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
15
new file mode 100644
264
new file mode 100644
16
index XXXXXXX..XXXXXXX
265
index XXXXXXX..XXXXXXX
17
--- /dev/null
266
--- /dev/null
18
+++ b/tests/test-bdrv-drain.c
267
+++ b/tests/qemu-iotests/211.out
19
@@ -XXX,XX +XXX,XX @@
268
@@ -XXX,XX +XXX,XX @@
20
+/*
269
+QA output created by 211
21
+ * Block node draining tests
270
+
22
+ *
271
+=== Successful image creation (defaults) ===
23
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
272
+
24
+ *
273
+Testing:
25
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
274
+QMP_VERSION
26
+ * of this software and associated documentation files (the "Software"), to deal
275
+{"return": {}}
27
+ * in the Software without restriction, including without limitation the rights
276
+{"return": {}}
28
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
277
+{"return": {}}
29
+ * copies of the Software, and to permit persons to whom the Software is
278
+{"return": {}}
30
+ * furnished to do so, subject to the following conditions:
279
+{"return": {}}
31
+ *
280
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
32
+ * The above copyright notice and this permission notice shall be included in
281
+
33
+ * all copies or substantial portions of the Software.
282
+image: TEST_DIR/t.IMGFMT
34
+ *
283
+file format: IMGFMT
35
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
284
+virtual size: 128M (134217728 bytes)
36
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
285
+[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}]
37
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
286
+
38
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
287
+=== Successful image creation (explicit defaults) ===
39
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
288
+
40
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
289
+Testing:
41
+ * THE SOFTWARE.
290
+QMP_VERSION
42
+ */
291
+{"return": {}}
43
+
292
+{"return": {}}
44
+#include "qemu/osdep.h"
293
+{"return": {}}
45
+#include "block/block.h"
294
+{"return": {}}
46
+#include "sysemu/block-backend.h"
295
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
47
+#include "qapi/error.h"
296
+
48
+
297
+image: TEST_DIR/t.IMGFMT
49
+typedef struct BDRVTestState {
298
+file format: IMGFMT
50
+ int drain_count;
299
+virtual size: 64M (67108864 bytes)
51
+} BDRVTestState;
300
+[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}]
52
+
301
+
53
+static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
302
+=== Successful image creation (with non-default options) ===
54
+{
303
+
55
+ BDRVTestState *s = bs->opaque;
304
+Testing:
56
+ s->drain_count++;
305
+QMP_VERSION
57
+}
306
+{"return": {}}
58
+
307
+{"return": {}}
59
+static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
308
+{"return": {}}
60
+{
309
+{"return": {}}
61
+ BDRVTestState *s = bs->opaque;
310
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
62
+ s->drain_count--;
311
+
63
+}
312
+image: TEST_DIR/t.IMGFMT
64
+
313
+file format: IMGFMT
65
+static void bdrv_test_close(BlockDriverState *bs)
314
+virtual size: 32M (33554432 bytes)
66
+{
315
+[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
67
+ BDRVTestState *s = bs->opaque;
316
+{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": OFFSET}]
68
+ g_assert_cmpint(s->drain_count, >, 0);
317
+
69
+}
318
+=== Invalid BlockdevRef ===
70
+
319
+
71
+static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
320
+Testing:
72
+ uint64_t offset, uint64_t bytes,
321
+QMP_VERSION
73
+ QEMUIOVector *qiov, int flags)
322
+{"return": {}}
74
+{
323
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
75
+ /* We want this request to stay until the polling loop in drain waits for
324
+{"return": {}}
76
+ * it to complete. We need to sleep a while as bdrv_drain_invoke() comes
325
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
77
+ * first and polls its result, too, but it shouldn't accidentally complete
326
+
78
+ * this request yet. */
327
+
79
+ co_aio_sleep_ns(qemu_get_aio_context(), QEMU_CLOCK_REALTIME, 100000);
328
+=== Zero size ===
80
+
329
+
81
+ return 0;
330
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
82
+}
331
+QMP_VERSION
83
+
332
+{"return": {}}
84
+static BlockDriver bdrv_test = {
333
+{"return": {}}
85
+ .format_name = "test",
334
+{"return": {}}
86
+ .instance_size = sizeof(BDRVTestState),
335
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
87
+
336
+
88
+ .bdrv_close = bdrv_test_close,
337
+image: TEST_DIR/t.IMGFMT
89
+ .bdrv_co_preadv = bdrv_test_co_preadv,
338
+file format: IMGFMT
90
+
339
+virtual size: 0 (0 bytes)
91
+ .bdrv_co_drain_begin = bdrv_test_co_drain_begin,
340
+
92
+ .bdrv_co_drain_end = bdrv_test_co_drain_end,
341
+=== Maximum size ===
93
+};
342
+
94
+
343
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
95
+static void aio_ret_cb(void *opaque, int ret)
344
+QMP_VERSION
96
+{
345
+{"return": {}}
97
+ int *aio_ret = opaque;
346
+{"return": {}}
98
+ *aio_ret = ret;
347
+{"return": {}}
99
+}
348
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
100
+
349
+
101
+static void test_drv_cb_drain_all(void)
350
+image: TEST_DIR/t.IMGFMT
102
+{
351
+file format: IMGFMT
103
+ BlockBackend *blk;
352
+virtual size: 512T (562949819203584 bytes)
104
+ BlockDriverState *bs;
353
+
105
+ BDRVTestState *s;
354
+=== Invalid sizes ===
106
+ BlockAIOCB *acb;
355
+
107
+ int aio_ret;
356
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
108
+
357
+QMP_VERSION
109
+ QEMUIOVector qiov;
358
+{"return": {}}
110
+ struct iovec iov = {
359
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)"}}
111
+ .iov_base = NULL,
360
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)"}}
112
+ .iov_len = 0,
361
+{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)"}}
113
+ };
362
+{"return": {}}
114
+ qemu_iovec_init_external(&qiov, &iov, 1);
363
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
115
+
364
+
116
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
365
+*** done
117
+ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
366
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
118
+ &error_abort);
119
+ s = bs->opaque;
120
+ blk_insert_bs(blk, bs, &error_abort);
121
+
122
+ /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
123
+ g_assert_cmpint(s->drain_count, ==, 0);
124
+ bdrv_drain_all_begin();
125
+ g_assert_cmpint(s->drain_count, ==, 1);
126
+ bdrv_drain_all_end();
127
+ g_assert_cmpint(s->drain_count, ==, 0);
128
+
129
+ /* Now do the same while a request is pending */
130
+ aio_ret = -EINPROGRESS;
131
+ acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret);
132
+ g_assert(acb != NULL);
133
+ g_assert_cmpint(aio_ret, ==, -EINPROGRESS);
134
+
135
+ g_assert_cmpint(s->drain_count, ==, 0);
136
+ bdrv_drain_all_begin();
137
+ g_assert_cmpint(aio_ret, ==, 0);
138
+ g_assert_cmpint(s->drain_count, ==, 1);
139
+ bdrv_drain_all_end();
140
+ g_assert_cmpint(s->drain_count, ==, 0);
141
+
142
+ bdrv_unref(bs);
143
+ blk_unref(blk);
144
+}
145
+
146
+int main(int argc, char **argv)
147
+{
148
+ bdrv_init();
149
+ qemu_init_main_loop(&error_abort);
150
+
151
+ g_test_init(&argc, &argv, NULL);
152
+
153
+ g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
154
+
155
+ return g_test_run();
156
+}
157
diff --git a/tests/Makefile.include b/tests/Makefile.include
158
index XXXXXXX..XXXXXXX 100644
367
index XXXXXXX..XXXXXXX 100644
159
--- a/tests/Makefile.include
368
--- a/tests/qemu-iotests/group
160
+++ b/tests/Makefile.include
369
+++ b/tests/qemu-iotests/group
161
@@ -XXX,XX +XXX,XX @@ gcov-files-test-thread-pool-y = thread-pool.c
370
@@ -XXX,XX +XXX,XX @@
162
gcov-files-test-hbitmap-y = util/hbitmap.c
371
208 rw auto quick
163
check-unit-y += tests/test-hbitmap$(EXESUF)
372
209 rw auto quick
164
gcov-files-test-hbitmap-y = blockjob.c
373
210 rw auto
165
+check-unit-y += tests/test-bdrv-drain$(EXESUF)
374
+211 rw auto quick
166
check-unit-y += tests/test-blockjob$(EXESUF)
167
check-unit-y += tests/test-blockjob-txn$(EXESUF)
168
check-unit-y += tests/test-x86-cpuid$(EXESUF)
169
@@ -XXX,XX +XXX,XX @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
170
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
171
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
172
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
173
+tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
174
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
175
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
176
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
177
--
375
--
178
2.13.6
376
2.13.6
179
377
180
378
diff view generated by jsdifflib
New patch
1
We want to test resizing even for luks. The only change that is needed
2
is to explicitly zero out new space for luks because it's undefined.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
7
---
8
tests/qemu-iotests/025 | 9 ++++++++-
9
1 file changed, 8 insertions(+), 1 deletion(-)
10
11
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
12
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/025
14
+++ b/tests/qemu-iotests/025
15
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
16
. ./common.filter
17
. ./common.pattern
18
19
-_supported_fmt raw qcow2 qed
20
+_supported_fmt raw qcow2 qed luks
21
_supported_proto file sheepdog rbd nfs
22
_supported_os Linux
23
24
@@ -XXX,XX +XXX,XX @@ length
25
EOF
26
_check_test_img
27
28
+# bdrv_truncate() doesn't zero the new space, so we need to do that explicitly.
29
+# We still want to test automatic zeroing for other formats even though
30
+# bdrv_truncate() doesn't guarantee it.
31
+if [ "$IMGFMT" == "luks" ]; then
32
+ $QEMU_IO -c "write -z $small_size $((big_size - small_size))" "$TEST_IMG" > /dev/null
33
+fi
34
+
35
echo
36
echo "=== Verifying image size after reopen"
37
$QEMU_IO -c "length" "$TEST_IMG"
38
--
39
2.13.6
40
41
diff view generated by jsdifflib
1
Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently
1
Commit e39e959e fixed an invalid assertion in the .bdrv_length
2
in use as a mirror target. It is not enough for image formats, though,
2
implementation, but left a similar assertion in place for
3
as these still unconditionally request BLK_PERM_CONSISTENT_READ.
3
.bdrv_truncate. Instead of crashing when the user requests a too large
4
image size, fail gracefully.
4
5
5
As this permission is geared towards whether the guest-visible data is
6
A file size of exactly INT64_MAX caused failure before, but is actually
6
consistent, and has no impact on whether the metadata is sane, and
7
legal.
7
'qemu-img info' does not read guest-visible data (except for the raw
8
format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there
9
is not going to be any guest I/O performed, regardless of image format.
10
8
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
12
---
12
---
13
block.c | 6 +++++-
13
block/crypto.c | 6 +++++-
14
1 file changed, 5 insertions(+), 1 deletion(-)
14
1 file changed, 5 insertions(+), 1 deletion(-)
15
15
16
diff --git a/block.c b/block.c
16
diff --git a/block/crypto.c b/block/crypto.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block.c
18
--- a/block/crypto.c
19
+++ b/block.c
19
+++ b/block/crypto.c
20
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
20
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
21
assert(role == &child_backing || role == &child_file);
21
BlockCrypto *crypto = bs->opaque;
22
22
uint64_t payload_offset =
23
if (!backing) {
23
qcrypto_block_get_payload_offset(crypto->block);
24
+ int flags = bdrv_reopen_get_flags(reopen_queue, bs);
24
- assert(payload_offset < (INT64_MAX - offset));
25
+
25
+
26
/* Apart from the modifications below, the same permissions are
26
+ if (payload_offset > INT64_MAX - offset) {
27
* forwarded and left alone as for filters */
27
+ error_setg(errp, "The requested file size is too large");
28
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
28
+ return -EFBIG;
29
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
29
+ }
30
30
31
/* bs->file always needs to be consistent because of the metadata. We
31
offset += payload_offset;
32
* can never allow other users to resize or write to it. */
32
33
- perm |= BLK_PERM_CONSISTENT_READ;
34
+ if (!(flags & BDRV_O_NO_IO)) {
35
+ perm |= BLK_PERM_CONSISTENT_READ;
36
+ }
37
shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
38
} else {
39
/* We want consistent read from backing files if the parent needs it.
40
--
33
--
41
2.13.6
34
2.13.6
42
35
43
36
diff view generated by jsdifflib
1
This change separates bdrv_drain_invoke(), which calls the BlockDriver
1
This tests that the .bdrv_truncate implementation for luks doesn't crash
2
drain callbacks, from bdrv_drain_recurse(). Instead, the function
2
for invalid image sizes.
3
performs its own recursion now.
4
3
5
One reason for this is that bdrv_drain_recurse() can be called multiple
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
times by bdrv_drain_all_begin(), but the callbacks may only be called
5
Reviewed-by: Eric Blake <eblake@redhat.com>
7
once. The separation is necessary to fix this bug.
6
---
7
tests/qemu-iotests/210 | 37 +++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/210.out | 16 ++++++++++++++++
9
2 files changed, 53 insertions(+)
8
10
9
The other reason is that we intend to go to a model where we call all
11
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
10
driver callbacks first, and only then start polling. This is not fully
12
index XXXXXXX..XXXXXXX 100755
11
achieved yet with this patch, as bdrv_drain_invoke() contains a
13
--- a/tests/qemu-iotests/210
12
BDRV_POLL_WHILE() loop for the block driver callbacks, which can still
14
+++ b/tests/qemu-iotests/210
13
call callbacks for any unrelated event. It's a step in this direction
15
@@ -XXX,XX +XXX,XX @@ run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
14
anyway.
16
{ "execute": "quit" }
15
17
EOF
16
Cc: qemu-stable@nongnu.org
18
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
+echo
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
20
+echo "=== Resize image with invalid sizes ==="
19
---
21
+echo
20
block/io.c | 14 +++++++++++---
22
+
21
1 file changed, 11 insertions(+), 3 deletions(-)
23
+run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
22
24
+ -blockdev driver=luks,file=node0,key-secret=keysec0,node-name=node1 \
23
diff --git a/block/io.c b/block/io.c
25
+ -object secret,id=keysec0,data="foo" <<EOF
26
+{ "execute": "qmp_capabilities" }
27
+{ "execute": "block_resize",
28
+ "arguments": {
29
+ "node-name": "node1",
30
+ "size": 9223372036854775296
31
+ }
32
+}
33
+{ "execute": "block_resize",
34
+ "arguments": {
35
+ "node-name": "node1",
36
+ "size": 9223372036854775808
37
+ }
38
+}
39
+{ "execute": "block_resize",
40
+ "arguments": {
41
+ "node-name": "node1",
42
+ "size": 18446744073709551104
43
+ }
44
+}
45
+{ "execute": "block_resize",
46
+ "arguments": {
47
+ "node-name": "node1",
48
+ "size": -9223372036854775808
49
+ }
50
+}
51
+{ "execute": "quit" }
52
+EOF
53
+
54
+_img_info | _filter_img_info
55
+
56
# success, all done
57
echo "*** done"
58
rm -f $seq.full
59
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
24
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
25
--- a/block/io.c
61
--- a/tests/qemu-iotests/210.out
26
+++ b/block/io.c
62
+++ b/tests/qemu-iotests/210.out
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
63
@@ -XXX,XX +XXX,XX @@ QMP_VERSION
28
bdrv_wakeup(bs);
64
{"return": {}}
29
}
65
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
30
66
31
+/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
32
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
33
{
34
+ BdrvChild *child, *tmp;
35
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
36
37
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
39
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
40
bdrv_coroutine_enter(bs, data.co);
41
BDRV_POLL_WHILE(bs, !data.done);
42
+
67
+
43
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
68
+=== Resize image with invalid sizes ===
44
+ bdrv_drain_invoke(child->bs, begin);
69
+
45
+ }
70
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -blockdev driver=IMGFMT,file=node0,key-secret=keysec0,node-name=node1 -object secret,id=keysec0,data=foo
46
}
71
+QMP_VERSION
47
72
+{"return": {}}
48
static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
73
+{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
49
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
74
+{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
50
BdrvChild *child, *tmp;
75
+{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
51
bool waited;
76
+{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
52
77
+{"return": {}}
53
- /* Ensure any pending metadata writes are submitted to bs->file. */
78
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
54
- bdrv_drain_invoke(bs, begin);
79
+
55
-
80
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
56
/* Wait for drained requests to finish */
81
+file format: IMGFMT
57
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
82
+virtual size: 0 (0 bytes)
58
83
*** done
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
60
bdrv_parent_drained_begin(bs);
61
}
62
63
+ bdrv_drain_invoke(bs, true);
64
bdrv_drain_recurse(bs, true);
65
}
66
67
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
68
}
69
70
bdrv_parent_drained_end(bs);
71
+ bdrv_drain_invoke(bs, false);
72
bdrv_drain_recurse(bs, false);
73
aio_enable_external(bdrv_get_aio_context(bs));
74
}
75
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
76
aio_context_acquire(aio_context);
77
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
78
if (aio_context == bdrv_get_aio_context(bs)) {
79
+ /* FIXME Calling this multiple times is wrong */
80
+ bdrv_drain_invoke(bs, true);
81
waited |= bdrv_drain_recurse(bs, true);
82
}
83
}
84
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
85
aio_context_acquire(aio_context);
86
aio_enable_external(aio_context);
87
bdrv_parent_drained_end(bs);
88
+ bdrv_drain_invoke(bs, false);
89
bdrv_drain_recurse(bs, false);
90
aio_context_release(aio_context);
91
}
92
--
84
--
93
2.13.6
85
2.13.6
94
86
95
87
diff view generated by jsdifflib
1
Commit 15afd94a047 added code to acquire and release the AioContext in
1
It's unclear what the real maximum cluster size is for the Parallels
2
qemuio_command(). This means that the lock is taken twice now in the
2
format, but let's at least make sure that we don't get integer
3
call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for
3
overflows in our .bdrv_co_create implementation.
4
any requests issued to nodes in a non-mainloop AioContext.
5
6
Dropping the first locking from hmp_qemu_io() fixes the problem.
7
4
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
10
---
7
---
11
hmp.c | 6 ------
8
block/parallels.c | 5 +++++
12
1 file changed, 6 deletions(-)
9
1 file changed, 5 insertions(+)
13
10
14
diff --git a/hmp.c b/hmp.c
11
diff --git a/block/parallels.c b/block/parallels.c
15
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
16
--- a/hmp.c
13
--- a/block/parallels.c
17
+++ b/hmp.c
14
+++ b/block/parallels.c
18
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
19
{
16
cl_size = DEFAULT_CLUSTER_SIZE;
20
BlockBackend *blk;
21
BlockBackend *local_blk = NULL;
22
- AioContext *aio_context;
23
const char* device = qdict_get_str(qdict, "device");
24
const char* command = qdict_get_str(qdict, "command");
25
Error *err = NULL;
26
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
27
}
28
}
17
}
29
18
30
- aio_context = blk_get_aio_context(blk);
19
+ /* XXX What is the real limit here? This is an insanely large maximum. */
31
- aio_context_acquire(aio_context);
20
+ if (cl_size >= INT64_MAX / MAX_PARALLELS_IMAGE_FACTOR) {
32
-
21
+ error_setg(errp, "Cluster size is too large");
33
/*
22
+ return -EINVAL;
34
* Notably absent: Proper permission management. This is sad, but it seems
23
+ }
35
* almost impossible to achieve without changing the semantics and thereby
24
if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) {
36
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
25
error_setg(errp, "Image size is too large for this cluster size");
37
*/
26
return -E2BIG;
38
qemuio_command(blk, command);
39
40
- aio_context_release(aio_context);
41
-
42
fail:
43
blk_unref(local_blk);
44
hmp_handle_error(mon, &err);
45
--
27
--
46
2.13.6
28
2.13.6
47
29
48
30
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
2
---
8
qemu-img.texi | 9 +++++++++
3
tests/qemu-iotests/212 | 326 +++++++++++++++++++++++++++++++++++++++++++++
9
1 file changed, 9 insertions(+)
4
tests/qemu-iotests/212.out | 111 +++++++++++++++
5
tests/qemu-iotests/group | 1 +
6
3 files changed, 438 insertions(+)
7
create mode 100755 tests/qemu-iotests/212
8
create mode 100644 tests/qemu-iotests/212.out
10
9
11
diff --git a/qemu-img.texi b/qemu-img.texi
10
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
11
new file mode 100755
12
index XXXXXXX..XXXXXXX
13
--- /dev/null
14
+++ b/tests/qemu-iotests/212
15
@@ -XXX,XX +XXX,XX @@
16
+#!/bin/bash
17
+#
18
+# Test parallels and file image creation
19
+#
20
+# Copyright (C) 2018 Red Hat, Inc.
21
+#
22
+# This program is free software; you can redistribute it and/or modify
23
+# it under the terms of the GNU General Public License as published by
24
+# the Free Software Foundation; either version 2 of the License, or
25
+# (at your option) any later version.
26
+#
27
+# This program is distributed in the hope that it will be useful,
28
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
29
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
+# GNU General Public License for more details.
31
+#
32
+# You should have received a copy of the GNU General Public License
33
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
+#
35
+
36
+# creator
37
+owner=kwolf@redhat.com
38
+
39
+seq=`basename $0`
40
+echo "QA output created by $seq"
41
+
42
+here=`pwd`
43
+status=1    # failure is the default!
44
+
45
+# get standard environment, filters and checks
46
+. ./common.rc
47
+. ./common.filter
48
+
49
+_supported_fmt parallels
50
+_supported_proto file
51
+_supported_os Linux
52
+
53
+function do_run_qemu()
54
+{
55
+ echo Testing: "$@"
56
+ $QEMU -nographic -qmp stdio -serial none "$@"
57
+ echo
58
+}
59
+
60
+function run_qemu()
61
+{
62
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
+ | _filter_qemu | _filter_imgfmt \
64
+ | _filter_actual_image_size
65
+}
66
+
67
+echo
68
+echo "=== Successful image creation (defaults) ==="
69
+echo
70
+
71
+size=$((128 * 1024 * 1024))
72
+
73
+run_qemu <<EOF
74
+{ "execute": "qmp_capabilities" }
75
+{ "execute": "x-blockdev-create",
76
+ "arguments": {
77
+ "driver": "file",
78
+ "filename": "$TEST_IMG",
79
+ "size": 0
80
+ }
81
+}
82
+{ "execute": "blockdev-add",
83
+ "arguments": {
84
+ "driver": "file",
85
+ "node-name": "imgfile",
86
+ "filename": "$TEST_IMG"
87
+ }
88
+}
89
+{ "execute": "x-blockdev-create",
90
+ "arguments": {
91
+ "driver": "$IMGFMT",
92
+ "file": "imgfile",
93
+ "size": $size
94
+ }
95
+}
96
+{ "execute": "quit" }
97
+EOF
98
+
99
+_img_info --format-specific | _filter_img_info --format-specific
100
+
101
+echo
102
+echo "=== Successful image creation (explicit defaults) ==="
103
+echo
104
+
105
+# Choose a different size to show that we got a new image
106
+size=$((64 * 1024 * 1024))
107
+
108
+run_qemu <<EOF
109
+{ "execute": "qmp_capabilities" }
110
+{ "execute": "x-blockdev-create",
111
+ "arguments": {
112
+ "driver": "file",
113
+ "filename": "$TEST_IMG",
114
+ "size": 0
115
+ }
116
+}
117
+{ "execute": "x-blockdev-create",
118
+ "arguments": {
119
+ "driver": "$IMGFMT",
120
+ "file": {
121
+ "driver": "file",
122
+ "filename": "$TEST_IMG"
123
+ },
124
+ "size": $size,
125
+ "cluster-size": 1048576
126
+ }
127
+}
128
+{ "execute": "quit" }
129
+EOF
130
+
131
+_img_info --format-specific | _filter_img_info --format-specific
132
+
133
+echo
134
+echo "=== Successful image creation (with non-default options) ==="
135
+echo
136
+
137
+# Choose a different size to show that we got a new image
138
+size=$((32 * 1024 * 1024))
139
+
140
+run_qemu <<EOF
141
+{ "execute": "qmp_capabilities" }
142
+{ "execute": "x-blockdev-create",
143
+ "arguments": {
144
+ "driver": "file",
145
+ "filename": "$TEST_IMG",
146
+ "size": 0
147
+ }
148
+}
149
+{ "execute": "x-blockdev-create",
150
+ "arguments": {
151
+ "driver": "$IMGFMT",
152
+ "file": {
153
+ "driver": "file",
154
+ "filename": "$TEST_IMG"
155
+ },
156
+ "size": $size,
157
+ "cluster-size": 65536
158
+ }
159
+}
160
+{ "execute": "quit" }
161
+EOF
162
+
163
+_img_info --format-specific | _filter_img_info --format-specific
164
+
165
+echo
166
+echo "=== Invalid BlockdevRef ==="
167
+echo
168
+
169
+run_qemu <<EOF
170
+{ "execute": "qmp_capabilities" }
171
+{ "execute": "x-blockdev-create",
172
+ "arguments": {
173
+ "driver": "$IMGFMT",
174
+ "file": "this doesn't exist",
175
+ "size": $size
176
+ }
177
+}
178
+{ "execute": "quit" }
179
+EOF
180
+
181
+echo
182
+echo "=== Zero size ==="
183
+echo
184
+
185
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
186
+{ "execute": "qmp_capabilities" }
187
+{ "execute": "x-blockdev-create",
188
+ "arguments": {
189
+ "driver": "$IMGFMT",
190
+ "file": "node0",
191
+ "size": 0
192
+ }
193
+}
194
+{ "execute": "quit" }
195
+EOF
196
+
197
+_img_info | _filter_img_info
198
+
199
+echo
200
+echo "=== Maximum size ==="
201
+echo
202
+
203
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
204
+{ "execute": "qmp_capabilities" }
205
+{ "execute": "x-blockdev-create",
206
+ "arguments": {
207
+ "driver": "$IMGFMT",
208
+ "file": "node0",
209
+ "size": 4503599627369984
210
+ }
211
+}
212
+{ "execute": "quit" }
213
+EOF
214
+
215
+_img_info | _filter_img_info
216
+
217
+echo
218
+echo "=== Invalid sizes ==="
219
+echo
220
+
221
+# TODO Negative image sizes aren't handled correctly, but this is a problem
222
+# with QAPI's implementation of the 'size' type and affects other commands as
223
+# well. Once this is fixed, we may want to add a test case here.
224
+
225
+# 1. Misaligned image size
226
+# 2. 2^64 - 512
227
+# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
228
+# 4. 2^63 - 512 (generally valid, but with the image header the file will
229
+# exceed 63 bits)
230
+# 5. 2^52 (512 bytes more than maximum image size)
231
+
232
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
233
+{ "execute": "qmp_capabilities" }
234
+{ "execute": "x-blockdev-create",
235
+ "arguments": {
236
+ "driver": "$IMGFMT",
237
+ "file": "node0",
238
+ "size": 1234
239
+ }
240
+}
241
+{ "execute": "x-blockdev-create",
242
+ "arguments": {
243
+ "driver": "$IMGFMT",
244
+ "file": "node0",
245
+ "size": 18446744073709551104
246
+ }
247
+}
248
+{ "execute": "x-blockdev-create",
249
+ "arguments": {
250
+ "driver": "$IMGFMT",
251
+ "file": "node0",
252
+ "size": 9223372036854775808
253
+ }
254
+}
255
+{ "execute": "x-blockdev-create",
256
+ "arguments": {
257
+ "driver": "$IMGFMT",
258
+ "file": "node0",
259
+ "size": 9223372036854775296
260
+ }
261
+}
262
+{ "execute": "x-blockdev-create",
263
+ "arguments": {
264
+ "driver": "$IMGFMT",
265
+ "file": "node0",
266
+ "size": 4503599627370497
267
+ }
268
+}
269
+{ "execute": "quit" }
270
+EOF
271
+
272
+echo
273
+echo "=== Invalid cluster size ==="
274
+echo
275
+
276
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
277
+{ "execute": "qmp_capabilities" }
278
+{ "execute": "x-blockdev-create",
279
+ "arguments": {
280
+ "driver": "$IMGFMT",
281
+ "file": "node0",
282
+ "size": 67108864,
283
+ "cluster-size": 1234
284
+ }
285
+}
286
+{ "execute": "x-blockdev-create",
287
+ "arguments": {
288
+ "driver": "$IMGFMT",
289
+ "file": "node0",
290
+ "size": 67108864,
291
+ "cluster-size": 128
292
+ }
293
+}
294
+{ "execute": "x-blockdev-create",
295
+ "arguments": {
296
+ "driver": "$IMGFMT",
297
+ "file": "node0",
298
+ "size": 67108864,
299
+ "cluster-size": 4294967296
300
+ }
301
+}
302
+{ "execute": "x-blockdev-create",
303
+ "arguments": {
304
+ "driver": "$IMGFMT",
305
+ "file": "node0",
306
+ "size": 67108864,
307
+ "cluster-size": 9223372036854775808
308
+ }
309
+}
310
+{ "execute": "x-blockdev-create",
311
+ "arguments": {
312
+ "driver": "$IMGFMT",
313
+ "file": "node0",
314
+ "size": 67108864,
315
+ "cluster-size": 18446744073709551104
316
+ }
317
+}
318
+{ "execute": "x-blockdev-create",
319
+ "arguments": {
320
+ "driver": "$IMGFMT",
321
+ "file": "node0",
322
+ "size": 67108864,
323
+ "cluster-size": 0
324
+ }
325
+}
326
+{ "execute": "x-blockdev-create",
327
+ "arguments": {
328
+ "driver": "$IMGFMT",
329
+ "file": "node0",
330
+ "size": 281474976710656,
331
+ "cluster-size": 512
332
+ }
333
+}
334
+{ "execute": "quit" }
335
+EOF
336
+
337
+
338
+# success, all done
339
+echo "*** done"
340
+rm -f $seq.full
341
+status=0
342
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
343
new file mode 100644
344
index XXXXXXX..XXXXXXX
345
--- /dev/null
346
+++ b/tests/qemu-iotests/212.out
347
@@ -XXX,XX +XXX,XX @@
348
+QA output created by 212
349
+
350
+=== Successful image creation (defaults) ===
351
+
352
+Testing:
353
+QMP_VERSION
354
+{"return": {}}
355
+{"return": {}}
356
+{"return": {}}
357
+{"return": {}}
358
+{"return": {}}
359
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
360
+
361
+image: TEST_DIR/t.IMGFMT
362
+file format: IMGFMT
363
+virtual size: 128M (134217728 bytes)
364
+
365
+=== Successful image creation (explicit defaults) ===
366
+
367
+Testing:
368
+QMP_VERSION
369
+{"return": {}}
370
+{"return": {}}
371
+{"return": {}}
372
+{"return": {}}
373
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
374
+
375
+image: TEST_DIR/t.IMGFMT
376
+file format: IMGFMT
377
+virtual size: 64M (67108864 bytes)
378
+
379
+=== Successful image creation (with non-default options) ===
380
+
381
+Testing:
382
+QMP_VERSION
383
+{"return": {}}
384
+{"return": {}}
385
+{"return": {}}
386
+{"return": {}}
387
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
388
+
389
+image: TEST_DIR/t.IMGFMT
390
+file format: IMGFMT
391
+virtual size: 32M (33554432 bytes)
392
+
393
+=== Invalid BlockdevRef ===
394
+
395
+Testing:
396
+QMP_VERSION
397
+{"return": {}}
398
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
399
+{"return": {}}
400
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
401
+
402
+
403
+=== Zero size ===
404
+
405
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
406
+QMP_VERSION
407
+{"return": {}}
408
+{"return": {}}
409
+{"return": {}}
410
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
411
+
412
+image: TEST_DIR/t.IMGFMT
413
+file format: IMGFMT
414
+virtual size: 0 (0 bytes)
415
+
416
+=== Maximum size ===
417
+
418
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
419
+QMP_VERSION
420
+{"return": {}}
421
+{"return": {}}
422
+{"return": {}}
423
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
424
+
425
+image: TEST_DIR/t.IMGFMT
426
+file format: IMGFMT
427
+virtual size: 4096T (4503599627369984 bytes)
428
+
429
+=== Invalid sizes ===
430
+
431
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
432
+QMP_VERSION
433
+{"return": {}}
434
+{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
435
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
436
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
437
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
438
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
439
+{"return": {}}
440
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
441
+
442
+
443
+=== Invalid cluster size ===
444
+
445
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
446
+QMP_VERSION
447
+{"return": {}}
448
+{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
449
+{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
450
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
451
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
452
+{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
453
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
454
+{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
455
+{"return": {}}
456
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
457
+
458
+*** done
459
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
12
index XXXXXXX..XXXXXXX 100644
460
index XXXXXXX..XXXXXXX 100644
13
--- a/qemu-img.texi
461
--- a/tests/qemu-iotests/group
14
+++ b/qemu-img.texi
462
+++ b/tests/qemu-iotests/group
15
@@ -XXX,XX +XXX,XX @@ exclusive with the @var{-O} parameters. It is currently required to also use
463
@@ -XXX,XX +XXX,XX @@
16
the @var{-n} parameter to skip image creation. This restriction may be relaxed
464
209 rw auto quick
17
in a future release.
465
210 rw auto
18
466
211 rw auto quick
19
+@item --force-share (-U)
467
+212 rw auto quick
20
+
21
+If specified, @code{qemu-img} will open the image with shared permissions,
22
+which makes it less likely to conflict with a running guest's permissions due
23
+to image locking. For example, this can be used to get the image information
24
+(with 'info' subcommand) when the image is used by a running guest. Note that
25
+this could produce inconsistent results because of concurrent metadata changes,
26
+etc. This option is only allowed when opening images in read-only mode.
27
+
28
@item fmt
29
is the disk image format. It is guessed automatically in most cases. See below
30
for a description of the supported disk formats.
31
--
468
--
32
2.13.6
469
2.13.6
33
470
34
471
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
Images with a non-power-of-two block size are invalid and cannot be
2
opened. Reject such block sizes when creating an image.
2
3
3
VPC has some difficulty creating geometries of particular size.
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
However, we can indeed force it to use a literal one, so let's
5
Reviewed-by: Eric Blake <eblake@redhat.com>
5
do that for the sake of test 197, which is testing some specific
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
6
offsets.
7
---
8
block/vhdx.c | 4 ++++
9
1 file changed, 4 insertions(+)
7
10
8
Signed-off-by: John Snow <jsnow@redhat.com>
11
diff --git a/block/vhdx.c b/block/vhdx.c
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Lukáš Doktor <ldoktor@redhat.com>
13
---
14
tests/qemu-iotests/197 | 4 ++++
15
tests/qemu-iotests/common.filter | 3 ++-
16
2 files changed, 6 insertions(+), 1 deletion(-)
17
18
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/197
21
+++ b/tests/qemu-iotests/197
22
@@ -XXX,XX +XXX,XX @@ echo '=== Copy-on-read ==='
23
echo
24
25
# Prep the images
26
+# VPC rounds image sizes to a specific geometry, force a specific size.
27
+if [ "$IMGFMT" = "vpc" ]; then
28
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
29
+fi
30
_make_test_img 4G
31
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
32
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
33
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
34
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/common.filter
13
--- a/block/vhdx.c
36
+++ b/tests/qemu-iotests/common.filter
14
+++ b/block/vhdx.c
37
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
38
-e "s# log_size=[0-9]\\+##g" \
16
error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
39
-e "s# refcount_bits=[0-9]\\+##g" \
17
return -EINVAL;
40
-e "s# key-secret=[a-zA-Z0-9]\\+##g" \
18
}
41
- -e "s# iter-time=[0-9]\\+##g"
19
+ if (!is_power_of_2(block_size)) {
42
+ -e "s# iter-time=[0-9]\\+##g" \
20
+ error_setg(errp, "Block size must be a power of two");
43
+ -e "s# force_size=\\(on\\|off\\)##g"
21
+ return -EINVAL;
44
}
22
+ }
45
23
if (block_size > VHDX_BLOCK_SIZE_MAX) {
46
_filter_img_info()
24
error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
25
VHDX_BLOCK_SIZE_MAX);
47
--
26
--
48
2.13.6
27
2.13.6
49
28
50
29
diff view generated by jsdifflib
1
Drain requests are propagated to child nodes, parent nodes and directly
1
error_setg_errno() is meant for cases where we got an errno from the OS
2
to the AioContext. The order in which this happened was different
2
that can add useful extra information to an error message. It's
3
between all combinations of drain/drain_all and begin/end.
3
pointless if we pass a constant errno, these cases should use plain
4
4
error_setg().
5
The correct order is to keep children only drained when their parents
6
are also drained. This means that at the start of a drained section, the
7
AioContext needs to be drained first, the parents second and only then
8
the children. The correct order for the end of a drained section is the
9
opposite.
10
11
This patch changes the three other functions to follow the example of
12
bdrv_drained_begin(), which is the only one that got it right.
13
5
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
16
---
9
---
17
block/io.c | 12 ++++++++----
10
block/vhdx.c | 9 ++++-----
18
1 file changed, 8 insertions(+), 4 deletions(-)
11
1 file changed, 4 insertions(+), 5 deletions(-)
19
12
20
diff --git a/block/io.c b/block/io.c
13
diff --git a/block/vhdx.c b/block/vhdx.c
21
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
22
--- a/block/io.c
15
--- a/block/vhdx.c
23
+++ b/block/io.c
16
+++ b/block/vhdx.c
24
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
25
return;
18
/* Validate options and set default values */
19
image_size = vhdx_opts->size;
20
if (image_size > VHDX_MAX_IMAGE_SIZE) {
21
- error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
22
+ error_setg(errp, "Image size too large; max of 64TB");
23
return -EINVAL;
26
}
24
}
27
25
28
+ /* Stop things in parent-to-child order */
26
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
29
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
27
log_size = vhdx_opts->log_size;
30
aio_disable_external(bdrv_get_aio_context(bs));
31
bdrv_parent_drained_begin(bs);
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
33
return;
34
}
28
}
35
29
if (log_size < MiB || (log_size % MiB) != 0) {
36
- bdrv_parent_drained_end(bs);
30
- error_setg_errno(errp, EINVAL, "Log size must be a multiple of 1 MB");
37
+ /* Re-enable things in child-to-parent order */
31
+ error_setg(errp, "Log size must be a multiple of 1 MB");
38
bdrv_drain_invoke(bs, false);
32
return -EINVAL;
39
+ bdrv_parent_drained_end(bs);
40
aio_enable_external(bdrv_get_aio_context(bs));
41
}
42
43
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
44
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
45
AioContext *aio_context = bdrv_get_aio_context(bs);
46
47
+ /* Stop things in parent-to-child order */
48
aio_context_acquire(aio_context);
49
- bdrv_parent_drained_begin(bs);
50
aio_disable_external(aio_context);
51
+ bdrv_parent_drained_begin(bs);
52
bdrv_drain_invoke(bs, true);
53
aio_context_release(aio_context);
54
55
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
56
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
57
AioContext *aio_context = bdrv_get_aio_context(bs);
58
59
+ /* Re-enable things in child-to-parent order */
60
aio_context_acquire(aio_context);
61
- aio_enable_external(aio_context);
62
- bdrv_parent_drained_end(bs);
63
bdrv_drain_invoke(bs, false);
64
+ bdrv_parent_drained_end(bs);
65
+ aio_enable_external(aio_context);
66
aio_context_release(aio_context);
67
}
33
}
34
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
36
}
37
38
if (block_size < MiB || (block_size % MiB) != 0) {
39
- error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
40
+ error_setg(errp, "Block size must be a multiple of 1 MB");
41
return -EINVAL;
42
}
43
if (!is_power_of_2(block_size)) {
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
45
return -EINVAL;
46
}
47
if (block_size > VHDX_BLOCK_SIZE_MAX) {
48
- error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
49
- VHDX_BLOCK_SIZE_MAX);
50
+ error_setg(errp, "Block size must not exceed %d", VHDX_BLOCK_SIZE_MAX);
51
return -EINVAL;
52
}
68
53
69
--
54
--
70
2.13.6
55
2.13.6
71
56
72
57
diff view generated by jsdifflib
1
Now that the bdrv_drain_invoke() calls are pulled up to the callers of
1
It's unclear what the real maximum is, but we use an uint32_t to store
2
bdrv_drain_recurse(), the 'begin' parameter isn't needed any more.
2
the log size in vhdx_co_create(), so we should check that the given
3
value fits in 32 bits.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
6
---
8
---
7
block/io.c | 12 ++++++------
9
block/vhdx.c | 4 ++++
8
1 file changed, 6 insertions(+), 6 deletions(-)
10
1 file changed, 4 insertions(+)
9
11
10
diff --git a/block/io.c b/block/io.c
12
diff --git a/block/vhdx.c b/block/vhdx.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/block/io.c
14
--- a/block/vhdx.c
13
+++ b/block/io.c
15
+++ b/block/vhdx.c
14
@@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
16
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
17
if (!vhdx_opts->has_log_size) {
18
log_size = DEFAULT_LOG_SIZE;
19
} else {
20
+ if (vhdx_opts->log_size > UINT32_MAX) {
21
+ error_setg(errp, "Log size must be smaller than 4 GB");
22
+ return -EINVAL;
23
+ }
24
log_size = vhdx_opts->log_size;
15
}
25
}
16
}
26
if (log_size < MiB || (log_size % MiB) != 0) {
17
18
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
19
+static bool bdrv_drain_recurse(BlockDriverState *bs)
20
{
21
BdrvChild *child, *tmp;
22
bool waited;
23
@@ -XXX,XX +XXX,XX @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
24
*/
25
bdrv_ref(bs);
26
}
27
- waited |= bdrv_drain_recurse(bs, begin);
28
+ waited |= bdrv_drain_recurse(bs);
29
if (in_main_loop) {
30
bdrv_unref(bs);
31
}
32
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_begin(BlockDriverState *bs)
33
}
34
35
bdrv_drain_invoke(bs, true);
36
- bdrv_drain_recurse(bs, true);
37
+ bdrv_drain_recurse(bs);
38
}
39
40
void bdrv_drained_end(BlockDriverState *bs)
41
@@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs)
42
43
bdrv_parent_drained_end(bs);
44
bdrv_drain_invoke(bs, false);
45
- bdrv_drain_recurse(bs, false);
46
+ bdrv_drain_recurse(bs);
47
aio_enable_external(bdrv_get_aio_context(bs));
48
}
49
50
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
51
aio_context_acquire(aio_context);
52
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
53
if (aio_context == bdrv_get_aio_context(bs)) {
54
- waited |= bdrv_drain_recurse(bs, true);
55
+ waited |= bdrv_drain_recurse(bs);
56
}
57
}
58
aio_context_release(aio_context);
59
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void)
60
aio_enable_external(aio_context);
61
bdrv_parent_drained_end(bs);
62
bdrv_drain_invoke(bs, false);
63
- bdrv_drain_recurse(bs, false);
64
+ bdrv_drain_recurse(bs);
65
aio_context_release(aio_context);
66
}
67
68
--
27
--
69
2.13.6
28
2.13.6
70
29
71
30
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
2
3
Convert nvme_init() to realize and rename it to nvme_realize().
4
5
Cc: John Snow <jsnow@redhat.com>
6
Cc: Keith Busch <keith.busch@intel.com>
7
Cc: Kevin Wolf <kwolf@redhat.com>
8
Cc: Max Reitz <mreitz@redhat.com>
9
Cc: Markus Armbruster <armbru@redhat.com>
10
11
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
2
---
14
hw/block/nvme.c | 18 ++++++++++--------
3
tests/qemu-iotests/213 | 349 +++++++++++++++++++++++++++++++++++++++++++++
15
1 file changed, 10 insertions(+), 8 deletions(-)
4
tests/qemu-iotests/213.out | 121 ++++++++++++++++
5
tests/qemu-iotests/group | 1 +
6
3 files changed, 471 insertions(+)
7
create mode 100755 tests/qemu-iotests/213
8
create mode 100644 tests/qemu-iotests/213.out
16
9
17
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
10
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
11
new file mode 100755
12
index XXXXXXX..XXXXXXX
13
--- /dev/null
14
+++ b/tests/qemu-iotests/213
15
@@ -XXX,XX +XXX,XX @@
16
+#!/bin/bash
17
+#
18
+# Test vhdx and file image creation
19
+#
20
+# Copyright (C) 2018 Red Hat, Inc.
21
+#
22
+# This program is free software; you can redistribute it and/or modify
23
+# it under the terms of the GNU General Public License as published by
24
+# the Free Software Foundation; either version 2 of the License, or
25
+# (at your option) any later version.
26
+#
27
+# This program is distributed in the hope that it will be useful,
28
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
29
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
+# GNU General Public License for more details.
31
+#
32
+# You should have received a copy of the GNU General Public License
33
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
+#
35
+
36
+# creator
37
+owner=kwolf@redhat.com
38
+
39
+seq=`basename $0`
40
+echo "QA output created by $seq"
41
+
42
+here=`pwd`
43
+status=1    # failure is the default!
44
+
45
+# get standard environment, filters and checks
46
+. ./common.rc
47
+. ./common.filter
48
+
49
+_supported_fmt vhdx
50
+_supported_proto file
51
+_supported_os Linux
52
+
53
+function do_run_qemu()
54
+{
55
+ echo Testing: "$@"
56
+ $QEMU -nographic -qmp stdio -serial none "$@"
57
+ echo
58
+}
59
+
60
+function run_qemu()
61
+{
62
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
63
+ | _filter_qemu | _filter_imgfmt \
64
+ | _filter_actual_image_size
65
+}
66
+
67
+echo
68
+echo "=== Successful image creation (defaults) ==="
69
+echo
70
+
71
+size=$((128 * 1024 * 1024))
72
+
73
+run_qemu <<EOF
74
+{ "execute": "qmp_capabilities" }
75
+{ "execute": "x-blockdev-create",
76
+ "arguments": {
77
+ "driver": "file",
78
+ "filename": "$TEST_IMG",
79
+ "size": 0
80
+ }
81
+}
82
+{ "execute": "blockdev-add",
83
+ "arguments": {
84
+ "driver": "file",
85
+ "node-name": "imgfile",
86
+ "filename": "$TEST_IMG"
87
+ }
88
+}
89
+{ "execute": "x-blockdev-create",
90
+ "arguments": {
91
+ "driver": "$IMGFMT",
92
+ "file": "imgfile",
93
+ "size": $size
94
+ }
95
+}
96
+{ "execute": "quit" }
97
+EOF
98
+
99
+_img_info --format-specific | _filter_img_info --format-specific
100
+
101
+echo
102
+echo "=== Successful image creation (explicit defaults) ==="
103
+echo
104
+
105
+# Choose a different size to show that we got a new image
106
+size=$((64 * 1024 * 1024))
107
+
108
+run_qemu <<EOF
109
+{ "execute": "qmp_capabilities" }
110
+{ "execute": "x-blockdev-create",
111
+ "arguments": {
112
+ "driver": "file",
113
+ "filename": "$TEST_IMG",
114
+ "size": 0
115
+ }
116
+}
117
+{ "execute": "x-blockdev-create",
118
+ "arguments": {
119
+ "driver": "$IMGFMT",
120
+ "file": {
121
+ "driver": "file",
122
+ "filename": "$TEST_IMG"
123
+ },
124
+ "size": $size,
125
+ "log-size": 1048576,
126
+ "block-size": 8388608,
127
+ "subformat": "dynamic",
128
+ "block-state-zero": true
129
+ }
130
+}
131
+{ "execute": "quit" }
132
+EOF
133
+
134
+_img_info --format-specific | _filter_img_info --format-specific
135
+
136
+echo
137
+echo "=== Successful image creation (with non-default options) ==="
138
+echo
139
+
140
+# Choose a different size to show that we got a new image
141
+size=$((32 * 1024 * 1024))
142
+
143
+run_qemu <<EOF
144
+{ "execute": "qmp_capabilities" }
145
+{ "execute": "x-blockdev-create",
146
+ "arguments": {
147
+ "driver": "file",
148
+ "filename": "$TEST_IMG",
149
+ "size": 0
150
+ }
151
+}
152
+{ "execute": "x-blockdev-create",
153
+ "arguments": {
154
+ "driver": "$IMGFMT",
155
+ "file": {
156
+ "driver": "file",
157
+ "filename": "$TEST_IMG"
158
+ },
159
+ "size": $size,
160
+ "log-size": 8388608,
161
+ "block-size": 268435456,
162
+ "subformat": "fixed",
163
+ "block-state-zero": false
164
+ }
165
+}
166
+{ "execute": "quit" }
167
+EOF
168
+
169
+_img_info --format-specific | _filter_img_info --format-specific
170
+
171
+echo
172
+echo "=== Invalid BlockdevRef ==="
173
+echo
174
+
175
+run_qemu <<EOF
176
+{ "execute": "qmp_capabilities" }
177
+{ "execute": "x-blockdev-create",
178
+ "arguments": {
179
+ "driver": "$IMGFMT",
180
+ "file": "this doesn't exist",
181
+ "size": $size
182
+ }
183
+}
184
+{ "execute": "quit" }
185
+EOF
186
+
187
+echo
188
+echo "=== Zero size ==="
189
+echo
190
+
191
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
192
+{ "execute": "qmp_capabilities" }
193
+{ "execute": "x-blockdev-create",
194
+ "arguments": {
195
+ "driver": "$IMGFMT",
196
+ "file": "node0",
197
+ "size": 0
198
+ }
199
+}
200
+{ "execute": "quit" }
201
+EOF
202
+
203
+_img_info | _filter_img_info
204
+
205
+echo
206
+echo "=== Maximum size ==="
207
+echo
208
+
209
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
210
+{ "execute": "qmp_capabilities" }
211
+{ "execute": "x-blockdev-create",
212
+ "arguments": {
213
+ "driver": "$IMGFMT",
214
+ "file": "node0",
215
+ "size": 70368744177664
216
+ }
217
+}
218
+{ "execute": "quit" }
219
+EOF
220
+
221
+_img_info | _filter_img_info
222
+
223
+echo
224
+echo "=== Invalid sizes ==="
225
+echo
226
+
227
+# TODO Negative image sizes aren't handled correctly, but this is a problem
228
+# with QAPI's implementation of the 'size' type and affects other commands as
229
+# well. Once this is fixed, we may want to add a test case here.
230
+
231
+# 1. 2^64 - 512
232
+# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
233
+# 3. 2^63 - 512 (generally valid, but with the image header the file will
234
+# exceed 63 bits)
235
+# 4. 2^46 + 1 (one byte more than maximum image size)
236
+
237
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
238
+{ "execute": "qmp_capabilities" }
239
+{ "execute": "x-blockdev-create",
240
+ "arguments": {
241
+ "driver": "$IMGFMT",
242
+ "file": "node0",
243
+ "size": 18446744073709551104
244
+ }
245
+}
246
+{ "execute": "x-blockdev-create",
247
+ "arguments": {
248
+ "driver": "$IMGFMT",
249
+ "file": "node0",
250
+ "size": 9223372036854775808
251
+ }
252
+}
253
+{ "execute": "x-blockdev-create",
254
+ "arguments": {
255
+ "driver": "$IMGFMT",
256
+ "file": "node0",
257
+ "size": 9223372036854775296
258
+ }
259
+}
260
+{ "execute": "x-blockdev-create",
261
+ "arguments": {
262
+ "driver": "$IMGFMT",
263
+ "file": "node0",
264
+ "size": 70368744177665
265
+ }
266
+}
267
+{ "execute": "quit" }
268
+EOF
269
+
270
+echo
271
+echo "=== Invalid block size ==="
272
+echo
273
+
274
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
275
+{ "execute": "qmp_capabilities" }
276
+{ "execute": "x-blockdev-create",
277
+ "arguments": {
278
+ "driver": "$IMGFMT",
279
+ "file": "node0",
280
+ "size": 67108864,
281
+ "block-size": 1234567
282
+ }
283
+}
284
+{ "execute": "x-blockdev-create",
285
+ "arguments": {
286
+ "driver": "$IMGFMT",
287
+ "file": "node0",
288
+ "size": 67108864,
289
+ "block-size": 128
290
+ }
291
+}
292
+{ "execute": "x-blockdev-create",
293
+ "arguments": {
294
+ "driver": "$IMGFMT",
295
+ "file": "node0",
296
+ "size": 67108864,
297
+ "block-size": 3145728
298
+ }
299
+}
300
+{ "execute": "x-blockdev-create",
301
+ "arguments": {
302
+ "driver": "$IMGFMT",
303
+ "file": "node0",
304
+ "size": 67108864,
305
+ "block-size": 536870912
306
+ }
307
+}
308
+{ "execute": "x-blockdev-create",
309
+ "arguments": {
310
+ "driver": "$IMGFMT",
311
+ "file": "node0",
312
+ "size": 67108864,
313
+ "block-size": 0
314
+ }
315
+}
316
+{ "execute": "quit" }
317
+EOF
318
+
319
+echo
320
+echo "=== Invalid log size ==="
321
+echo
322
+
323
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
324
+{ "execute": "qmp_capabilities" }
325
+{ "execute": "x-blockdev-create",
326
+ "arguments": {
327
+ "driver": "$IMGFMT",
328
+ "file": "node0",
329
+ "size": 67108864,
330
+ "log-size": 1234567
331
+ }
332
+}
333
+{ "execute": "x-blockdev-create",
334
+ "arguments": {
335
+ "driver": "$IMGFMT",
336
+ "file": "node0",
337
+ "size": 67108864,
338
+ "log-size": 128
339
+ }
340
+}
341
+{ "execute": "x-blockdev-create",
342
+ "arguments": {
343
+ "driver": "$IMGFMT",
344
+ "file": "node0",
345
+ "size": 67108864,
346
+ "log-size": 4294967296
347
+ }
348
+}
349
+{ "execute": "x-blockdev-create",
350
+ "arguments": {
351
+ "driver": "$IMGFMT",
352
+ "file": "node0",
353
+ "size": 67108864,
354
+ "log-size": 0
355
+ }
356
+}
357
+{ "execute": "quit" }
358
+EOF
359
+
360
+
361
+# success, all done
362
+echo "*** done"
363
+rm -f $seq.full
364
+status=0
365
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
366
new file mode 100644
367
index XXXXXXX..XXXXXXX
368
--- /dev/null
369
+++ b/tests/qemu-iotests/213.out
370
@@ -XXX,XX +XXX,XX @@
371
+QA output created by 213
372
+
373
+=== Successful image creation (defaults) ===
374
+
375
+Testing:
376
+QMP_VERSION
377
+{"return": {}}
378
+{"return": {}}
379
+{"return": {}}
380
+{"return": {}}
381
+{"return": {}}
382
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
383
+
384
+image: TEST_DIR/t.IMGFMT
385
+file format: IMGFMT
386
+virtual size: 128M (134217728 bytes)
387
+
388
+=== Successful image creation (explicit defaults) ===
389
+
390
+Testing:
391
+QMP_VERSION
392
+{"return": {}}
393
+{"return": {}}
394
+{"return": {}}
395
+{"return": {}}
396
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
397
+
398
+image: TEST_DIR/t.IMGFMT
399
+file format: IMGFMT
400
+virtual size: 64M (67108864 bytes)
401
+
402
+=== Successful image creation (with non-default options) ===
403
+
404
+Testing:
405
+QMP_VERSION
406
+{"return": {}}
407
+{"return": {}}
408
+{"return": {}}
409
+{"return": {}}
410
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
411
+
412
+image: TEST_DIR/t.IMGFMT
413
+file format: IMGFMT
414
+virtual size: 32M (33554432 bytes)
415
+
416
+=== Invalid BlockdevRef ===
417
+
418
+Testing:
419
+QMP_VERSION
420
+{"return": {}}
421
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
422
+{"return": {}}
423
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
424
+
425
+
426
+=== Zero size ===
427
+
428
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
429
+QMP_VERSION
430
+{"return": {}}
431
+{"return": {}}
432
+{"return": {}}
433
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
434
+
435
+image: TEST_DIR/t.IMGFMT
436
+file format: IMGFMT
437
+virtual size: 0 (0 bytes)
438
+
439
+=== Maximum size ===
440
+
441
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
442
+QMP_VERSION
443
+{"return": {}}
444
+{"return": {}}
445
+{"return": {}}
446
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
447
+
448
+image: TEST_DIR/t.IMGFMT
449
+file format: IMGFMT
450
+virtual size: 64T (70368744177664 bytes)
451
+
452
+=== Invalid sizes ===
453
+
454
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
455
+QMP_VERSION
456
+{"return": {}}
457
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
458
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
459
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
460
+{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
461
+{"return": {}}
462
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
463
+
464
+
465
+=== Invalid block size ===
466
+
467
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
468
+QMP_VERSION
469
+{"return": {}}
470
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
471
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
472
+{"error": {"class": "GenericError", "desc": "Block size must be a power of two"}}
473
+{"error": {"class": "GenericError", "desc": "Block size must not exceed 268435456"}}
474
+{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
475
+{"return": {}}
476
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
477
+
478
+
479
+=== Invalid log size ===
480
+
481
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
482
+QMP_VERSION
483
+{"return": {}}
484
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
485
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
486
+{"error": {"class": "GenericError", "desc": "Log size must be smaller than 4 GB"}}
487
+{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
488
+{"return": {}}
489
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
490
+
491
+*** done
492
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
18
index XXXXXXX..XXXXXXX 100644
493
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/nvme.c
494
--- a/tests/qemu-iotests/group
20
+++ b/hw/block/nvme.c
495
+++ b/tests/qemu-iotests/group
21
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps nvme_cmb_ops = {
496
@@ -XXX,XX +XXX,XX @@
22
},
497
210 rw auto
23
};
498
211 rw auto quick
24
499
212 rw auto quick
25
-static int nvme_init(PCIDevice *pci_dev)
500
+213 rw auto quick
26
+static void nvme_realize(PCIDevice *pci_dev, Error **errp)
27
{
28
NvmeCtrl *n = NVME(pci_dev);
29
NvmeIdCtrl *id = &n->id_ctrl;
30
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
31
Error *local_err = NULL;
32
33
if (!n->conf.blk) {
34
- return -1;
35
+ error_setg(errp, "drive property not set");
36
+ return;
37
}
38
39
bs_size = blk_getlength(n->conf.blk);
40
if (bs_size < 0) {
41
- return -1;
42
+ error_setg(errp, "could not get backing file size");
43
+ return;
44
}
45
46
blkconf_serial(&n->conf, &n->serial);
47
if (!n->serial) {
48
- return -1;
49
+ error_setg(errp, "serial property not set");
50
+ return;
51
}
52
blkconf_blocksizes(&n->conf);
53
blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
54
false, &local_err);
55
if (local_err) {
56
- error_report_err(local_err);
57
- return -1;
58
+ error_propagate(errp, local_err);
59
+ return;
60
}
61
62
pci_conf = pci_dev->config;
63
@@ -XXX,XX +XXX,XX @@ static int nvme_init(PCIDevice *pci_dev)
64
cpu_to_le64(n->ns_size >>
65
id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds);
66
}
67
- return 0;
68
}
69
70
static void nvme_exit(PCIDevice *pci_dev)
71
@@ -XXX,XX +XXX,XX @@ static void nvme_class_init(ObjectClass *oc, void *data)
72
DeviceClass *dc = DEVICE_CLASS(oc);
73
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
74
75
- pc->init = nvme_init;
76
+ pc->realize = nvme_realize;
77
pc->exit = nvme_exit;
78
pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
79
pc->vendor_id = PCI_VENDOR_ID_INTEL;
80
--
501
--
81
2.13.6
502
2.13.6
82
503
83
504
diff view generated by jsdifflib