1
The following changes since commit ad1b4ec39caa5b3f17cbd8160283a03a3dcfe2ae:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/kraxel/tags/input-20180515-pull-request' into staging (2018-05-15 12:50:06 +0100)
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 1fce860ea5eba1ca00a67911fc0b8a5d80009514:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-05-15' into queue-block (2018-05-15 16:19:53 +0200)
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- Switch AIO/callback based block drivers to a byte-based interface
16
- Fix resize (extending) of short overlays
17
- Block jobs: Expose error string via query-block-jobs
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- Block job cleanups and fixes
18
- qemu-storage-daemon: Fix non-string --object properties
19
- hmp: Allow using a qdev id in block_set_io_throttle
19
20
- Copy-on-read block driver
21
- The qcow2 default refcount cache size has been decreased
22
- Various bug fixes
23
----------------------------------------------------------------
20
----------------------------------------------------------------
24
Alberto Garcia (5):
21
Alberto Garcia (1):
25
hmp: Allow using a qdev id in block_set_io_throttle
22
qcow2: Add incompatibility note between backing files and raw external data files
26
Fix error message about compressed clusters with OFLAG_COPIED
27
specs/qcow2: Clarify that compressed clusters have the COPIED bit reset
28
qcow2: Give the refcount cache the minimum possible size by default
29
docs: Document the new default sizes of the qcow2 caches
30
23
31
Daniel Henrique Barboza (1):
24
Andrzej Jakowski (1):
32
block-backend: simplify blk_get_aio_context
25
nvme: introduce PMR support from NVMe 1.4 spec
33
26
34
Eric Blake (7):
27
Kevin Wolf (12):
35
block: Support byte-based aio callbacks
28
block: Add flags to BlockDriver.bdrv_co_truncate()
36
file-win32: Switch to byte-based callbacks
29
block: Add flags to bdrv(_co)_truncate()
37
null: Switch to byte-based read/write
30
block-backend: Add flags to blk_truncate()
38
rbd: Switch to byte-based callbacks
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
39
vxhs: Switch to byte-based callbacks
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
40
block: Drop last of the sector-based aio callbacks
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
41
block: Merge .bdrv_co_writev{,_flags} in drivers
34
block: truncate: Don't make backing file data visible
35
iotests: Filter testfiles out in filter_img_info()
36
iotests: Test committing to short backing file
37
qcow2: Forward ZERO_WRITE flag for full preallocation
38
qom: Factor out user_creatable_add_dict()
39
qemu-storage-daemon: Fix non-string --object properties
42
40
43
John Snow (1):
41
Paolo Bonzini (1):
44
blockjob: expose error string via query
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
45
43
46
Kevin Wolf (7):
44
docs/interop/qcow2.txt | 3 +
47
blockjob: Fix assertion in block_job_finalize()
45
hw/block/nvme.h | 2 +
48
blockjob: Wrappers for progress counter access
46
include/block/block.h | 5 +-
49
blockjob: Move RateLimit to BlockJob
47
include/block/block_int.h | 10 +-
50
blockjob: Implement block_job_set_speed() centrally
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
51
blockjob: Introduce block_job_ratelimit_get_delay()
49
include/qom/object_interfaces.h | 16 +++
52
blockjob: Add block_job_driver()
50
include/sysemu/block-backend.h | 2 +-
53
Merge remote-tracking branch 'mreitz/tags/pull-block-2018-05-15' into queue-block
51
block.c | 3 +-
52
block/block-backend.c | 4 +-
53
block/commit.c | 4 +-
54
block/crypto.c | 7 +-
55
block/file-posix.c | 6 +-
56
block/file-win32.c | 2 +-
57
block/gluster.c | 1 +
58
block/io.c | 43 ++++++-
59
block/iscsi.c | 2 +-
60
block/mirror.c | 2 +-
61
block/nfs.c | 3 +-
62
block/parallels.c | 6 +-
63
block/qcow.c | 4 +-
64
block/qcow2-cluster.c | 2 +-
65
block/qcow2-refcount.c | 2 +-
66
block/qcow2.c | 73 +++++++++--
67
block/qed.c | 3 +-
68
block/raw-format.c | 6 +-
69
block/rbd.c | 1 +
70
block/sheepdog.c | 4 +-
71
block/ssh.c | 2 +-
72
block/vdi.c | 2 +-
73
block/vhdx-log.c | 2 +-
74
block/vhdx.c | 6 +-
75
block/vmdk.c | 8 +-
76
block/vpc.c | 2 +-
77
blockdev.c | 2 +-
78
hw/block/nvme.c | 109 ++++++++++++++++
79
qemu-img.c | 2 +-
80
qemu-io-cmds.c | 2 +-
81
qemu-storage-daemon.c | 4 +-
82
qom/object_interfaces.c | 31 +++++
83
qom/qom-qmp-cmds.c | 24 +---
84
tests/test-block-iothread.c | 9 +-
85
tests/qemu-iotests/iotests.py | 5 +-
86
hw/block/Makefile.objs | 2 +-
87
hw/block/trace-events | 4 +
88
tests/qemu-iotests/244 | 10 +-
89
tests/qemu-iotests/244.out | 9 +-
90
tests/qemu-iotests/274 | 155 +++++++++++++++++++++++
91
tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++
92
tests/qemu-iotests/group | 1 +
93
49 files changed, 951 insertions(+), 96 deletions(-)
94
create mode 100755 tests/qemu-iotests/274
95
create mode 100644 tests/qemu-iotests/274.out
54
96
55
Max Reitz (17):
56
iotests: Split 214 off of 122
57
iotests: Add failure matching to common.qemu
58
iotests: Skip 181 and 201 without userfaultfd
59
block: Add COR filter driver
60
block: BLK_PERM_WRITE includes ..._UNCHANGED
61
block: Add BDRV_REQ_WRITE_UNCHANGED flag
62
block: Set BDRV_REQ_WRITE_UNCHANGED for COR writes
63
block/quorum: Support BDRV_REQ_WRITE_UNCHANGED
64
block: Support BDRV_REQ_WRITE_UNCHANGED in filters
65
iotests: Clean up wrap image in 197
66
iotests: Copy 197 for COR filter driver
67
iotests: Add test for COR across nodes
68
qemu-img: Check post-truncation size
69
block: Document BDRV_REQ_WRITE_UNCHANGED support
70
qemu-io: Use purely string blockdev options
71
qemu-img: Use only string options in img_open_opts
72
iotests: Add test for -U/force-share conflicts
73
97
74
qapi/block-core.json | 11 ++-
75
docs/interop/qcow2.txt | 8 +-
76
docs/qcow2-cache.txt | 33 ++++----
77
block/qcow2.h | 4 -
78
include/block/block.h | 9 ++-
79
include/block/block_int.h | 28 +++++--
80
include/block/blockjob.h | 32 ++++++++
81
include/block/blockjob_int.h | 11 ++-
82
include/block/raw-aio.h | 2 +-
83
block/backup.c | 62 ++++++---------
84
block/blkdebug.c | 9 ++-
85
block/blkreplay.c | 3 +
86
block/blkverify.c | 3 +
87
block/block-backend.c | 8 +-
88
block/commit.c | 35 +++------
89
block/copy-on-read.c | 173 +++++++++++++++++++++++++++++++++++++++++
90
block/file-win32.c | 47 ++++++-----
91
block/gluster.c | 4 +-
92
block/io.c | 75 ++++++++++--------
93
block/iscsi.c | 8 +-
94
block/mirror.c | 44 ++++-------
95
block/null.c | 45 +++++------
96
block/parallels.c | 4 +-
97
block/qcow.c | 6 +-
98
block/qcow2-refcount.c | 4 +-
99
block/qcow2.c | 31 +++++---
100
block/qed.c | 3 +-
101
block/quorum.c | 19 +++--
102
block/raw-format.c | 9 ++-
103
block/rbd.c | 40 +++++-----
104
block/replication.c | 4 +-
105
block/sheepdog.c | 4 +-
106
block/ssh.c | 4 +-
107
block/stream.c | 33 +++-----
108
block/throttle.c | 6 +-
109
block/vhdx.c | 4 +-
110
block/vxhs.c | 43 +++++-----
111
block/win32-aio.c | 5 +-
112
blockjob.c | 40 +++++++---
113
hmp.c | 14 +++-
114
qemu-img.c | 43 ++++++++--
115
qemu-io.c | 4 +-
116
block/Makefile.objs | 2 +-
117
hmp-commands.hx | 3 +-
118
tests/qemu-iotests/122 | 47 -----------
119
tests/qemu-iotests/122.out | 33 --------
120
tests/qemu-iotests/137.out | 2 +-
121
tests/qemu-iotests/153 | 17 ++++
122
tests/qemu-iotests/153.out | 16 ++++
123
tests/qemu-iotests/181 | 13 ++++
124
tests/qemu-iotests/197 | 1 +
125
tests/qemu-iotests/201 | 13 ++++
126
tests/qemu-iotests/214 | 97 +++++++++++++++++++++++
127
tests/qemu-iotests/214.out | 35 +++++++++
128
tests/qemu-iotests/215 | 120 ++++++++++++++++++++++++++++
129
tests/qemu-iotests/215.out | 26 +++++++
130
tests/qemu-iotests/216 | 115 +++++++++++++++++++++++++++
131
tests/qemu-iotests/216.out | 28 +++++++
132
tests/qemu-iotests/common.qemu | 58 ++++++++++++--
133
tests/qemu-iotests/group | 3 +
134
60 files changed, 1174 insertions(+), 429 deletions(-)
135
create mode 100644 block/copy-on-read.c
136
create mode 100755 tests/qemu-iotests/214
137
create mode 100644 tests/qemu-iotests/214.out
138
create mode 100755 tests/qemu-iotests/215
139
create mode 100644 tests/qemu-iotests/215.out
140
create mode 100755 tests/qemu-iotests/216
141
create mode 100644 tests/qemu-iotests/216.out
142
diff view generated by jsdifflib
Deleted patch
1
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
2
1
3
blk_get_aio_context verifies if BlockDriverState bs is not NULL,
4
return bdrv_get_aio_context(bs) if true or qemu_get_aio_context()
5
otherwise. However, bdrv_get_aio_context from block.c already does
6
this verification itself, also returning qemu_get_aio_context()
7
if bs is NULL:
8
9
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
10
{
11
return bs ? bs->aio_context : qemu_get_aio_context();
12
}
13
14
This patch simplifies blk_get_aio_context to simply call
15
bdrv_get_aio_context instead of replicating the same logic.
16
17
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
18
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
21
block/block-backend.c | 8 +-------
22
1 file changed, 1 insertion(+), 7 deletions(-)
23
24
diff --git a/block/block-backend.c b/block/block-backend.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/block-backend.c
27
+++ b/block/block-backend.c
28
@@ -XXX,XX +XXX,XX @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
29
30
AioContext *blk_get_aio_context(BlockBackend *blk)
31
{
32
- BlockDriverState *bs = blk_bs(blk);
33
-
34
- if (bs) {
35
- return bdrv_get_aio_context(bs);
36
- } else {
37
- return qemu_get_aio_context();
38
- }
39
+ return bdrv_get_aio_context(blk_bs(blk));
40
}
41
42
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
43
--
44
2.13.6
45
46
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Compressed clusters are not supposed to have the COPIED bit set, but
3
Backing files and raw external data files are mutually exclusive.
4
this is not made explicit in the specs, so let's document it.
4
The documentation of the raw external data bit (in autoclear_features)
5
already indicates that, but we should also mention it on the other
6
side.
5
7
8
Suggested-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Message-id: 74552e1d6e858d3159cb0c0e188e80bc9248e337.1523376013.git.berto@igalia.com
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
docs/interop/qcow2.txt | 8 ++++----
14
docs/interop/qcow2.txt | 3 +++
12
1 file changed, 4 insertions(+), 4 deletions(-)
15
1 file changed, 3 insertions(+)
13
16
14
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/interop/qcow2.txt
19
--- a/docs/interop/qcow2.txt
17
+++ b/docs/interop/qcow2.txt
20
+++ b/docs/interop/qcow2.txt
18
@@ -XXX,XX +XXX,XX @@ L2 table entry:
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
19
62: 0 for standard clusters
22
is stored (NB: The string is not null terminated). 0 if the
20
1 for compressed clusters
23
image doesn't have a backing file.
21
24
22
- 63: 0 for a cluster that is unused or requires COW, 1 if its
25
+ Note: backing files are incompatible with raw external data
23
- refcount is exactly one. This information is only accurate
26
+ files (auto-clear feature bit 1).
24
- in L2 tables that are reachable from the active L1
27
+
25
- table.
28
16 - 19: backing_file_size
26
+ 63: 0 for clusters that are unused, compressed or require COW.
29
Length of the backing file name in bytes. Must not be
27
+ 1 for standard clusters whose refcount is exactly one.
30
longer than 1023 bytes. Undefined if the image doesn't have
28
+ This information is only accurate in L2 tables
29
+ that are reachable from the active L1 table.
30
31
Standard Cluster Descriptor:
32
33
--
31
--
34
2.13.6
32
2.25.3
35
33
36
34
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
Test 244 checks the expected behavior of qcow2 external data files
4
byte-based. Make the change for the last few sector-based callbacks
4
with respect to zero and discarded clusters. Filesystems however
5
in the vxhs driver.
5
are free to ignore discard requests, and this seems to be the
6
case for overlayfs. Relax the tests to skip checks on the
7
external data file for discarded areas, which implies not using
8
qemu-img compare in the data_file_raw=on case.
6
9
7
Note that the driver was already using byte-based calls for
10
This fixes docker tests on RHEL8.
8
performing actual I/O, so this just gets rid of a round trip
9
of scaling; however, as I don't know if VxHS is tolerant of
10
non-sector AIO operations, I went with the conservative approach
11
of adding .bdrv_refresh_limits to override the block layer
12
defaults back to the pre-patch value of 512.
13
11
14
Signed-off-by: Eric Blake <eblake@redhat.com>
12
Cc: Kevin Wolf <kwolf@redhat.com>
13
Cc: qemu-block@nongnu.org
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
---
17
block/vxhs.c | 43 ++++++++++++++++++++++---------------------
18
tests/qemu-iotests/244 | 10 ++++++++--
18
1 file changed, 22 insertions(+), 21 deletions(-)
19
tests/qemu-iotests/244.out | 9 ++++++---
20
2 files changed, 14 insertions(+), 5 deletions(-)
19
21
20
diff --git a/block/vxhs.c b/block/vxhs.c
22
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/244
25
+++ b/tests/qemu-iotests/244
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
27
echo
28
$QEMU_IO -c 'read -P 0 0 1M' \
29
-c 'read -P 0x11 1M 1M' \
30
- -c 'read -P 0 2M 2M' \
31
-c 'read -P 0x11 4M 1M' \
32
-c 'read -P 0 5M 1M' \
33
-f raw "$TEST_IMG.data" |
34
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
35
-f $IMGFMT "$TEST_IMG" |
36
_filter_qemu_io
37
38
+# Discarded clusters are only marked as such in the qcow2 metadata, but
39
+# they can contain stale data in the external data file. Instead, zero
40
+# clusters must be zeroed in the external data file too.
41
echo
42
-$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
43
+$QEMU_IO -c 'read -P 0 0 1M' \
44
+ -c 'read -P 0x11 1M 1M' \
45
+ -c 'read -P 0 3M 3M' \
46
+ -f raw "$TEST_IMG".data |
47
+ _filter_qemu_io
48
49
echo -n "qcow2 file size after I/O: "
50
du -b $TEST_IMG | cut -f1
51
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
21
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
22
--- a/block/vxhs.c
53
--- a/tests/qemu-iotests/244.out
23
+++ b/block/vxhs.c
54
+++ b/tests/qemu-iotests/244.out
24
@@ -XXX,XX +XXX,XX @@ static void vxhs_parse_filename(const char *filename, QDict *options,
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
25
}
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
26
}
57
read 1048576/1048576 bytes at offset 1048576
27
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
28
+static void vxhs_refresh_limits(BlockDriverState *bs, Error **errp)
59
-read 2097152/2097152 bytes at offset 2097152
29
+{
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
30
+ /* XXX Does VXHS support AIO on less than 512-byte alignment? */
61
read 1048576/1048576 bytes at offset 4194304
31
+ bs->bl.request_alignment = 512;
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
32
+}
63
read 1048576/1048576 bytes at offset 5242880
33
+
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
34
static int vxhs_init_and_ref(void)
65
read 4194304/4194304 bytes at offset 2097152
35
{
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
36
if (vxhs_ref++ == 0) {
67
37
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo vxhs_aiocb_info = {
68
-Images are identical.
38
* and is passed to QNIO. When QNIO completes the work,
69
+read 1048576/1048576 bytes at offset 0
39
* it will be passed back through the callback.
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
40
*/
71
+read 1048576/1048576 bytes at offset 1048576
41
-static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
42
- QEMUIOVector *qiov, int nb_sectors,
73
+read 3145728/3145728 bytes at offset 3145728
43
+static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, uint64_t offset,
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
44
+ QEMUIOVector *qiov, uint64_t size,
75
qcow2 file size after I/O: 327680
45
BlockCompletionFunc *cb, void *opaque,
76
46
VDISKAIOCmd iodir)
77
=== bdrv_co_block_status test for file and offset=0 ===
47
{
48
VXHSAIOCB *acb = NULL;
49
BDRVVXHSState *s = bs->opaque;
50
- size_t size;
51
- uint64_t offset;
52
int iio_flags = 0;
53
int ret = 0;
54
void *dev_handle = s->vdisk_hostinfo.dev_handle;
55
56
- offset = sector_num * BDRV_SECTOR_SIZE;
57
- size = nb_sectors * BDRV_SECTOR_SIZE;
58
acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque);
59
60
/*
61
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
62
switch (iodir) {
63
case VDISK_AIO_WRITE:
64
ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
65
- offset, (uint64_t)size, iio_flags);
66
+ offset, size, iio_flags);
67
break;
68
case VDISK_AIO_READ:
69
ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
70
- offset, (uint64_t)size, iio_flags);
71
+ offset, size, iio_flags);
72
break;
73
default:
74
trace_vxhs_aio_rw_invalid(iodir);
75
@@ -XXX,XX +XXX,XX @@ errout:
76
return NULL;
77
}
78
79
-static BlockAIOCB *vxhs_aio_readv(BlockDriverState *bs,
80
- int64_t sector_num, QEMUIOVector *qiov,
81
- int nb_sectors,
82
+static BlockAIOCB *vxhs_aio_preadv(BlockDriverState *bs,
83
+ uint64_t offset, uint64_t bytes,
84
+ QEMUIOVector *qiov, int flags,
85
BlockCompletionFunc *cb, void *opaque)
86
{
87
- return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
88
- opaque, VDISK_AIO_READ);
89
+ return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_READ);
90
}
91
92
-static BlockAIOCB *vxhs_aio_writev(BlockDriverState *bs,
93
- int64_t sector_num, QEMUIOVector *qiov,
94
- int nb_sectors,
95
- BlockCompletionFunc *cb, void *opaque)
96
+static BlockAIOCB *vxhs_aio_pwritev(BlockDriverState *bs,
97
+ uint64_t offset, uint64_t bytes,
98
+ QEMUIOVector *qiov, int flags,
99
+ BlockCompletionFunc *cb, void *opaque)
100
{
101
- return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors,
102
- cb, opaque, VDISK_AIO_WRITE);
103
+ return vxhs_aio_rw(bs, offset, qiov, bytes, cb, opaque, VDISK_AIO_WRITE);
104
}
105
106
static void vxhs_close(BlockDriverState *bs)
107
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vxhs = {
108
.instance_size = sizeof(BDRVVXHSState),
109
.bdrv_file_open = vxhs_open,
110
.bdrv_parse_filename = vxhs_parse_filename,
111
+ .bdrv_refresh_limits = vxhs_refresh_limits,
112
.bdrv_close = vxhs_close,
113
.bdrv_getlength = vxhs_getlength,
114
- .bdrv_aio_readv = vxhs_aio_readv,
115
- .bdrv_aio_writev = vxhs_aio_writev,
116
+ .bdrv_aio_preadv = vxhs_aio_preadv,
117
+ .bdrv_aio_pwritev = vxhs_aio_pwritev,
118
};
119
120
static void bdrv_vxhs_init(void)
121
--
78
--
122
2.13.6
79
2.25.3
123
80
124
81
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
2
2
driver callbacks, and a supported_truncate_flags field in
3
We have too many driver callback interfaces; simplify the mess
3
BlockDriverState that allows drivers to advertise support for request
4
somewhat by merging the flags parameter of .bdrv_co_writev_flags()
4
flags in the context of truncate.
5
into .bdrv_co_writev(). Note that as long as a driver doesn't set
5
6
.supported_write_flags, the flags argument will be 0 and behavior is
6
For now, we always pass 0 and no drivers declare support for any flag.
7
identical. Also note that the public function bdrv_co_writev() still
7
8
lacks a flags argument; so the driver signature is thus intentionally
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
slightly different. But that's not the end of the world, nor the first
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
time that the driver interface differs slightly from the public
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
interface.
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
Ideally, we should be rewriting all of these drivers to use modern
14
byte-based interfaces. But that's a more invasive patch to write
15
and audit, compared to the simplification done here.
16
17
Signed-off-by: Eric Blake <eblake@redhat.com>
18
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
14
---
21
include/block/block_int.h | 2 --
15
include/block/block_int.h | 10 +++++++++-
22
block/gluster.c | 4 +++-
16
block/crypto.c | 3 ++-
23
block/io.c | 13 ++++---------
17
block/file-posix.c | 2 +-
24
block/iscsi.c | 8 ++++----
18
block/file-win32.c | 2 +-
25
block/parallels.c | 4 +++-
19
block/gluster.c | 1 +
26
block/qcow.c | 6 ++++--
20
block/io.c | 8 +++++++-
27
block/qed.c | 3 ++-
21
block/iscsi.c | 2 +-
28
block/replication.c | 4 +++-
22
block/nfs.c | 3 ++-
29
block/sheepdog.c | 4 +++-
23
block/qcow2.c | 2 +-
30
block/ssh.c | 4 +++-
24
block/qed.c | 1 +
31
block/vhdx.c | 4 +++-
25
block/raw-format.c | 2 +-
32
11 files changed, 32 insertions(+), 24 deletions(-)
26
block/rbd.c | 1 +
27
block/sheepdog.c | 4 ++--
28
block/ssh.c | 2 +-
29
tests/test-block-iothread.c | 3 ++-
30
15 files changed, 33 insertions(+), 13 deletions(-)
33
31
34
diff --git a/include/block/block_int.h b/include/block/block_int.h
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
35
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
36
--- a/include/block/block_int.h
34
--- a/include/block/block_int.h
37
+++ b/include/block/block_int.h
35
+++ b/include/block/block_int.h
38
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
39
int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs,
37
*/
40
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
41
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
39
bool exact, PreallocMode prealloc,
42
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
40
- Error **errp);
43
- int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
41
+ BdrvRequestFlags flags, Error **errp);
44
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
42
45
/**
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
46
* @offset: position in bytes to write at
44
bool has_variable_length;
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
55
+ */
56
+ unsigned int supported_truncate_flags;
57
58
/* the following member gives a name to every node on the bs graph. */
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
63
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
65
66
static int coroutine_fn
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
79
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
81
bool exact, PreallocMode prealloc,
82
- Error **errp)
83
+ BdrvRequestFlags flags, Error **errp)
84
{
85
BDRVRawState *s = bs->opaque;
86
struct stat st;
87
diff --git a/block/file-win32.c b/block/file-win32.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/file-win32.c
90
+++ b/block/file-win32.c
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
92
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
94
bool exact, PreallocMode prealloc,
95
- Error **errp)
96
+ BdrvRequestFlags flags, Error **errp)
97
{
98
BDRVRawState *s = bs->opaque;
99
LONG low, high;
47
diff --git a/block/gluster.c b/block/gluster.c
100
diff --git a/block/gluster.c b/block/gluster.c
48
index XXXXXXX..XXXXXXX 100644
101
index XXXXXXX..XXXXXXX 100644
49
--- a/block/gluster.c
102
--- a/block/gluster.c
50
+++ b/block/gluster.c
103
+++ b/block/gluster.c
51
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
52
static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
105
int64_t offset,
53
int64_t sector_num,
106
bool exact,
54
int nb_sectors,
107
PreallocMode prealloc,
55
- QEMUIOVector *qiov)
108
+ BdrvRequestFlags flags,
56
+ QEMUIOVector *qiov,
109
Error **errp)
57
+ int flags)
110
{
58
{
111
BDRVGlusterState *s = bs->opaque;
59
+ assert(!flags);
60
return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
61
}
62
63
diff --git a/block/io.c b/block/io.c
112
diff --git a/block/io.c b/block/io.c
64
index XXXXXXX..XXXXXXX 100644
113
index XXXXXXX..XXXXXXX 100644
65
--- a/block/io.c
114
--- a/block/io.c
66
+++ b/block/io.c
115
+++ b/block/io.c
67
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
68
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
117
BlockDriverState *bs = child->bs;
69
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
118
BlockDriver *drv = bs->drv;
70
119
BdrvTrackedRequest req;
71
- if (drv->bdrv_co_writev_flags) {
120
+ BdrvRequestFlags flags = 0;
72
- ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
121
int64_t old_size, new_bytes;
73
- flags & bs->supported_write_flags);
122
int ret;
74
- flags &= ~bs->supported_write_flags;
123
75
- } else {
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
76
- assert(drv->bdrv_co_writev);
125
}
77
- assert(!bs->supported_write_flags);
126
78
- ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
127
if (drv->bdrv_co_truncate) {
79
- }
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
80
+ assert(drv->bdrv_co_writev);
129
+ if (flags & ~bs->supported_truncate_flags) {
81
+ ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
130
+ error_setg(errp, "Block driver does not support requested flags");
82
+ flags & bs->supported_write_flags);
131
+ ret = -ENOTSUP;
83
+ flags &= ~bs->supported_write_flags;
132
+ goto out;
84
133
+ }
85
emulate_flags:
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
86
if (ret == 0 && (flags & BDRV_REQ_FUA)) {
135
} else if (bs->file && drv->is_filter) {
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
137
} else {
87
diff --git a/block/iscsi.c b/block/iscsi.c
138
diff --git a/block/iscsi.c b/block/iscsi.c
88
index XXXXXXX..XXXXXXX 100644
139
index XXXXXXX..XXXXXXX 100644
89
--- a/block/iscsi.c
140
--- a/block/iscsi.c
90
+++ b/block/iscsi.c
141
+++ b/block/iscsi.c
91
@@ -XXX,XX +XXX,XX @@ static inline bool iscsi_allocmap_is_valid(IscsiLun *iscsilun,
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
92
}
143
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
145
bool exact, PreallocMode prealloc,
146
- Error **errp)
147
+ BdrvRequestFlags flags, Error **errp)
148
{
149
IscsiLun *iscsilun = bs->opaque;
150
int64_t cur_length;
151
diff --git a/block/nfs.c b/block/nfs.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/block/nfs.c
154
+++ b/block/nfs.c
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
93
156
94
static int coroutine_fn
157
static int coroutine_fn
95
-iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
96
- QEMUIOVector *iov, int flags)
159
- PreallocMode prealloc, Error **errp)
97
+iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
98
+ QEMUIOVector *iov, int flags)
161
+ Error **errp)
99
{
162
{
100
IscsiLun *iscsilun = bs->opaque;
163
NFSClient *client = bs->opaque;
101
struct IscsiTask iTask;
164
int ret;
102
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
165
diff --git a/block/qcow2.c b/block/qcow2.c
103
.bdrv_co_pdiscard = iscsi_co_pdiscard,
166
index XXXXXXX..XXXXXXX 100644
104
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
167
--- a/block/qcow2.c
105
.bdrv_co_readv = iscsi_co_readv,
168
+++ b/block/qcow2.c
106
- .bdrv_co_writev_flags = iscsi_co_writev_flags,
169
@@ -XXX,XX +XXX,XX @@ fail:
107
+ .bdrv_co_writev = iscsi_co_writev,
170
108
.bdrv_co_flush_to_disk = iscsi_co_flush,
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
109
172
bool exact, PreallocMode prealloc,
110
#ifdef __linux__
173
- Error **errp)
111
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = {
174
+ BdrvRequestFlags flags, Error **errp)
112
.bdrv_co_pdiscard = iscsi_co_pdiscard,
175
{
113
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
176
BDRVQcow2State *s = bs->opaque;
114
.bdrv_co_readv = iscsi_co_readv,
177
uint64_t old_length;
115
- .bdrv_co_writev_flags = iscsi_co_writev_flags,
116
+ .bdrv_co_writev = iscsi_co_writev,
117
.bdrv_co_flush_to_disk = iscsi_co_flush,
118
119
#ifdef __linux__
120
diff --git a/block/parallels.c b/block/parallels.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/block/parallels.c
123
+++ b/block/parallels.c
124
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_block_status(BlockDriverState *bs,
125
}
126
127
static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
128
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
129
+ int64_t sector_num, int nb_sectors,
130
+ QEMUIOVector *qiov, int flags)
131
{
132
BDRVParallelsState *s = bs->opaque;
133
uint64_t bytes_done = 0;
134
QEMUIOVector hd_qiov;
135
int ret = 0;
136
137
+ assert(!flags);
138
qemu_iovec_init(&hd_qiov, qiov->niov);
139
140
while (nb_sectors > 0) {
141
diff --git a/block/qcow.c b/block/qcow.c
142
index XXXXXXX..XXXXXXX 100644
143
--- a/block/qcow.c
144
+++ b/block/qcow.c
145
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
146
}
147
148
static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
149
- int nb_sectors, QEMUIOVector *qiov)
150
+ int nb_sectors, QEMUIOVector *qiov,
151
+ int flags)
152
{
153
BDRVQcowState *s = bs->opaque;
154
int index_in_cluster;
155
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
156
uint8_t *buf;
157
void *orig_buf;
158
159
+ assert(!flags);
160
s->cluster_cache_offset = -1; /* disable compressed cache */
161
162
/* We must always copy the iov when encrypting, so we
163
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
164
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
165
/* could not compress: write normal cluster */
166
ret = qcow_co_writev(bs, offset >> BDRV_SECTOR_BITS,
167
- bytes >> BDRV_SECTOR_BITS, qiov);
168
+ bytes >> BDRV_SECTOR_BITS, qiov, 0);
169
if (ret < 0) {
170
goto fail;
171
}
172
diff --git a/block/qed.c b/block/qed.c
178
diff --git a/block/qed.c b/block/qed.c
173
index XXXXXXX..XXXXXXX 100644
179
index XXXXXXX..XXXXXXX 100644
174
--- a/block/qed.c
180
--- a/block/qed.c
175
+++ b/block/qed.c
181
+++ b/block/qed.c
176
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
177
183
int64_t offset,
178
static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
184
bool exact,
179
int64_t sector_num, int nb_sectors,
185
PreallocMode prealloc,
180
- QEMUIOVector *qiov)
186
+ BdrvRequestFlags flags,
181
+ QEMUIOVector *qiov, int flags)
187
Error **errp)
182
{
188
{
183
+ assert(!flags);
189
BDRVQEDState *s = bs->opaque;
184
return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
190
diff --git a/block/raw-format.c b/block/raw-format.c
185
}
191
index XXXXXXX..XXXXXXX 100644
186
192
--- a/block/raw-format.c
187
diff --git a/block/replication.c b/block/replication.c
193
+++ b/block/raw-format.c
188
index XXXXXXX..XXXXXXX 100644
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
189
--- a/block/replication.c
195
190
+++ b/block/replication.c
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
191
@@ -XXX,XX +XXX,XX @@ out:
197
bool exact, PreallocMode prealloc,
192
static coroutine_fn int replication_co_writev(BlockDriverState *bs,
198
- Error **errp)
193
int64_t sector_num,
199
+ BdrvRequestFlags flags, Error **errp)
194
int remaining_sectors,
200
{
195
- QEMUIOVector *qiov)
201
BDRVRawState *s = bs->opaque;
196
+ QEMUIOVector *qiov,
202
197
+ int flags)
203
diff --git a/block/rbd.c b/block/rbd.c
198
{
204
index XXXXXXX..XXXXXXX 100644
199
BDRVReplicationState *s = bs->opaque;
205
--- a/block/rbd.c
200
QEMUIOVector hd_qiov;
206
+++ b/block/rbd.c
201
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_writev(BlockDriverState *bs,
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
202
int ret;
208
int64_t offset,
203
int64_t n;
209
bool exact,
204
210
PreallocMode prealloc,
205
+ assert(!flags);
211
+ BdrvRequestFlags flags,
206
ret = replication_get_io_status(s);
212
Error **errp)
207
if (ret < 0) {
213
{
208
goto out;
214
int r;
209
diff --git a/block/sheepdog.c b/block/sheepdog.c
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
210
index XXXXXXX..XXXXXXX 100644
216
index XXXXXXX..XXXXXXX 100644
211
--- a/block/sheepdog.c
217
--- a/block/sheepdog.c
212
+++ b/block/sheepdog.c
218
+++ b/block/sheepdog.c
213
@@ -XXX,XX +XXX,XX @@ static void sd_aio_complete(SheepdogAIOCB *acb)
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
214
}
220
215
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
216
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
222
bool exact, PreallocMode prealloc,
217
- int nb_sectors, QEMUIOVector *qiov)
223
- Error **errp)
218
+ int nb_sectors, QEMUIOVector *qiov,
224
+ BdrvRequestFlags flags, Error **errp)
219
+ int flags)
225
{
220
{
221
SheepdogAIOCB acb;
222
int ret;
223
int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
224
BDRVSheepdogState *s = bs->opaque;
226
BDRVSheepdogState *s = bs->opaque;
225
227
int ret, fd;
226
+ assert(!flags);
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
227
if (offset > s->inode.vdi_size) {
231
if (offset > s->inode.vdi_size) {
228
ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
229
if (ret < 0) {
234
if (ret < 0) {
235
return ret;
236
}
230
diff --git a/block/ssh.c b/block/ssh.c
237
diff --git a/block/ssh.c b/block/ssh.c
231
index XXXXXXX..XXXXXXX 100644
238
index XXXXXXX..XXXXXXX 100644
232
--- a/block/ssh.c
239
--- a/block/ssh.c
233
+++ b/block/ssh.c
240
+++ b/block/ssh.c
234
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
235
242
236
static coroutine_fn int ssh_co_writev(BlockDriverState *bs,
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
237
int64_t sector_num,
244
bool exact, PreallocMode prealloc,
238
- int nb_sectors, QEMUIOVector *qiov)
245
- Error **errp)
239
+ int nb_sectors, QEMUIOVector *qiov,
246
+ BdrvRequestFlags flags, Error **errp)
240
+ int flags)
241
{
247
{
242
BDRVSSHState *s = bs->opaque;
248
BDRVSSHState *s = bs->opaque;
243
int ret;
249
244
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
245
+ assert(!flags);
251
index XXXXXXX..XXXXXXX 100644
246
qemu_co_mutex_lock(&s->lock);
252
--- a/tests/test-block-iothread.c
247
ret = ssh_write(s, bs, sector_num * BDRV_SECTOR_SIZE,
253
+++ b/tests/test-block-iothread.c
248
nb_sectors * BDRV_SECTOR_SIZE, qiov);
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
249
diff --git a/block/vhdx.c b/block/vhdx.c
255
250
index XXXXXXX..XXXXXXX 100644
256
static int coroutine_fn
251
--- a/block/vhdx.c
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
252
+++ b/block/vhdx.c
258
- PreallocMode prealloc, Error **errp)
253
@@ -XXX,XX +XXX,XX @@ int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s)
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
260
+ Error **errp)
261
{
262
return 0;
254
}
263
}
255
256
static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
257
- int nb_sectors, QEMUIOVector *qiov)
258
+ int nb_sectors, QEMUIOVector *qiov,
259
+ int flags)
260
{
261
int ret = -ENOTSUP;
262
BDRVVHDXState *s = bs->opaque;
263
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
264
uint64_t bat_prior_offset = 0;
265
bool bat_update = false;
266
267
+ assert(!flags);
268
qemu_iovec_init(&hd_qiov, qiov->niov);
269
270
qemu_co_mutex_lock(&s->lock);
271
--
264
--
272
2.13.6
265
2.25.3
273
266
274
267
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
bdrv_truncate().
2
4
3
This flag signifies that a write request will not change the visible
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
disk content. With this flag set, it is sufficient to have the
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
BLK_PERM_WRITE_UNCHANGED permission instead of BLK_PERM_WRITE.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20180421132929.21610-4-mreitz@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
11
---
14
include/block/block.h | 6 +++++-
12
include/block/block.h | 5 +++--
15
block/io.c | 6 +++++-
13
block/block-backend.c | 2 +-
16
2 files changed, 10 insertions(+), 2 deletions(-)
14
block/crypto.c | 2 +-
15
block/io.c | 12 +++++++-----
16
block/parallels.c | 6 +++---
17
block/qcow.c | 4 ++--
18
block/qcow2-refcount.c | 2 +-
19
block/qcow2.c | 15 +++++++++------
20
block/raw-format.c | 2 +-
21
block/vhdx-log.c | 2 +-
22
block/vhdx.c | 2 +-
23
block/vmdk.c | 2 +-
24
tests/test-block-iothread.c | 6 +++---
25
13 files changed, 34 insertions(+), 28 deletions(-)
17
26
18
diff --git a/include/block/block.h b/include/block/block.h
27
diff --git a/include/block/block.h b/include/block/block.h
19
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
20
--- a/include/block/block.h
29
--- a/include/block/block.h
21
+++ b/include/block/block.h
30
+++ b/include/block/block.h
22
@@ -XXX,XX +XXX,XX @@ typedef enum {
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
23
BDRV_REQ_FUA = 0x10,
32
void bdrv_refresh_filename(BlockDriverState *bs);
24
BDRV_REQ_WRITE_COMPRESSED = 0x20,
33
25
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
26
+ /* Signifies that this write request will not change the visible disk
35
- PreallocMode prealloc, Error **errp);
27
+ * content. */
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
28
+ BDRV_REQ_WRITE_UNCHANGED = 0x40,
37
+ Error **errp);
29
+
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
30
/* Mask of valid flags */
39
- PreallocMode prealloc, Error **errp);
31
- BDRV_REQ_MASK = 0x3f,
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
32
+ BDRV_REQ_MASK = 0x7f,
41
33
} BdrvRequestFlags;
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
34
43
int64_t bdrv_getlength(BlockDriverState *bs);
35
typedef struct BlockSizes {
44
diff --git a/block/block-backend.c b/block/block-backend.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/block-backend.c
47
+++ b/block/block-backend.c
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
49
return -ENOMEDIUM;
50
}
51
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
54
}
55
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
60
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
62
63
offset += payload_offset;
64
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
}
68
69
static void block_crypto_close(BlockDriverState *bs)
36
diff --git a/block/io.c b/block/io.c
70
diff --git a/block/io.c b/block/io.c
37
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
38
--- a/block/io.c
72
--- a/block/io.c
39
+++ b/block/io.c
73
+++ b/block/io.c
40
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
41
assert(!waited || !req->serialising);
75
* 'offset' bytes in length.
42
assert(req->overlap_offset <= offset);
76
*/
43
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
44
- assert(child->perm & BLK_PERM_WRITE);
78
- PreallocMode prealloc, Error **errp)
45
+ if (flags & BDRV_REQ_WRITE_UNCHANGED) {
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
46
+ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
80
+ Error **errp)
47
+ } else {
81
{
48
+ assert(child->perm & BLK_PERM_WRITE);
82
BlockDriverState *bs = child->bs;
49
+ }
83
BlockDriver *drv = bs->drv;
50
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
84
BdrvTrackedRequest req;
51
85
- BdrvRequestFlags flags = 0;
52
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
86
int64_t old_size, new_bytes;
87
int ret;
88
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
90
}
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
92
} else if (bs->file && drv->is_filter) {
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
95
} else {
96
error_setg(errp, "Image format driver does not support resize");
97
ret = -ENOTSUP;
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
99
int64_t offset;
100
bool exact;
101
PreallocMode prealloc;
102
+ BdrvRequestFlags flags;
103
Error **errp;
104
int ret;
105
} TruncateCo;
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
107
{
108
TruncateCo *tco = opaque;
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
110
- tco->prealloc, tco->errp);
111
+ tco->prealloc, tco->flags, tco->errp);
112
aio_wait_kick();
113
}
114
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
116
- PreallocMode prealloc, Error **errp)
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
118
{
119
Coroutine *co;
120
TruncateCo tco = {
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
122
.offset = offset,
123
.exact = exact,
124
.prealloc = prealloc,
125
+ .flags = flags,
126
.errp = errp,
127
.ret = NOT_DONE,
128
};
129
diff --git a/block/parallels.c b/block/parallels.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/parallels.c
132
+++ b/block/parallels.c
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
134
} else {
135
ret = bdrv_truncate(bs->file,
136
(s->data_end + space) << BDRV_SECTOR_BITS,
137
- false, PREALLOC_MODE_OFF, NULL);
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
139
}
140
if (ret < 0) {
141
return ret;
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
143
* That means we have to pass exact=true.
144
*/
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
146
- PREALLOC_MODE_OFF, &local_err);
147
+ PREALLOC_MODE_OFF, 0, &local_err);
148
if (ret < 0) {
149
error_report_err(local_err);
150
res->check_errors++;
151
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
152
153
/* errors are ignored, so we might as well pass exact=true */
154
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
155
- PREALLOC_MODE_OFF, NULL);
156
+ PREALLOC_MODE_OFF, 0, NULL);
157
}
158
159
g_free(s->bat_dirty_bmap);
160
diff --git a/block/qcow.c b/block/qcow.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qcow.c
163
+++ b/block/qcow.c
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
165
return -E2BIG;
166
}
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
168
- false, PREALLOC_MODE_OFF, NULL);
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
170
if (ret < 0) {
171
return ret;
172
}
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
174
l1_length) < 0)
175
return -1;
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
177
- PREALLOC_MODE_OFF, NULL);
178
+ PREALLOC_MODE_OFF, 0, NULL);
179
if (ret < 0)
180
return ret;
181
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/qcow2-refcount.c
185
+++ b/block/qcow2-refcount.c
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
187
}
188
189
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
190
- PREALLOC_MODE_OFF, &local_err);
191
+ PREALLOC_MODE_OFF, 0, &local_err);
192
if (ret < 0) {
193
error_report_err(local_err);
194
goto resize_fail;
195
diff --git a/block/qcow2.c b/block/qcow2.c
196
index XXXXXXX..XXXXXXX 100644
197
--- a/block/qcow2.c
198
+++ b/block/qcow2.c
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
200
mode = PREALLOC_MODE_OFF;
201
}
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
203
- mode, errp);
204
+ mode, 0, errp);
205
if (ret < 0) {
206
return ret;
207
}
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
209
* always fulfilled, so there is no need to pass it on.)
210
*/
211
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
212
- false, PREALLOC_MODE_OFF, &local_err);
213
+ false, PREALLOC_MODE_OFF, 0, &local_err);
214
if (local_err) {
215
warn_reportf_err(local_err,
216
"Failed to truncate the tail of the image: ");
217
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
218
* file should be resized to the exact target size, too,
219
* so we pass @exact here.
220
*/
221
- ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp);
222
+ ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
223
+ errp);
224
if (ret < 0) {
225
goto fail;
226
}
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
228
new_file_size = allocation_start +
229
nb_new_data_clusters * s->cluster_size;
230
/* Image file grows, so @exact does not matter */
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
233
+ errp);
234
if (ret < 0) {
235
error_prepend(errp, "Failed to resize underlying file: ");
236
qcow2_free_clusters(bs, allocation_start,
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
238
if (len < 0) {
239
return len;
240
}
241
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
242
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
243
+ NULL);
244
}
245
246
if (offset_into_cluster(s, offset)) {
247
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
248
}
249
250
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
251
- PREALLOC_MODE_OFF, &local_err);
252
+ PREALLOC_MODE_OFF, 0, &local_err);
253
if (ret < 0) {
254
error_report_err(local_err);
255
goto fail;
256
diff --git a/block/raw-format.c b/block/raw-format.c
257
index XXXXXXX..XXXXXXX 100644
258
--- a/block/raw-format.c
259
+++ b/block/raw-format.c
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
261
262
s->size = offset;
263
offset += s->offset;
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
266
}
267
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
270
index XXXXXXX..XXXXXXX 100644
271
--- a/block/vhdx-log.c
272
+++ b/block/vhdx-log.c
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
274
goto exit;
275
}
276
ret = bdrv_truncate(bs->file, new_file_size, false,
277
- PREALLOC_MODE_OFF, NULL);
278
+ PREALLOC_MODE_OFF, 0, NULL);
279
if (ret < 0) {
280
goto exit;
281
}
282
diff --git a/block/vhdx.c b/block/vhdx.c
283
index XXXXXXX..XXXXXXX 100644
284
--- a/block/vhdx.c
285
+++ b/block/vhdx.c
286
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
287
}
288
289
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
290
- PREALLOC_MODE_OFF, NULL);
291
+ PREALLOC_MODE_OFF, 0, NULL);
292
}
293
294
/*
295
diff --git a/block/vmdk.c b/block/vmdk.c
296
index XXXXXXX..XXXXXXX 100644
297
--- a/block/vmdk.c
298
+++ b/block/vmdk.c
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
300
}
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
302
ret = bdrv_truncate(s->extents[i].file, length, false,
303
- PREALLOC_MODE_OFF, NULL);
304
+ PREALLOC_MODE_OFF, 0, NULL);
305
if (ret < 0) {
306
return ret;
307
}
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/tests/test-block-iothread.c
311
+++ b/tests/test-block-iothread.c
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
313
int ret;
314
315
/* Normal success path */
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
318
g_assert_cmpint(ret, ==, 0);
319
320
/* Early error: Negative offset */
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
323
g_assert_cmpint(ret, ==, -EINVAL);
324
325
/* Error: Read-only image */
326
c->bs->read_only = true;
327
c->bs->open_flags &= ~BDRV_O_RDWR;
328
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
331
g_assert_cmpint(ret, ==, -EACCES);
332
333
c->bs->read_only = false;
53
--
334
--
54
2.13.6
335
2.25.3
55
336
56
337
diff view generated by jsdifflib
1
Block job drivers are not expected to mess with the internals of the
1
Now that node level interface bdrv_truncate() supports passing request
2
BlockJob object, so provide wrapper functions for one of the cases where
2
flags to the block driver, expose this on the BlockBackend level, too.
3
they still do it: Updating the progress counter.
4
3
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
---
10
include/block/blockjob.h | 19 +++++++++++++++++++
11
include/sysemu/block-backend.h | 2 +-
11
block/backup.c | 22 +++++++++++++---------
12
block.c | 3 ++-
12
block/commit.c | 16 ++++++++--------
13
block/block-backend.c | 4 ++--
13
block/mirror.c | 11 +++++------
14
block/commit.c | 4 ++--
14
block/stream.c | 14 ++++++++------
15
block/crypto.c | 2 +-
15
blockjob.c | 10 ++++++++++
16
block/mirror.c | 2 +-
16
6 files changed, 63 insertions(+), 29 deletions(-)
17
block/qcow2.c | 4 ++--
17
18
block/qed.c | 2 +-
18
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
19
block/vdi.c | 2 +-
19
index XXXXXXX..XXXXXXX 100644
20
block/vhdx.c | 4 ++--
20
--- a/include/block/blockjob.h
21
block/vmdk.c | 6 +++---
21
+++ b/include/block/blockjob.h
22
block/vpc.c | 2 +-
22
@@ -XXX,XX +XXX,XX @@ void block_job_finalize(BlockJob *job, Error **errp);
23
blockdev.c | 2 +-
23
void block_job_dismiss(BlockJob **job, Error **errp);
24
qemu-img.c | 2 +-
24
25
qemu-io-cmds.c | 2 +-
25
/**
26
15 files changed, 22 insertions(+), 21 deletions(-)
26
+ * block_job_progress_update:
27
27
+ * @job: The job that has made progress
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
28
+ * @done: How much progress the job made
29
index XXXXXXX..XXXXXXX 100644
29
+ *
30
--- a/include/sysemu/block-backend.h
30
+ * Updates the progress counter of the job.
31
+++ b/include/sysemu/block-backend.h
31
+ */
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
32
+void block_job_progress_update(BlockJob *job, uint64_t done);
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
33
+
34
int bytes);
34
+/**
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
35
+ * block_job_progress_set_remaining:
36
- PreallocMode prealloc, Error **errp);
36
+ * @job: The job whose expected progress end value is set
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
37
+ * @remaining: Expected end value of the progress counter of the job
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
38
+ *
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
39
+ * Sets the expected end value of the progress counter of a job so that a
40
int64_t pos, int size);
40
+ * completion percentage can be calculated when the progress is updated.
41
diff --git a/block.c b/block.c
41
+ */
42
index XXXXXXX..XXXXXXX 100644
42
+void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining);
43
--- a/block.c
43
+
44
+++ b/block.c
44
+/**
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
45
* block_job_query:
46
int64_t size;
46
* @job: The job to get information about.
47
int ret;
47
*
48
48
diff --git a/block/backup.c b/block/backup.c
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
49
index XXXXXXX..XXXXXXX 100644
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
50
--- a/block/backup.c
51
+ &local_err);
51
+++ b/block/backup.c
52
if (ret < 0 && ret != -ENOTSUP) {
52
@@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob {
53
error_propagate(errp, local_err);
53
BlockdevOnError on_source_error;
54
return ret;
54
BlockdevOnError on_target_error;
55
diff --git a/block/block-backend.c b/block/block-backend.c
55
CoRwlock flush_rwlock;
56
index XXXXXXX..XXXXXXX 100644
56
+ uint64_t len;
57
--- a/block/block-backend.c
57
uint64_t bytes_read;
58
+++ b/block/block-backend.c
58
int64_t cluster_size;
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
59
bool compress;
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
61
62
trace_backup_do_cow_process(job, start);
63
64
- n = MIN(job->cluster_size, job->common.len - start);
65
+ n = MIN(job->cluster_size, job->len - start);
66
67
if (!bounce_buffer) {
68
bounce_buffer = blk_blockalign(blk, job->cluster_size);
69
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
70
* offset field is an opaque progress value, it is not a disk offset.
71
*/
72
job->bytes_read += n;
73
- job->common.offset += n;
74
+ block_job_progress_update(&job->common, n);
75
}
76
77
out:
78
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
79
return;
80
}
81
82
- len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size);
83
+ len = DIV_ROUND_UP(backup_job->len, backup_job->cluster_size);
84
hbitmap_set(backup_job->copy_bitmap, 0, len);
85
}
60
}
86
61
87
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
88
bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
63
- PreallocMode prealloc, Error **errp)
89
}
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
90
65
{
91
- job->common.offset = job->common.len -
66
if (!blk_is_available(blk)) {
92
- hbitmap_count(job->copy_bitmap) * job->cluster_size;
67
error_setg(errp, "No medium inserted");
93
+ /* TODO block_job_progress_set_remaining() would make more sense */
68
return -ENOMEDIUM;
94
+ block_job_progress_update(&job->common,
69
}
95
+ job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size);
70
96
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
97
bdrv_dirty_iter_free(dbi);
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
98
}
73
}
99
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
74
100
QLIST_INIT(&job->inflight_reqs);
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
101
qemu_co_rwlock_init(&job->flush_rwlock);
102
103
- nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size);
104
+ nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size);
105
+ block_job_progress_set_remaining(&job->common, job->len);
106
+
107
job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
108
if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
109
backup_incremental_init_copy_bitmap(job);
110
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
111
ret = backup_run_incremental(job);
112
} else {
113
/* Both FULL and TOP SYNC_MODE's require copying.. */
114
- for (offset = 0; offset < job->common.len;
115
+ for (offset = 0; offset < job->len;
116
offset += job->cluster_size) {
117
bool error_is_read;
118
int alloced = 0;
119
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
120
goto error;
121
}
122
123
- /* job->common.len is fixed, so we can't allow resize */
124
+ /* job->len is fixed, so we can't allow resize */
125
job = block_job_create(job_id, &backup_job_driver, txn, bs,
126
BLK_PERM_CONSISTENT_READ,
127
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
128
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
129
/* Required permissions are already taken with target's blk_new() */
130
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
131
&error_abort);
132
- job->common.len = len;
133
+ job->len = len;
134
135
return &job->common;
136
137
diff --git a/block/commit.c b/block/commit.c
76
diff --git a/block/commit.c b/block/commit.c
138
index XXXXXXX..XXXXXXX 100644
77
index XXXXXXX..XXXXXXX 100644
139
--- a/block/commit.c
78
--- a/block/commit.c
140
+++ b/block/commit.c
79
+++ b/block/commit.c
141
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque)
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
142
int64_t n = 0; /* bytes */
81
}
143
void *buf = NULL;
82
144
int bytes_written = 0;
83
if (base_len < len) {
145
- int64_t base_len;
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
146
+ int64_t len, base_len;
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
147
148
- ret = s->common.len = blk_getlength(s->top);
149
-
150
- if (s->common.len < 0) {
151
+ ret = len = blk_getlength(s->top);
152
+ if (len < 0) {
153
goto out;
154
}
155
+ block_job_progress_set_remaining(&s->common, len);
156
157
ret = base_len = blk_getlength(s->base);
158
if (base_len < 0) {
159
goto out;
160
}
161
162
- if (base_len < s->common.len) {
163
- ret = blk_truncate(s->base, s->common.len, PREALLOC_MODE_OFF, NULL);
164
+ if (base_len < len) {
165
+ ret = blk_truncate(s->base, len, PREALLOC_MODE_OFF, NULL);
166
if (ret) {
86
if (ret) {
167
goto out;
87
goto out;
168
}
88
}
169
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque)
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
170
90
* grow the backing file image if possible. If not possible,
171
buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE);
91
* we must return an error */
172
92
if (length > backing_length) {
173
- for (offset = 0; offset < s->common.len; offset += n) {
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
174
+ for (offset = 0; offset < len; offset += n) {
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
175
bool copy;
95
&local_err);
176
96
if (ret < 0) {
177
/* Note that even when no rate limit is applied we need to yield
97
error_report_err(local_err);
178
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque)
98
diff --git a/block/crypto.c b/block/crypto.c
179
}
99
index XXXXXXX..XXXXXXX 100644
180
}
100
--- a/block/crypto.c
181
/* Publish progress */
101
+++ b/block/crypto.c
182
- s->common.offset += n;
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
183
+ block_job_progress_update(&s->common, n);
103
* which will be used by the crypto header
184
104
*/
185
if (copy && s->common.speed) {
105
return blk_truncate(data->blk, data->size + headerlen, false,
186
delay_ns = ratelimit_calculate_delay(&s->limit, n);
106
- data->prealloc, errp);
107
+ data->prealloc, 0, errp);
108
}
109
110
187
diff --git a/block/mirror.c b/block/mirror.c
111
diff --git a/block/mirror.c b/block/mirror.c
188
index XXXXXXX..XXXXXXX 100644
112
index XXXXXXX..XXXXXXX 100644
189
--- a/block/mirror.c
113
--- a/block/mirror.c
190
+++ b/block/mirror.c
114
+++ b/block/mirror.c
191
@@ -XXX,XX +XXX,XX @@ static void mirror_iteration_done(MirrorOp *op, int ret)
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
192
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
116
193
}
117
if (s->bdev_length > base_length) {
194
if (!s->initial_zeroing_ongoing) {
118
ret = blk_truncate(s->target, s->bdev_length, false,
195
- s->common.offset += op->bytes;
119
- PREALLOC_MODE_OFF, NULL);
196
+ block_job_progress_update(&s->common, op->bytes);
120
+ PREALLOC_MODE_OFF, 0, NULL);
197
}
121
if (ret < 0) {
198
}
122
goto immediate_exit;
199
qemu_iovec_destroy(&op->qiov);
123
}
200
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
124
diff --git a/block/qcow2.c b/block/qcow2.c
201
block_job_pause_point(&s->common);
125
index XXXXXXX..XXXXXXX 100644
202
126
--- a/block/qcow2.c
203
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
127
+++ b/block/qcow2.c
204
- /* s->common.offset contains the number of bytes already processed so
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
205
- * far, cnt is the number of dirty bytes remaining and
129
206
- * s->bytes_in_flight is the number of bytes currently being
130
/* Okay, now that we have a valid image, let's give it the right size */
207
- * processed; together those are the current total operation length */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
208
- s->common.len = s->common.offset + s->bytes_in_flight + cnt;
132
- errp);
209
+ /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is
133
+ 0, errp);
210
+ * the number of bytes currently being processed; together those are
134
if (ret < 0) {
211
+ * the current remaining operation length */
135
error_prepend(errp, "Could not resize image: ");
212
+ block_job_progress_set_remaining(&s->common, s->bytes_in_flight + cnt);
213
214
/* Note that even when no rate limit is applied we need to yield
215
* periodically with no pending I/O so that bdrv_drain_all() returns.
216
diff --git a/block/stream.c b/block/stream.c
217
index XXXXXXX..XXXXXXX 100644
218
--- a/block/stream.c
219
+++ b/block/stream.c
220
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
221
BlockBackend *blk = s->common.blk;
222
BlockDriverState *bs = blk_bs(blk);
223
BlockDriverState *base = s->base;
224
+ int64_t len;
225
int64_t offset = 0;
226
uint64_t delay_ns = 0;
227
int error = 0;
228
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
229
goto out;
136
goto out;
230
}
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
231
138
* Amending image options should ensure that the image has
232
- s->common.len = bdrv_getlength(bs);
139
* exactly the given new values, so pass exact=true here.
233
- if (s->common.len < 0) {
140
*/
234
- ret = s->common.len;
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
235
+ len = bdrv_getlength(bs);
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
236
+ if (len < 0) {
143
blk_unref(blk);
237
+ ret = len;
144
if (ret < 0) {
145
return ret;
146
diff --git a/block/qed.c b/block/qed.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/block/qed.c
149
+++ b/block/qed.c
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
151
* The QED format associates file length with allocation status,
152
* so a new file (which is empty) must have a length of 0.
153
*/
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
156
if (ret < 0) {
238
goto out;
157
goto out;
239
}
158
}
240
+ block_job_progress_set_remaining(&s->common, len);
159
diff --git a/block/vdi.c b/block/vdi.c
241
160
index XXXXXXX..XXXXXXX 100644
242
buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
161
--- a/block/vdi.c
243
162
+++ b/block/vdi.c
244
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
245
bdrv_enable_copy_on_read(bs);
164
246
}
165
if (image_type == VDI_TYPE_STATIC) {
247
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
248
- for ( ; offset < s->common.len; offset += n) {
167
- PREALLOC_MODE_OFF, errp);
249
+ for ( ; offset < len; offset += n) {
168
+ PREALLOC_MODE_OFF, 0, errp);
250
bool copy;
169
if (ret < 0) {
251
170
error_prepend(errp, "Failed to statically allocate file");
252
/* Note that even when no rate limit is applied we need to yield
171
goto exit;
253
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
172
diff --git a/block/vhdx.c b/block/vhdx.c
254
173
index XXXXXXX..XXXXXXX 100644
255
/* Finish early if end of backing file has been reached */
174
--- a/block/vhdx.c
256
if (ret == 0 && n == 0) {
175
+++ b/block/vhdx.c
257
- n = s->common.len - offset;
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
258
+ n = len - offset;
177
/* All zeroes, so we can just extend the file - the end of the BAT
259
}
178
* is the furthest thing we have written yet */
260
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
261
copy = (ret == 1);
180
- errp);
262
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
181
+ 0, errp);
263
ret = 0;
182
if (ret < 0) {
264
183
goto exit;
265
/* Publish progress */
184
}
266
- s->common.offset += n;
185
} else if (type == VHDX_TYPE_FIXED) {
267
+ block_job_progress_update(&s->common, n);
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
268
if (copy && s->common.speed) {
187
- PREALLOC_MODE_OFF, errp);
269
delay_ns = ratelimit_calculate_delay(&s->limit, n);
188
+ PREALLOC_MODE_OFF, 0, errp);
270
} else {
189
if (ret < 0) {
271
diff --git a/blockjob.c b/blockjob.c
190
goto exit;
272
index XXXXXXX..XXXXXXX 100644
191
}
273
--- a/blockjob.c
192
diff --git a/block/vmdk.c b/block/vmdk.c
274
+++ b/blockjob.c
193
index XXXXXXX..XXXXXXX 100644
275
@@ -XXX,XX +XXX,XX @@ int block_job_complete_sync(BlockJob *job, Error **errp)
194
--- a/block/vmdk.c
276
return block_job_finish_sync(job, &block_job_complete, errp);
195
+++ b/block/vmdk.c
277
}
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
278
197
int gd_buf_size;
279
+void block_job_progress_update(BlockJob *job, uint64_t done)
198
280
+{
199
if (flat) {
281
+ job->offset += done;
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
282
+}
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
283
+
202
goto exit;
284
+void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining)
203
}
285
+{
204
magic = cpu_to_be32(VMDK4_MAGIC);
286
+ job->len = job->offset + remaining;
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
287
+}
206
}
288
+
207
289
BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
290
{
209
- PREALLOC_MODE_OFF, errp);
291
BlockJobInfo *info;
210
+ PREALLOC_MODE_OFF, 0, errp);
211
if (ret < 0) {
212
goto exit;
213
}
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
215
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
216
* for description file */
217
if (desc_offset == 0) {
218
- ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp);
219
+ ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
220
if (ret < 0) {
221
goto exit;
222
}
223
diff --git a/block/vpc.c b/block/vpc.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/vpc.c
226
+++ b/block/vpc.c
227
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
228
/* Add footer to total size */
229
total_size += HEADER_SIZE;
230
231
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp);
232
+ ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
233
if (ret < 0) {
234
return ret;
235
}
236
diff --git a/blockdev.c b/blockdev.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/blockdev.c
239
+++ b/blockdev.c
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
241
}
242
243
bdrv_drained_begin(bs);
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
246
bdrv_drained_end(bs);
247
248
out:
249
diff --git a/qemu-img.c b/qemu-img.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
252
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
255
* success when the image has not actually been resized.
256
*/
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
259
if (!ret) {
260
qprintf(quiet, "Image resized.\n");
261
} else {
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
263
index XXXXXXX..XXXXXXX 100644
264
--- a/qemu-io-cmds.c
265
+++ b/qemu-io-cmds.c
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
267
* exact=true. It is better to err on the "emit more errors" side
268
* than to be overly permissive.
269
*/
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
272
if (ret < 0) {
273
error_report_err(local_err);
274
return ret;
292
--
275
--
293
2.13.6
276
2.25.3
294
277
295
278
diff view generated by jsdifflib
1
This gets us rid of more direct accesses to BlockJob fields from the
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
2
job drivers.
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
3
undo any previous preallocation, but just adds the zero flag to all
4
relevant L2 entries. If an external data file is in use, a write_zeroes
5
request to the data file is made instead.
3
6
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
12
---
9
include/block/blockjob_int.h | 8 ++++++++
13
block/qcow2-cluster.c | 2 +-
10
block/backup.c | 18 +++++++-----------
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
11
block/commit.c | 4 ++--
15
2 files changed, 35 insertions(+), 1 deletion(-)
12
block/mirror.c | 5 +----
13
block/stream.c | 4 ++--
14
blockjob.c | 9 +++++++++
15
6 files changed, 29 insertions(+), 19 deletions(-)
16
16
17
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/blockjob_int.h
19
--- a/block/qcow2-cluster.c
20
+++ b/include/block/blockjob_int.h
20
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ void block_job_sleep_ns(BlockJob *job, int64_t ns);
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
22
void block_job_yield(BlockJob *job);
22
/* Caller must pass aligned values, except at image end */
23
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
24
/**
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
25
+ * block_job_ratelimit_get_delay:
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
26
+ *
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
27
+ * Calculate and return delay for the next request in ns. See the documentation
27
28
+ * of ratelimit_calculate_delay() for details.
28
/* The zero flag is only supported by version 3 and newer */
29
+ */
29
if (s->qcow_version < 3) {
30
+int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n);
30
diff --git a/block/qcow2.c b/block/qcow2.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2.c
33
+++ b/block/qcow2.c
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
35
36
bs->supported_zero_flags = header.version >= 3 ?
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
39
40
/* Repair image if dirty */
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
43
g_assert_not_reached();
44
}
45
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
31
+
48
+
32
+/**
49
+ /*
33
* block_job_early_fail:
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
34
* @bs: The block device.
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
35
*
52
+ * at the end of the image (which it is here).
36
diff --git a/block/backup.c b/block/backup.c
53
+ */
37
index XXXXXXX..XXXXXXX 100644
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
38
--- a/block/backup.c
55
+ if (ret < 0) {
39
+++ b/block/backup.c
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
40
@@ -XXX,XX +XXX,XX @@ static void backup_complete(BlockJob *job, void *opaque)
57
+ goto fail;
41
58
+ }
42
static bool coroutine_fn yield_and_check(BackupBlockJob *job)
43
{
44
+ uint64_t delay_ns;
45
+
59
+
46
if (block_job_is_cancelled(&job->common)) {
60
+ /* Write explicit zeros for the unaligned head */
47
return true;
61
+ if (zero_start > old_length) {
48
}
62
+ uint64_t len = zero_start - old_length;
49
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
50
- /* we need to yield so that bdrv_drain_all() returns.
64
+ QEMUIOVector qiov;
51
- * (without, VM does not reboot)
65
+ qemu_iovec_init_buf(&qiov, buf, len);
52
- */
66
+
53
- if (job->common.speed) {
67
+ qemu_co_mutex_unlock(&s->lock);
54
- uint64_t delay_ns = ratelimit_calculate_delay(&job->common.limit,
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
55
- job->bytes_read);
69
+ qemu_co_mutex_lock(&s->lock);
56
- job->bytes_read = 0;
70
+
57
- block_job_sleep_ns(&job->common, delay_ns);
71
+ qemu_vfree(buf);
58
- } else {
72
+ if (ret < 0) {
59
- block_job_sleep_ns(&job->common, 0);
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
60
- }
74
+ goto fail;
61
+ /* We need to yield even for delay_ns = 0 so that bdrv_drain_all() can
75
+ }
62
+ * return. Without a yield, the VM would not reboot. */
76
+ }
63
+ delay_ns = block_job_ratelimit_get_delay(&job->common, job->bytes_read);
64
+ job->bytes_read = 0;
65
+ block_job_sleep_ns(&job->common, delay_ns);
66
67
if (block_job_is_cancelled(&job->common)) {
68
return true;
69
diff --git a/block/commit.c b/block/commit.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/commit.c
72
+++ b/block/commit.c
73
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque)
74
/* Publish progress */
75
block_job_progress_update(&s->common, n);
76
77
- if (copy && s->common.speed) {
78
- delay_ns = ratelimit_calculate_delay(&s->common.limit, n);
79
+ if (copy) {
80
+ delay_ns = block_job_ratelimit_get_delay(&s->common, n);
81
} else {
82
delay_ns = 0;
83
}
84
diff --git a/block/mirror.c b/block/mirror.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/mirror.c
87
+++ b/block/mirror.c
88
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
89
assert(io_bytes);
90
offset += io_bytes;
91
nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity);
92
- if (s->common.speed) {
93
- delay_ns = ratelimit_calculate_delay(&s->common.limit,
94
- io_bytes_acct);
95
- }
96
+ delay_ns = block_job_ratelimit_get_delay(&s->common, io_bytes_acct);
97
}
98
return delay_ns;
99
}
100
diff --git a/block/stream.c b/block/stream.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/stream.c
103
+++ b/block/stream.c
104
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
105
106
/* Publish progress */
107
block_job_progress_update(&s->common, n);
108
- if (copy && s->common.speed) {
109
- delay_ns = ratelimit_calculate_delay(&s->common.limit, n);
110
+ if (copy) {
111
+ delay_ns = block_job_ratelimit_get_delay(&s->common, n);
112
} else {
113
delay_ns = 0;
114
}
115
diff --git a/blockjob.c b/blockjob.c
116
index XXXXXXX..XXXXXXX 100644
117
--- a/blockjob.c
118
+++ b/blockjob.c
119
@@ -XXX,XX +XXX,XX @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
120
block_job_enter_cond(job, block_job_timer_pending);
121
}
122
123
+int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
124
+{
125
+ if (!job->speed) {
126
+ return 0;
127
+ }
77
+ }
128
+
78
+
129
+ return ratelimit_calculate_delay(&job->limit, n);
79
if (prealloc != PREALLOC_MODE_OFF) {
130
+}
80
/* Flush metadata before actually changing the image size */
131
+
81
ret = qcow2_write_caches(bs);
132
void block_job_complete(BlockJob *job, Error **errp)
133
{
134
/* Should not be reachable via external interface for internal jobs */
135
--
82
--
136
2.13.6
83
2.25.3
137
84
138
85
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
The raw format driver can simply forward the flag and let its bs->file
2
child take care of actually providing the zeros.
2
3
3
Update the rest of the filter drivers to support
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
BDRV_REQ_WRITE_UNCHANGED. They already forward write request flags to
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
their children, so we just have to announce support for it.
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/raw-format.c | 4 +++-
12
1 file changed, 3 insertions(+), 1 deletion(-)
6
13
7
This patch does not cover the replication driver because that currently
8
does not support flags at all, and because it just grabs the WRITE
9
permission for its children when it can, so we should be fine just
10
submitting the incoming WRITE_UNCHANGED requests as normal writes.
11
12
It also does not cover format drivers for similar reasons. They all use
13
bdrv_format_default_perms() as their .bdrv_child_perm() implementation
14
so they just always grab the WRITE permission for their file children
15
whenever possible. In addition, it often would be difficult to
16
ascertain whether incoming unchanging writes end up as unchanging writes
17
in their files. So we just leave them as normal potentially changing
18
writes.
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: Alberto Garcia <berto@igalia.com>
23
Message-id: 20180421132929.21610-7-mreitz@redhat.com
24
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
---
27
block/blkdebug.c | 9 +++++----
28
block/blkreplay.c | 3 +++
29
block/blkverify.c | 3 +++
30
block/copy-on-read.c | 10 ++++++----
31
block/mirror.c | 2 ++
32
block/raw-format.c | 9 +++++----
33
block/throttle.c | 6 ++++--
34
7 files changed, 28 insertions(+), 14 deletions(-)
35
36
diff --git a/block/blkdebug.c b/block/blkdebug.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/blkdebug.c
39
+++ b/block/blkdebug.c
40
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
41
goto out;
42
}
43
44
- bs->supported_write_flags = BDRV_REQ_FUA &
45
- bs->file->bs->supported_write_flags;
46
- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
47
- bs->file->bs->supported_zero_flags;
48
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
49
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
50
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
51
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
52
+ bs->file->bs->supported_zero_flags);
53
ret = -EINVAL;
54
55
/* Set alignment overrides */
56
diff --git a/block/blkreplay.c b/block/blkreplay.c
57
index XXXXXXX..XXXXXXX 100755
58
--- a/block/blkreplay.c
59
+++ b/block/blkreplay.c
60
@@ -XXX,XX +XXX,XX @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
61
goto fail;
62
}
63
64
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
65
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
66
+
67
ret = 0;
68
fail:
69
return ret;
70
diff --git a/block/blkverify.c b/block/blkverify.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/blkverify.c
73
+++ b/block/blkverify.c
74
@@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
75
goto fail;
76
}
77
78
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
79
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
80
+
81
ret = 0;
82
fail:
83
qemu_opts_del(opts);
84
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/copy-on-read.c
87
+++ b/block/copy-on-read.c
88
@@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
89
return -EINVAL;
90
}
91
92
- bs->supported_write_flags = BDRV_REQ_FUA &
93
- bs->file->bs->supported_write_flags;
94
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
95
+ (BDRV_REQ_FUA &
96
+ bs->file->bs->supported_write_flags);
97
98
- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
99
- bs->file->bs->supported_zero_flags;
100
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
101
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
102
+ bs->file->bs->supported_zero_flags);
103
104
return 0;
105
}
106
diff --git a/block/mirror.c b/block/mirror.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/mirror.c
109
+++ b/block/mirror.c
110
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
111
mirror_top_bs->implicit = true;
112
}
113
mirror_top_bs->total_sectors = bs->total_sectors;
114
+ mirror_top_bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
115
+ mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED;
116
bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
117
118
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
119
diff --git a/block/raw-format.c b/block/raw-format.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
120
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
121
--- a/block/raw-format.c
16
--- a/block/raw-format.c
122
+++ b/block/raw-format.c
17
+++ b/block/raw-format.c
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
19
20
s->size = offset;
21
offset += s->offset;
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
24
}
25
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
123
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
124
}
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
125
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
126
bs->sg = bs->file->bs->sg;
30
bs->file->bs->supported_zero_flags);
127
- bs->supported_write_flags = BDRV_REQ_FUA &
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
128
- bs->file->bs->supported_write_flags;
32
+ BDRV_REQ_ZERO_WRITE;
129
- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
130
- bs->file->bs->supported_zero_flags;
131
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
132
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
133
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
134
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
135
+ bs->file->bs->supported_zero_flags);
136
33
137
if (bs->probed && !bdrv_is_read_only(bs)) {
34
if (bs->probed && !bdrv_is_read_only(bs)) {
138
fprintf(stderr,
35
bdrv_refresh_filename(bs->file->bs);
139
diff --git a/block/throttle.c b/block/throttle.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/block/throttle.c
142
+++ b/block/throttle.c
143
@@ -XXX,XX +XXX,XX @@ static int throttle_open(BlockDriverState *bs, QDict *options,
144
if (!bs->file) {
145
return -EINVAL;
146
}
147
- bs->supported_write_flags = bs->file->bs->supported_write_flags;
148
- bs->supported_zero_flags = bs->file->bs->supported_zero_flags;
149
+ bs->supported_write_flags = bs->file->bs->supported_write_flags |
150
+ BDRV_REQ_WRITE_UNCHANGED;
151
+ bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
152
+ BDRV_REQ_WRITE_UNCHANGED;
153
154
return throttle_configure_tgm(bs, tgm, options, errp);
155
}
156
--
36
--
157
2.13.6
37
2.25.3
158
38
159
39
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
OS, so we can advertise the flag and just ignore it.
2
3
3
When we've reached the concluded state, we need to expose the error
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
state if applicable. Add the new field.
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
6
This should be sufficient for determining if a job completed
7
successfully or not after concluding; if we want to discriminate
8
based on how it failed more mechanically, we can always add an
9
explicit return code enumeration later.
10
11
I didn't bother to make it only show up if we are in the concluded
12
state; I don't think it's necessary.
13
14
Cc: qemu-stable@nongnu.org
15
Signed-off-by: John Snow <jsnow@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
10
---
20
qapi/block-core.json | 6 +++++-
11
block/file-posix.c | 4 ++++
21
blockjob.c | 2 ++
12
1 file changed, 4 insertions(+)
22
2 files changed, 7 insertions(+), 1 deletion(-)
23
13
24
diff --git a/qapi/block-core.json b/qapi/block-core.json
14
diff --git a/block/file-posix.c b/block/file-posix.c
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/qapi/block-core.json
16
--- a/block/file-posix.c
27
+++ b/qapi/block-core.json
17
+++ b/block/file-posix.c
28
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
29
# @auto-dismiss: Job will dismiss itself when CONCLUDED, moving to the NULL
19
#endif
30
# state and disappearing from the query list. (since 2.12)
20
31
#
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
32
+# @error: Error information if the job did not complete successfully.
22
+ if (S_ISREG(st.st_mode)) {
33
+# Not set if the job completed successfully. (since 2.12.1)
23
+ /* When extending regular files, we get zeros from the OS */
34
+#
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
35
# Since: 1.1
25
+ }
36
##
26
ret = 0;
37
{ 'struct': 'BlockJobInfo',
27
fail:
38
@@ -XXX,XX +XXX,XX @@
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
39
'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int',
40
'io-status': 'BlockDeviceIoStatus', 'ready': 'bool',
41
'status': 'BlockJobStatus',
42
- 'auto-finalize': 'bool', 'auto-dismiss': 'bool' } }
43
+ 'auto-finalize': 'bool', 'auto-dismiss': 'bool',
44
+ '*error': 'str' } }
45
46
##
47
# @query-block-jobs:
48
diff --git a/blockjob.c b/blockjob.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/blockjob.c
51
+++ b/blockjob.c
52
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
53
info->status = job->status;
54
info->auto_finalize = job->auto_finalize;
55
info->auto_dismiss = job->auto_dismiss;
56
+ info->has_error = job->ret != 0;
57
+ info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL;
58
return info;
59
}
60
61
--
29
--
62
2.13.6
30
2.25.3
63
31
64
32
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
When extending the size of an image that has a backing file larger than
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
2
4
3
We are gradually moving away from sector-based interfaces, towards
5
Consider the following scenario where the overlay is shorter than its
4
byte-based. Add new sector-based aio callbacks for read and write,
6
backing file:
5
to match the fact that bdrv_aio_pdiscard is already byte-based.
6
7
7
Ideally, drivers should be converted to use coroutine callbacks
8
base.qcow2: AAAAAAAA
8
rather than aio; but that is not quite as trivial (and if we were
9
overlay.qcow2: BBBB
9
to do that conversion, the null-aio driver would disappear), so for
10
the short term, converting the signature but keeping things with
11
aio is easier. However, we CAN declare that a driver that uses
12
the byte-based aio interfaces now defaults to byte-based
13
operations, and must explicitly provide a refresh_limits override
14
to stick with larger alignments (making the alignment issues more
15
obvious directly in the drivers touched in the next few patches).
16
10
17
Once all drivers are converted, the sector-based aio callbacks will
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
18
be removed; in the meantime, a FIXME comment is added due to a
12
unallocated and make the additional As from base.qcow2 visible like
19
slight inefficiency that will be touched up as part of that later
13
before this patch, but zeros should be read.
20
cleanup.
21
14
22
Simplify some instances of 'bs->drv' into 'drv' while touching this,
15
A similar case happens with the various variants of a commit job when an
23
since the local variable already exists to reduce typing.
16
intermediate file is short (- for unallocated):
24
17
25
Signed-off-by: Eric Blake <eblake@redhat.com>
18
base.qcow2: A-A-AAAA
19
mid.qcow2: BB-B
20
top.qcow2: C--C--C-
21
22
After commit top.qcow2 to mid.qcow2, the following happens:
23
24
mid.qcow2: CB-C00C0 (correct result)
25
mid.qcow2: CB-C--C- (before this fix)
26
27
Without the fix, blocks that previously read as zeros on top.qcow2
28
suddenly turn into A.
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
Message-Id: <20200424125448.63318-8-kwolf@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
35
---
28
include/block/block_int.h | 6 ++++++
36
block/io.c | 25 +++++++++++++++++++++++++
29
block/io.c | 38 +++++++++++++++++++++++++++++---------
37
1 file changed, 25 insertions(+)
30
2 files changed, 35 insertions(+), 9 deletions(-)
31
38
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
35
+++ b/include/block/block_int.h
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
37
BlockAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
38
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
39
BlockCompletionFunc *cb, void *opaque);
40
+ BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs,
41
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
42
+ BlockCompletionFunc *cb, void *opaque);
43
BlockAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
44
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
45
BlockCompletionFunc *cb, void *opaque);
46
+ BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs,
47
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
48
+ BlockCompletionFunc *cb, void *opaque);
49
BlockAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
50
BlockCompletionFunc *cb, void *opaque);
51
BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs,
52
diff --git a/block/io.c b/block/io.c
39
diff --git a/block/io.c b/block/io.c
53
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
54
--- a/block/io.c
41
--- a/block/io.c
55
+++ b/block/io.c
42
+++ b/block/io.c
56
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
44
goto out;
57
}
45
}
58
46
59
/* Default alignment based on whether driver has byte interface */
47
+ /*
60
- bs->bl.request_alignment = drv->bdrv_co_preadv ? 1 : 512;
48
+ * If the image has a backing file that is large enough that it would
61
+ bs->bl.request_alignment = (drv->bdrv_co_preadv ||
49
+ * provide data for the new area, we cannot leave it unallocated because
62
+ drv->bdrv_aio_preadv) ? 1 : 512;
50
+ * then the backing file content would become visible. Instead, zero-fill
63
51
+ * the new area.
64
/* Take some limits from the children as a default */
52
+ *
65
if (bs->file) {
53
+ * Note that if the image has a backing file, but was opened without the
66
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
54
+ * backing file, taking care of keeping things consistent with that backing
67
return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags);
55
+ * file is the user's responsibility.
68
}
56
+ */
69
57
+ if (new_bytes && bs->backing) {
70
+ /* FIXME - no need to calculate these if .bdrv_aio_preadv exists */
58
+ int64_t backing_len;
71
sector_num = offset >> BDRV_SECTOR_BITS;
59
+
72
nb_sectors = bytes >> BDRV_SECTOR_BITS;
60
+ backing_len = bdrv_getlength(backing_bs(bs));
73
61
+ if (backing_len < 0) {
74
- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
62
+ ret = backing_len;
75
- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
76
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
64
+ goto out;
77
+ if (!drv->bdrv_aio_preadv) {
65
+ }
78
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
66
+
79
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
67
+ if (backing_len > old_size) {
80
+ assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
68
+ flags |= BDRV_REQ_ZERO_WRITE;
69
+ }
81
+ }
70
+ }
82
71
+
83
if (drv->bdrv_co_readv) {
72
if (drv->bdrv_co_truncate) {
84
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
73
if (flags & ~bs->supported_truncate_flags) {
85
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
74
error_setg(errp, "Block driver does not support requested flags");
86
.coroutine = qemu_coroutine_self(),
87
};
88
89
- acb = bs->drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
90
+ if (drv->bdrv_aio_preadv) {
91
+ acb = drv->bdrv_aio_preadv(bs, offset, bytes, qiov, flags,
92
+ bdrv_co_io_em_complete, &co);
93
+ } else {
94
+ acb = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
95
bdrv_co_io_em_complete, &co);
96
+ }
97
if (acb == NULL) {
98
return -EIO;
99
} else {
100
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
101
goto emulate_flags;
102
}
103
104
+ /* FIXME - no need to calculate these if .bdrv_aio_pwritev exists */
105
sector_num = offset >> BDRV_SECTOR_BITS;
106
nb_sectors = bytes >> BDRV_SECTOR_BITS;
107
108
- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
109
- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
110
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
111
+ if (!drv->bdrv_aio_pwritev) {
112
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
113
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
114
+ assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
115
+ }
116
117
if (drv->bdrv_co_writev_flags) {
118
ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
119
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
120
.coroutine = qemu_coroutine_self(),
121
};
122
123
- acb = bs->drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
124
+ if (drv->bdrv_aio_pwritev) {
125
+ acb = drv->bdrv_aio_pwritev(bs, offset, bytes, qiov,
126
+ flags & bs->supported_write_flags,
127
+ bdrv_co_io_em_complete, &co);
128
+ flags &= ~bs->supported_write_flags;
129
+ } else {
130
+ assert(!bs->supported_write_flags);
131
+ acb = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
132
bdrv_co_io_em_complete, &co);
133
+ }
134
if (acb == NULL) {
135
ret = -EIO;
136
} else {
137
--
75
--
138
2.13.6
76
2.25.3
139
77
140
78
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
We are gradually moving away from sector-based interfaces, towards
4
byte-based. Make the change for the last few sector-based callbacks
5
in the file-win32 driver.
6
7
Note that the driver was already using byte-based calls for
8
performing actual I/O, so this just gets rid of a round trip
9
of scaling; however, as I don't know if Windows is tolerant of
10
non-sector AIO operations, I went with the conservative approach
11
of modifying .bdrv_refresh_limits to override the block layer
12
defaults back to the pre-patch value of 512.
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
include/block/raw-aio.h | 2 +-
18
block/file-win32.c | 47 +++++++++++++++++++++++++++++------------------
19
block/win32-aio.c | 5 ++---
20
3 files changed, 32 insertions(+), 22 deletions(-)
21
22
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/raw-aio.h
25
+++ b/include/block/raw-aio.h
26
@@ -XXX,XX +XXX,XX @@ void win32_aio_cleanup(QEMUWin32AIOState *aio);
27
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
28
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
29
QEMUWin32AIOState *aio, HANDLE hfile,
30
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
31
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
32
BlockCompletionFunc *cb, void *opaque, int type);
33
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
34
AioContext *old_context);
35
diff --git a/block/file-win32.c b/block/file-win32.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/file-win32.c
38
+++ b/block/file-win32.c
39
@@ -XXX,XX +XXX,XX @@ static void raw_probe_alignment(BlockDriverState *bs, Error **errp)
40
&dg.Geometry.BytesPerSector,
41
&freeClusters, &totalClusters);
42
bs->bl.request_alignment = dg.Geometry.BytesPerSector;
43
+ return;
44
}
45
+
46
+ /* XXX Does Windows support AIO on less than 512-byte alignment? */
47
+ bs->bl.request_alignment = 512;
48
}
49
50
static void raw_parse_flags(int flags, bool use_aio, int *access_flags,
51
@@ -XXX,XX +XXX,XX @@ fail:
52
return ret;
53
}
54
55
-static BlockAIOCB *raw_aio_readv(BlockDriverState *bs,
56
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
57
- BlockCompletionFunc *cb, void *opaque)
58
+static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
59
+ uint64_t offset, uint64_t bytes,
60
+ QEMUIOVector *qiov, int flags,
61
+ BlockCompletionFunc *cb, void *opaque)
62
{
63
BDRVRawState *s = bs->opaque;
64
if (s->aio) {
65
- return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
66
- nb_sectors, cb, opaque, QEMU_AIO_READ);
67
+ return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov,
68
+ cb, opaque, QEMU_AIO_READ);
69
} else {
70
- return paio_submit(bs, s->hfile, sector_num << BDRV_SECTOR_BITS, qiov,
71
- nb_sectors << BDRV_SECTOR_BITS,
72
+ return paio_submit(bs, s->hfile, offset, qiov, bytes,
73
cb, opaque, QEMU_AIO_READ);
74
}
75
}
76
77
-static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,
78
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
79
- BlockCompletionFunc *cb, void *opaque)
80
+static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs,
81
+ uint64_t offset, uint64_t bytes,
82
+ QEMUIOVector *qiov, int flags,
83
+ BlockCompletionFunc *cb, void *opaque)
84
{
85
BDRVRawState *s = bs->opaque;
86
if (s->aio) {
87
- return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
88
- nb_sectors, cb, opaque, QEMU_AIO_WRITE);
89
+ return win32_aio_submit(bs, s->aio, s->hfile, offset, bytes, qiov,
90
+ cb, opaque, QEMU_AIO_WRITE);
91
} else {
92
- return paio_submit(bs, s->hfile, sector_num << BDRV_SECTOR_BITS, qiov,
93
- nb_sectors << BDRV_SECTOR_BITS,
94
+ return paio_submit(bs, s->hfile, offset, qiov, bytes,
95
cb, opaque, QEMU_AIO_WRITE);
96
}
97
}
98
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
99
.bdrv_co_create_opts = raw_co_create_opts,
100
.bdrv_has_zero_init = bdrv_has_zero_init_1,
101
102
- .bdrv_aio_readv = raw_aio_readv,
103
- .bdrv_aio_writev = raw_aio_writev,
104
+ .bdrv_aio_preadv = raw_aio_preadv,
105
+ .bdrv_aio_pwritev = raw_aio_pwritev,
106
.bdrv_aio_flush = raw_aio_flush,
107
108
.bdrv_truncate    = raw_truncate,
109
@@ -XXX,XX +XXX,XX @@ static void hdev_parse_filename(const char *filename, QDict *options,
110
bdrv_parse_filename_strip_prefix(filename, "host_device:", options);
111
}
112
113
+static void hdev_refresh_limits(BlockDriverState *bs, Error **errp)
114
+{
115
+ /* XXX Does Windows support AIO on less than 512-byte alignment? */
116
+ bs->bl.request_alignment = 512;
117
+}
118
+
119
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
120
Error **errp)
121
{
122
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
123
.bdrv_probe_device    = hdev_probe_device,
124
.bdrv_file_open    = hdev_open,
125
.bdrv_close        = raw_close,
126
+ .bdrv_refresh_limits = hdev_refresh_limits,
127
128
- .bdrv_aio_readv = raw_aio_readv,
129
- .bdrv_aio_writev = raw_aio_writev,
130
+ .bdrv_aio_preadv = raw_aio_preadv,
131
+ .bdrv_aio_pwritev = raw_aio_pwritev,
132
.bdrv_aio_flush = raw_aio_flush,
133
134
.bdrv_detach_aio_context = raw_detach_aio_context,
135
diff --git a/block/win32-aio.c b/block/win32-aio.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/win32-aio.c
138
+++ b/block/win32-aio.c
139
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo win32_aiocb_info = {
140
141
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
142
QEMUWin32AIOState *aio, HANDLE hfile,
143
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
144
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
145
BlockCompletionFunc *cb, void *opaque, int type)
146
{
147
struct QEMUWin32AIOCB *waiocb;
148
- uint64_t offset = sector_num * 512;
149
DWORD rc;
150
151
waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque);
152
- waiocb->nbytes = nb_sectors * 512;
153
+ waiocb->nbytes = bytes;
154
waiocb->qiov = qiov;
155
waiocb->is_read = (type == QEMU_AIO_READ);
156
157
--
158
2.13.6
159
160
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
We are gradually moving away from sector-based interfaces, towards
4
byte-based. Make the change for the last few sector-based callbacks
5
in the null-co and null-aio drivers.
6
7
Note that since the null driver does nothing on writes, it trivially
8
supports the BDRV_REQ_FUA flag (all writes have already landed to
9
the same bit-bucket without needing an extra flush call). Also, since
10
the null driver does just as well with byte-based requests, we can
11
now avoid cycles wasted on read-modify-write by taking advantage of
12
the block layer now defaulting the alignment to 1 instead of 512.
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/null.c | 45 +++++++++++++++++++++++----------------------
18
1 file changed, 23 insertions(+), 22 deletions(-)
19
20
diff --git a/block/null.c b/block/null.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/null.c
23
+++ b/block/null.c
24
@@ -XXX,XX +XXX,XX @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
25
}
26
s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
27
qemu_opts_del(opts);
28
+ bs->supported_write_flags = BDRV_REQ_FUA;
29
return ret;
30
}
31
32
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
33
return 0;
34
}
35
36
-static coroutine_fn int null_co_readv(BlockDriverState *bs,
37
- int64_t sector_num, int nb_sectors,
38
- QEMUIOVector *qiov)
39
+static coroutine_fn int null_co_preadv(BlockDriverState *bs,
40
+ uint64_t offset, uint64_t bytes,
41
+ QEMUIOVector *qiov, int flags)
42
{
43
BDRVNullState *s = bs->opaque;
44
45
if (s->read_zeroes) {
46
- qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
47
+ qemu_iovec_memset(qiov, 0, 0, bytes);
48
}
49
50
return null_co_common(bs);
51
}
52
53
-static coroutine_fn int null_co_writev(BlockDriverState *bs,
54
- int64_t sector_num, int nb_sectors,
55
- QEMUIOVector *qiov)
56
+static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
57
+ uint64_t offset, uint64_t bytes,
58
+ QEMUIOVector *qiov, int flags)
59
{
60
return null_co_common(bs);
61
}
62
@@ -XXX,XX +XXX,XX @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
63
return &acb->common;
64
}
65
66
-static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
67
- int64_t sector_num, QEMUIOVector *qiov,
68
- int nb_sectors,
69
- BlockCompletionFunc *cb,
70
- void *opaque)
71
+static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
72
+ uint64_t offset, uint64_t bytes,
73
+ QEMUIOVector *qiov, int flags,
74
+ BlockCompletionFunc *cb,
75
+ void *opaque)
76
{
77
BDRVNullState *s = bs->opaque;
78
79
if (s->read_zeroes) {
80
- qemu_iovec_memset(qiov, 0, 0, nb_sectors * BDRV_SECTOR_SIZE);
81
+ qemu_iovec_memset(qiov, 0, 0, bytes);
82
}
83
84
return null_aio_common(bs, cb, opaque);
85
}
86
87
-static BlockAIOCB *null_aio_writev(BlockDriverState *bs,
88
- int64_t sector_num, QEMUIOVector *qiov,
89
- int nb_sectors,
90
- BlockCompletionFunc *cb,
91
- void *opaque)
92
+static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
93
+ uint64_t offset, uint64_t bytes,
94
+ QEMUIOVector *qiov, int flags,
95
+ BlockCompletionFunc *cb,
96
+ void *opaque)
97
{
98
return null_aio_common(bs, cb, opaque);
99
}
100
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_co = {
101
.bdrv_close = null_close,
102
.bdrv_getlength = null_getlength,
103
104
- .bdrv_co_readv = null_co_readv,
105
- .bdrv_co_writev = null_co_writev,
106
+ .bdrv_co_preadv = null_co_preadv,
107
+ .bdrv_co_pwritev = null_co_pwritev,
108
.bdrv_co_flush_to_disk = null_co_flush,
109
.bdrv_reopen_prepare = null_reopen_prepare,
110
111
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_null_aio = {
112
.bdrv_close = null_close,
113
.bdrv_getlength = null_getlength,
114
115
- .bdrv_aio_readv = null_aio_readv,
116
- .bdrv_aio_writev = null_aio_writev,
117
+ .bdrv_aio_preadv = null_aio_preadv,
118
+ .bdrv_aio_pwritev = null_aio_pwritev,
119
.bdrv_aio_flush = null_aio_flush,
120
.bdrv_reopen_prepare = null_reopen_prepare,
121
122
--
123
2.13.6
124
125
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
We want to keep TEST_IMG for the full path of the main test image, but
2
filter_testfiles() must be called for other test images before replacing
3
other things like the image format because the test directory path could
4
contain the format as a substring.
2
5
3
The QMP version of this command can take a qdev ID since 7a9877a02635,
6
Insert a filter_testfiles() call between both.
4
but the HMP version is still using the deprecated block device name so
5
there's no way to refer to a block device added like this:
6
7
7
-blockdev node-name=disk0,driver=qcow2,file.driver=file,file.filename=hd.qcow2
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
-device virtio-blk-pci,id=virtio-blk-pci0,drive=disk0
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
This patch works around this problem by using the specified name as a
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
11
qdev ID if the block device name is not found.
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
13
---
17
hmp.c | 14 ++++++++++++--
14
tests/qemu-iotests/iotests.py | 5 +++--
18
hmp-commands.hx | 3 ++-
15
1 file changed, 3 insertions(+), 2 deletions(-)
19
2 files changed, 14 insertions(+), 3 deletions(-)
20
16
21
diff --git a/hmp.c b/hmp.c
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
22
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
23
--- a/hmp.c
19
--- a/tests/qemu-iotests/iotests.py
24
+++ b/hmp.c
20
+++ b/tests/qemu-iotests/iotests.py
25
@@ -XXX,XX +XXX,XX @@ void hmp_change(Monitor *mon, const QDict *qdict)
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
26
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
22
for line in output.split('\n'):
27
{
23
if 'disk size' in line or 'actual-size' in line:
28
Error *err = NULL;
24
continue
29
+ char *device = (char *) qdict_get_str(qdict, "device");
25
- line = line.replace(filename, 'TEST_IMG') \
30
BlockIOThrottle throttle = {
26
- .replace(imgfmt, 'IMGFMT')
31
- .has_device = true,
27
+ line = line.replace(filename, 'TEST_IMG')
32
- .device = (char *) qdict_get_str(qdict, "device"),
28
+ line = filter_testfiles(line)
33
.bps = qdict_get_int(qdict, "bps"),
29
+ line = line.replace(imgfmt, 'IMGFMT')
34
.bps_rd = qdict_get_int(qdict, "bps_rd"),
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
35
.bps_wr = qdict_get_int(qdict, "bps_wr"),
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
36
@@ -XXX,XX +XXX,XX @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
37
.iops_wr = qdict_get_int(qdict, "iops_wr"),
38
};
39
40
+ /* qmp_block_set_io_throttle has separate parameters for the
41
+ * (deprecated) block device name and the qdev ID but the HMP
42
+ * version has only one, so we must decide which one to pass. */
43
+ if (blk_by_name(device)) {
44
+ throttle.has_device = true;
45
+ throttle.device = device;
46
+ } else {
47
+ throttle.has_id = true;
48
+ throttle.id = device;
49
+ }
50
+
51
qmp_block_set_io_throttle(&throttle, &err);
52
hmp_handle_error(mon, &err);
53
}
54
diff --git a/hmp-commands.hx b/hmp-commands.hx
55
index XXXXXXX..XXXXXXX 100644
56
--- a/hmp-commands.hx
57
+++ b/hmp-commands.hx
58
@@ -XXX,XX +XXX,XX @@ ETEXI
59
STEXI
60
@item block_set_io_throttle @var{device} @var{bps} @var{bps_rd} @var{bps_wr} @var{iops} @var{iops_rd} @var{iops_wr}
61
@findex block_set_io_throttle
62
-Change I/O throttle limits for a block drive to @var{bps} @var{bps_rd} @var{bps_wr} @var{iops} @var{iops_rd} @var{iops_wr}
63
+Change I/O throttle limits for a block drive to @var{bps} @var{bps_rd} @var{bps_wr} @var{iops} @var{iops_rd} @var{iops_wr}.
64
+@var{device} can be a block device name, a qdev ID or a QOM path.
65
ETEXI
66
67
{
68
--
33
--
69
2.13.6
34
2.25.3
70
35
71
36
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/group | 1 +
10
3 files changed, 424 insertions(+)
11
create mode 100755 tests/qemu-iotests/274
12
create mode 100644 tests/qemu-iotests/274.out
2
13
3
COR across nodes (that is, you have some filter node between the
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
4
actually COR target and the node that performs the COR) cannot reliably
5
work together with the permission system when there is no explicit COR
6
node that can request the WRITE_UNCHANGED permission for its child.
7
This is because COR (currently) sneaks its requests by the usual
8
permission checks, so it can work without a WRITE* permission; but if
9
there is a filter node in between, that will re-issue the request, which
10
then passes through the usual check -- and if nobody has requested a
11
WRITE_UNCHANGED permission, that check will fail.
12
13
There is no real direct fix apart from hoping that there is someone who
14
has requested that permission; in case of just the qemu-io HMP command
15
(and no guest device), however, that is not the case. The real real fix
16
is to implement the copy-on-read flag through an implicitly added COR
17
node. Such a node can request the necessary permissions as shown in
18
this test.
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Message-id: 20180421132929.21610-10-mreitz@redhat.com
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
tests/qemu-iotests/216 | 115 +++++++++++++++++++++++++++++++++++++++++++++
26
tests/qemu-iotests/216.out | 28 +++++++++++
27
tests/qemu-iotests/group | 1 +
28
3 files changed, 144 insertions(+)
29
create mode 100755 tests/qemu-iotests/216
30
create mode 100644 tests/qemu-iotests/216.out
31
32
diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216
33
new file mode 100755
15
new file mode 100755
34
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
35
--- /dev/null
17
--- /dev/null
36
+++ b/tests/qemu-iotests/216
18
+++ b/tests/qemu-iotests/274
37
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
38
+#!/usr/bin/env python
20
+#!/usr/bin/env python3
39
+#
21
+#
40
+# Copy-on-read tests using a COR filter node
22
+# Copyright (C) 2019 Red Hat, Inc.
41
+#
42
+# Copyright (C) 2018 Red Hat, Inc.
43
+#
23
+#
44
+# This program is free software; you can redistribute it and/or modify
24
+# This program is free software; you can redistribute it and/or modify
45
+# it under the terms of the GNU General Public License as published by
25
+# it under the terms of the GNU General Public License as published by
46
+# the Free Software Foundation; either version 2 of the License, or
26
+# the Free Software Foundation; either version 2 of the License, or
47
+# (at your option) any later version.
27
+# (at your option) any later version.
...
...
52
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
53
+#
33
+#
54
+# You should have received a copy of the GNU General Public License
34
+# You should have received a copy of the GNU General Public License
55
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
56
+#
36
+#
57
+# Creator/Owner: Max Reitz <mreitz@redhat.com>
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
38
+#
39
+# Some tests for short backing files and short overlays
58
+
40
+
59
+import iotests
41
+import iotests
60
+from iotests import log, qemu_img_pipe, qemu_io, filter_qemu_io
42
+
61
+
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
62
+# Need backing file support
63
+iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk'])
64
+iotests.verify_platform(['linux'])
44
+iotests.verify_platform(['linux'])
65
+
45
+
66
+log('')
46
+size_short = 1 * 1024 * 1024
67
+log('=== Copy-on-read across nodes ===')
47
+size_long = 2 * 1024 * 1024
68
+log('')
48
+size_diff = size_long - size_short
69
+
49
+
70
+# The old copy-on-read mechanism without a filter node cannot request
50
+def create_chain() -> None:
71
+# WRITE_UNCHANGED permissions for its child. Therefore it just tries
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
72
+# to sneak its write by the usual permission system and holds its
52
+ str(size_long))
73
+# fingers crossed. However, that sneaking does not work so well when
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
74
+# there is a filter node in the way: That will receive the write
54
+ str(size_short))
75
+# request and re-issue a new one to its child, which this time is a
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
76
+# proper write request that will make the permission system cough --
56
+ str(size_long))
77
+# unless there is someone at the top (like a guest device) that has
57
+
78
+# requested write permissions.
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
79
+#
59
+
80
+# A COR filter node, however, can request the proper permissions for
60
+def create_vm() -> iotests.VM:
81
+# its child and therefore is not hit by this issue.
61
+ vm = iotests.VM()
82
+
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
83
+with iotests.FilePath('base.img') as base_img_path, \
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
84
+ iotests.FilePath('top.img') as top_img_path, \
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
85
+ iotests.VM() as vm:
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
86
+
66
+ % iotests.imgfmt)
87
+ log('--- Setting up images ---')
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
88
+ log('')
68
+ return vm
89
+
69
+
90
+ qemu_img_pipe('create', '-f', iotests.imgfmt, base_img_path, '64M')
70
+with iotests.FilePath('base') as base, \
91
+
71
+ iotests.FilePath('mid') as mid, \
92
+ log(filter_qemu_io(qemu_io(base_img_path, '-c', 'write -P 1 0M 1M')))
72
+ iotests.FilePath('top') as top:
93
+
73
+
94
+ qemu_img_pipe('create', '-f', iotests.imgfmt, '-b', base_img_path,
74
+ iotests.log('== Commit tests ==')
95
+ top_img_path)
75
+
96
+
76
+ create_chain()
97
+ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'write -P 2 1M 1M')))
77
+
98
+
78
+ iotests.log('=== Check visible data ===')
99
+ log('')
79
+
100
+ log('--- Doing COR ---')
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
101
+ log('')
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
102
+
82
+
103
+ # Compare with e.g. the following:
83
+ iotests.log('=== Checking allocation status ===')
104
+ # vm.add_drive_raw('if=none,node-name=node0,copy-on-read=on,driver=raw,' \
84
+
105
+ # 'file.driver=%s,file.file.filename=%s' %
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
106
+ # (iotests.imgfmt, top_img_path))
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
107
+ # (Remove the blockdev-add instead.)
87
+ base)
108
+ # ((Not tested here because it hits an assertion in the permission
88
+
109
+ # system.))
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
110
+
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
111
+ vm.launch()
91
+ mid)
112
+
92
+
113
+ log(vm.qmp('blockdev-add',
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
114
+ node_name='node0',
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
115
+ driver='copy-on-read',
95
+ top)
116
+ file={
96
+
117
+ 'driver': 'raw',
97
+ iotests.log('=== Checking map ===')
118
+ 'file': {
98
+
119
+ 'driver': 'copy-on-read',
99
+ iotests.qemu_img_log('map', '--output=json', base)
120
+ 'file': {
100
+ iotests.qemu_img_log('map', '--output=human', base)
121
+ 'driver': 'raw',
101
+ iotests.qemu_img_log('map', '--output=json', mid)
122
+ 'file': {
102
+ iotests.qemu_img_log('map', '--output=human', mid)
123
+ 'driver': iotests.imgfmt,
103
+ iotests.qemu_img_log('map', '--output=json', top)
124
+ 'file': {
104
+ iotests.qemu_img_log('map', '--output=human', top)
125
+ 'driver': 'file',
105
+
126
+ 'filename': top_img_path
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
127
+ },
107
+
128
+ 'backing': {
108
+ iotests.qemu_img_log('commit', top)
129
+ 'driver': iotests.imgfmt,
109
+ iotests.img_info_log(mid)
130
+ 'file': {
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
131
+ 'driver': 'file',
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
132
+ 'filename': base_img_path
112
+
133
+ }
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
134
+ }
114
+
135
+ }
115
+ create_chain()
136
+ }
116
+ with create_vm() as vm:
137
+ }
117
+ vm.launch()
138
+ }))
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
139
+
119
+
140
+ # Trigger COR
120
+ iotests.img_info_log(mid)
141
+ log(vm.qmp('human-monitor-command',
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
142
+ command_line='qemu-io node0 "read 0 64M"'))
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
143
+
123
+
144
+ vm.shutdown()
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
145
+
125
+
146
+ log('')
126
+ create_chain()
147
+ log('--- Checking COR result ---')
127
+ with create_vm() as vm:
148
+ log('')
128
+ vm.launch()
149
+
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
150
+ log(filter_qemu_io(qemu_io(base_img_path, '-c', 'discard 0 64M')))
130
+ job_id='job0', auto_dismiss=False)
151
+ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 1 0M 1M')))
131
+ vm.run_job('job0', wait=5)
152
+ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 2 1M 1M')))
132
+
153
diff --git a/tests/qemu-iotests/216.out b/tests/qemu-iotests/216.out
133
+ iotests.img_info_log(mid)
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
136
+
137
+
138
+ iotests.log('== Resize tests ==')
139
+
140
+ # Use different sizes for different allocation modes:
141
+ #
142
+ # We want to have at least one test where 32 bit truncation in the size of
143
+ # the overlapping area becomes visible. This is covered by the
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
145
+ #
146
+ # However, we can only do this for modes that don't preallocate data
147
+ # because otherwise we might run out of space on the test host.
148
+ #
149
+ # We also want to test some unaligned combinations.
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
151
+ ('off', '6G', '1G', '8G', '5G'),
152
+ ('metadata', '32G', '30G', '33G', '31G'),
153
+ ('falloc', '10M', '5M', '15M', '9M'),
154
+ ('full', '16M', '8M', '12M', '11M'),
155
+ ('off', '384k', '253k', '512k', '253k'),
156
+ ('off', '400k', '256k', '512k', '336k'),
157
+ ('off', '512k', '256k', '500k', '436k')]:
158
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
162
+ top_size_old)
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
164
+
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
166
+ #
167
+ # In theory, leaving base_size to top_size_new unallocated would be
168
+ # correct, but in practice, if we zero out anything, we zero out
169
+ # everything up to top_size_new.
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
171
+ '--preallocation', prealloc, top, top_size_new)
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
173
+ iotests.qemu_io_log('-c', 'map', top)
174
+ iotests.qemu_img_log('map', '--output=json', top)
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
154
new file mode 100644
176
new file mode 100644
155
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
156
--- /dev/null
178
--- /dev/null
157
+++ b/tests/qemu-iotests/216.out
179
+++ b/tests/qemu-iotests/274.out
158
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
159
+
181
+== Commit tests ==
160
+=== Copy-on-read across nodes ===
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
161
+
183
+
162
+--- Setting up images ---
184
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
163
+
185
+
164
+wrote 1048576/1048576 bytes at offset 0
186
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
165
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
187
+
166
+
188
+wrote 2097152/2097152 bytes at offset 0
167
+wrote 1048576/1048576 bytes at offset 1048576
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
190
+
169
+
191
+=== Check visible data ===
170
+
171
+--- Doing COR ---
172
+
173
+{u'return': {}}
174
+{u'return': u''}
175
+
176
+--- Checking COR result ---
177
+
178
+discard 67108864/67108864 bytes at offset 0
179
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
180
+
181
+read 1048576/1048576 bytes at offset 0
192
+read 1048576/1048576 bytes at offset 0
182
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
183
+
194
+
184
+read 1048576/1048576 bytes at offset 1048576
195
+read 1048576/1048576 bytes at offset 1048576
185
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
197
+
198
+=== Checking allocation status ===
199
+1048576/1048576 bytes allocated at offset 0 bytes
200
+1048576/1048576 bytes allocated at offset 1 MiB
201
+
202
+0/1048576 bytes allocated at offset 0 bytes
203
+0/0 bytes allocated at offset 1 MiB
204
+
205
+0/1048576 bytes allocated at offset 0 bytes
206
+0/1048576 bytes allocated at offset 1 MiB
207
+
208
+=== Checking map ===
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
211
+Offset Length Mapped to File
212
+0 0x200000 0x50000 TEST_DIR/PID-base
213
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
215
+
216
+Offset Length Mapped to File
217
+0 0x100000 0x50000 TEST_DIR/PID-base
218
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
222
+Offset Length Mapped to File
223
+0 0x100000 0x50000 TEST_DIR/PID-base
224
+
225
+=== Testing qemu-img commit (top -> mid) ===
226
+Image committed.
227
+
228
+image: TEST_IMG
229
+file format: IMGFMT
230
+virtual size: 2 MiB (2097152 bytes)
231
+cluster_size: 65536
232
+backing file: TEST_DIR/PID-base
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
239
+read 1048576/1048576 bytes at offset 0
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
242
+read 1048576/1048576 bytes at offset 1048576
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
244
+
245
+=== Testing HMP commit (top -> mid) ===
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
247
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
249
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
251
+
252
+wrote 2097152/2097152 bytes at offset 0
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
256
+{"return": ""}
257
+image: TEST_IMG
258
+file format: IMGFMT
259
+virtual size: 2 MiB (2097152 bytes)
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
268
+read 1048576/1048576 bytes at offset 0
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
+
271
+read 1048576/1048576 bytes at offset 1048576
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+
274
+=== Testing QMP active commit (top -> mid) ===
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
280
+
281
+wrote 2097152/2097152 bytes at offset 0
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
283
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
285
+{"return": {}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
287
+{"return": {}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
333
+
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
186
+
448
+
187
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
188
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
189
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
190
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
191
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
192
213 rw auto quick
454
270 rw backing quick
193
214 rw auto
455
272 rw
194
215 rw auto quick
456
273 backing quick
195
+216 rw auto quick
457
+274 rw backing
196
218 rw auto quick
458
277 rw quick
459
279 rw backing quick
460
280 rw migration quick
197
--
461
--
198
2.13.6
462
2.25.3
199
463
200
464
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
2
image is possibly preallocated and then the zero flag is added to all
3
clusters. This means that a copy-on-write operation may be needed when
4
writing to these clusters, despite having used preallocation, negating
5
one of the major benefits of preallocation.
2
6
3
The L2 and refcount caches have default sizes that can be overridden
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
4
using the l2-cache-size and refcount-cache-size (an additional
8
and if the protocol driver can ensure that the new area reads as zeros,
5
parameter named cache-size sets the combined size of both caches).
9
we can skip setting the zero flag in the qcow2 layer.
6
10
7
Unless forced by one of the aforementioned parameters, QEMU will set
11
Unfortunately, the same approach doesn't work for metadata
8
the unspecified sizes so that the L2 cache is 4 times larger than the
12
preallocation, so we'll still set the zero flag there.
9
refcount cache.
10
13
11
This is based on the premise that the refcount metadata needs to be
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
only a fourth of the L2 metadata to cover the same amount of disk
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
space. This is incorrect for two reasons:
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
block/qcow2.c | 22 +++++++++++++++++++---
21
tests/qemu-iotests/274.out | 4 ++--
22
2 files changed, 21 insertions(+), 5 deletions(-)
14
23
15
a) The amount of disk covered by an L2 table depends solely on the
16
cluster size, but in the case of a refcount block it depends on
17
the cluster size *and* the width of each refcount entry.
18
The 4/1 ratio is only valid with 16-bit entries (the default).
19
20
b) When we talk about disk space and L2 tables we are talking about
21
guest space (L2 tables map guest clusters to host clusters),
22
whereas refcount blocks are used for host clusters (including
23
L1/L2 tables and the refcount blocks themselves). On a fully
24
populated (and uncompressed) qcow2 file, image size > virtual size
25
so there are more refcount entries than L2 entries.
26
27
Problem (a) could be fixed by adjusting the algorithm to take into
28
account the refcount entry width. Problem (b) could be fixed by
29
increasing a bit the refcount cache size to account for the clusters
30
used for qcow2 metadata.
31
32
However this patch takes a completely different approach and instead
33
of keeping a ratio between both cache sizes it assigns as much as
34
possible to the L2 cache and the remainder to the refcount cache.
35
36
The reason is that L2 tables are used for every single I/O request
37
from the guest and the effect of increasing the cache is significant
38
and clearly measurable. Refcount blocks are however only used for
39
cluster allocation and internal snapshots and in practice are accessed
40
sequentially in most cases, so the effect of increasing the cache is
41
negligible (even when doing random writes from the guest).
42
43
So, make the refcount cache as small as possible unless the user
44
explicitly asks for a larger one.
45
46
Signed-off-by: Alberto Garcia <berto@igalia.com>
47
Reviewed-by: Eric Blake <eblake@redhat.com>
48
Reviewed-by: Max Reitz <mreitz@redhat.com>
49
Message-id: 9695182c2eb11b77cb319689a1ebaa4e7c9d6591.1523968389.git.berto@igalia.com
50
Signed-off-by: Max Reitz <mreitz@redhat.com>
51
---
52
block/qcow2.h | 4 ----
53
block/qcow2.c | 31 +++++++++++++++++++------------
54
tests/qemu-iotests/137.out | 2 +-
55
3 files changed, 20 insertions(+), 17 deletions(-)
56
57
diff --git a/block/qcow2.h b/block/qcow2.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/qcow2.h
60
+++ b/block/qcow2.h
61
@@ -XXX,XX +XXX,XX @@
62
#define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */
63
#define DEFAULT_L2_CACHE_BYTE_SIZE 1048576 /* bytes */
64
65
-/* The refblock cache needs only a fourth of the L2 cache size to cover as many
66
- * clusters */
67
-#define DEFAULT_L2_REFCOUNT_SIZE_RATIO 4
68
-
69
#define DEFAULT_CLUSTER_SIZE 65536
70
71
72
diff --git a/block/qcow2.c b/block/qcow2.c
24
diff --git a/block/qcow2.c b/block/qcow2.c
73
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
74
--- a/block/qcow2.c
26
--- a/block/qcow2.c
75
+++ b/block/qcow2.c
27
+++ b/block/qcow2.c
76
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
77
} else if (refcount_cache_size_set) {
29
/* Allocate the data area */
78
*l2_cache_size = combined_cache_size - *refcount_cache_size;
30
new_file_size = allocation_start +
79
} else {
31
nb_new_data_clusters * s->cluster_size;
80
- *refcount_cache_size = combined_cache_size
32
- /* Image file grows, so @exact does not matter */
81
- / (DEFAULT_L2_REFCOUNT_SIZE_RATIO + 1);
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
82
- *l2_cache_size = combined_cache_size - *refcount_cache_size;
34
- errp);
83
+ uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
35
+ /*
84
+ uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
36
+ * Image file grows, so @exact does not matter.
85
+ uint64_t min_refcount_cache =
37
+ *
86
+ (uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
38
+ * If we need to zero out the new area, try first whether the protocol
87
+
39
+ * driver can already take care of this.
88
+ /* Assign as much memory as possible to the L2 cache, and
40
+ */
89
+ * use the remainder for the refcount cache */
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
90
+ if (combined_cache_size >= max_l2_cache + min_refcount_cache) {
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
91
+ *l2_cache_size = max_l2_cache;
43
+ BDRV_REQ_ZERO_WRITE, NULL);
92
+ *refcount_cache_size = combined_cache_size - *l2_cache_size;
44
+ if (ret >= 0) {
93
+ } else {
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
94
+ *refcount_cache_size =
95
+ MIN(combined_cache_size, min_refcount_cache);
96
+ *l2_cache_size = combined_cache_size - *refcount_cache_size;
97
+ }
46
+ }
98
}
47
+ } else {
99
} else {
48
+ ret = -1;
100
- if (!l2_cache_size_set && !refcount_cache_size_set) {
101
+ if (!l2_cache_size_set) {
102
*l2_cache_size = MAX(DEFAULT_L2_CACHE_BYTE_SIZE,
103
(uint64_t)DEFAULT_L2_CACHE_CLUSTERS
104
* s->cluster_size);
105
- *refcount_cache_size = *l2_cache_size
106
- / DEFAULT_L2_REFCOUNT_SIZE_RATIO;
107
- } else if (!l2_cache_size_set) {
108
- *l2_cache_size = *refcount_cache_size
109
- * DEFAULT_L2_REFCOUNT_SIZE_RATIO;
110
- } else if (!refcount_cache_size_set) {
111
- *refcount_cache_size = *l2_cache_size
112
- / DEFAULT_L2_REFCOUNT_SIZE_RATIO;
113
+ }
49
+ }
114
+ if (!refcount_cache_size_set) {
50
+ if (ret < 0) {
115
+ *refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
116
}
52
+ errp);
117
}
53
+ }
118
54
if (ret < 0) {
119
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
55
error_prepend(errp, "Failed to resize underlying file: ");
56
qcow2_free_clusters(bs, allocation_start,
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
120
index XXXXXXX..XXXXXXX 100644
58
index XXXXXXX..XXXXXXX 100644
121
--- a/tests/qemu-iotests/137.out
59
--- a/tests/qemu-iotests/274.out
122
+++ b/tests/qemu-iotests/137.out
60
+++ b/tests/qemu-iotests/274.out
123
@@ -XXX,XX +XXX,XX @@ refcount-cache-size may not exceed cache-size
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
124
L2 cache size too big
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
125
L2 cache entry size must be a power of two between 512 and the cluster size (65536)
63
126
L2 cache entry size must be a power of two between 512 and the cluster size (65536)
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
127
-L2 cache size too big
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
128
+Refcount cache size too big
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
129
Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
67
130
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
68
=== preallocation=full ===
131
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
72
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
76
77
=== preallocation=off ===
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
132
--
79
--
133
2.13.6
80
2.25.3
134
81
135
82
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
2
3
We are gradually moving away from sector-based interfaces, towards
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
4
byte-based. Now that all drivers with aio callbacks are using the
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
5
byte-based interfaces, we can remove the sector-based versions.
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
7
persistent across system reboot.
6
8
7
Signed-off-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
15
---
10
include/block/block_int.h | 6 ----
16
hw/block/nvme.h | 2 +
11
block/io.c | 84 ++++++++++++++++++++---------------------------
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
12
2 files changed, 36 insertions(+), 54 deletions(-)
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
19
hw/block/Makefile.objs | 2 +-
20
hw/block/trace-events | 4 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
13
22
14
diff --git a/include/block/block_int.h b/include/block/block_int.h
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
15
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block_int.h
25
--- a/hw/block/nvme.h
17
+++ b/include/block/block_int.h
26
+++ b/hw/block/nvme.h
18
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
19
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
20
29
21
/* aio */
30
char *serial;
22
- BlockAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
31
+ HostMemoryBackend *pmrdev;
23
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
32
+
24
- BlockCompletionFunc *cb, void *opaque);
33
NvmeNamespace *namespaces;
25
BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs,
34
NvmeSQueue **sq;
26
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
35
NvmeCQueue **cq;
27
BlockCompletionFunc *cb, void *opaque);
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
28
- BlockAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
29
- int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
30
- BlockCompletionFunc *cb, void *opaque);
31
BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs,
32
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
33
BlockCompletionFunc *cb, void *opaque);
34
diff --git a/block/io.c b/block/io.c
35
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
36
--- a/block/io.c
38
--- a/include/block/nvme.h
37
+++ b/block/io.c
39
+++ b/include/block/nvme.h
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
39
return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags);
41
uint64_t acq;
42
uint32_t cmbloc;
43
uint32_t cmbsz;
44
+ uint8_t padding[3520]; /* not used by QEMU */
45
+ uint32_t pmrcap;
46
+ uint32_t pmrctl;
47
+ uint32_t pmrsts;
48
+ uint32_t pmrebs;
49
+ uint32_t pmrswtp;
50
+ uint32_t pmrmsc;
51
} NvmeBar;
52
53
enum NvmeCapShift {
54
@@ -XXX,XX +XXX,XX @@ enum NvmeCapShift {
55
CAP_CSS_SHIFT = 37,
56
CAP_MPSMIN_SHIFT = 48,
57
CAP_MPSMAX_SHIFT = 52,
58
+ CAP_PMR_SHIFT = 56,
59
};
60
61
enum NvmeCapMask {
62
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
63
CAP_CSS_MASK = 0xff,
64
CAP_MPSMIN_MASK = 0xf,
65
CAP_MPSMAX_MASK = 0xf,
66
+ CAP_PMR_MASK = 0x1,
67
};
68
69
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
70
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
71
<< CAP_MPSMIN_SHIFT)
72
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
73
<< CAP_MPSMAX_SHIFT)
74
+#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
75
+ << CAP_PMR_SHIFT)
76
77
enum NvmeCcShift {
78
CC_EN_SHIFT = 0,
79
@@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask {
80
#define NVME_CMBSZ_GETSIZE(cmbsz) \
81
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
82
83
+enum NvmePmrcapShift {
84
+ PMRCAP_RDS_SHIFT = 3,
85
+ PMRCAP_WDS_SHIFT = 4,
86
+ PMRCAP_BIR_SHIFT = 5,
87
+ PMRCAP_PMRTU_SHIFT = 8,
88
+ PMRCAP_PMRWBM_SHIFT = 10,
89
+ PMRCAP_PMRTO_SHIFT = 16,
90
+ PMRCAP_CMSS_SHIFT = 24,
91
+};
92
+
93
+enum NvmePmrcapMask {
94
+ PMRCAP_RDS_MASK = 0x1,
95
+ PMRCAP_WDS_MASK = 0x1,
96
+ PMRCAP_BIR_MASK = 0x7,
97
+ PMRCAP_PMRTU_MASK = 0x3,
98
+ PMRCAP_PMRWBM_MASK = 0xf,
99
+ PMRCAP_PMRTO_MASK = 0xff,
100
+ PMRCAP_CMSS_MASK = 0x1,
101
+};
102
+
103
+#define NVME_PMRCAP_RDS(pmrcap) \
104
+ ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
105
+#define NVME_PMRCAP_WDS(pmrcap) \
106
+ ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
107
+#define NVME_PMRCAP_BIR(pmrcap) \
108
+ ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
109
+#define NVME_PMRCAP_PMRTU(pmrcap) \
110
+ ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
111
+#define NVME_PMRCAP_PMRWBM(pmrcap) \
112
+ ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
113
+#define NVME_PMRCAP_PMRTO(pmrcap) \
114
+ ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
115
+#define NVME_PMRCAP_CMSS(pmrcap) \
116
+ ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
117
+
118
+#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
119
+ (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
120
+#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
121
+ (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
122
+#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
123
+ (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
124
+#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
125
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
126
+#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
127
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
128
+#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
129
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
130
+#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
131
+ (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
132
+
133
+enum NvmePmrctlShift {
134
+ PMRCTL_EN_SHIFT = 0,
135
+};
136
+
137
+enum NvmePmrctlMask {
138
+ PMRCTL_EN_MASK = 0x1,
139
+};
140
+
141
+#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
142
+
143
+#define NVME_PMRCTL_SET_EN(pmrctl, val) \
144
+ (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
145
+
146
+enum NvmePmrstsShift {
147
+ PMRSTS_ERR_SHIFT = 0,
148
+ PMRSTS_NRDY_SHIFT = 8,
149
+ PMRSTS_HSTS_SHIFT = 9,
150
+ PMRSTS_CBAI_SHIFT = 12,
151
+};
152
+
153
+enum NvmePmrstsMask {
154
+ PMRSTS_ERR_MASK = 0xff,
155
+ PMRSTS_NRDY_MASK = 0x1,
156
+ PMRSTS_HSTS_MASK = 0x7,
157
+ PMRSTS_CBAI_MASK = 0x1,
158
+};
159
+
160
+#define NVME_PMRSTS_ERR(pmrsts) \
161
+ ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
162
+#define NVME_PMRSTS_NRDY(pmrsts) \
163
+ ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
164
+#define NVME_PMRSTS_HSTS(pmrsts) \
165
+ ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
166
+#define NVME_PMRSTS_CBAI(pmrsts) \
167
+ ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
168
+
169
+#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
170
+ (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
171
+#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
172
+ (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
173
+#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
174
+ (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
175
+#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
176
+ (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
177
+
178
+enum NvmePmrebsShift {
179
+ PMREBS_PMRSZU_SHIFT = 0,
180
+ PMREBS_RBB_SHIFT = 4,
181
+ PMREBS_PMRWBZ_SHIFT = 8,
182
+};
183
+
184
+enum NvmePmrebsMask {
185
+ PMREBS_PMRSZU_MASK = 0xf,
186
+ PMREBS_RBB_MASK = 0x1,
187
+ PMREBS_PMRWBZ_MASK = 0xffffff,
188
+};
189
+
190
+#define NVME_PMREBS_PMRSZU(pmrebs) \
191
+ ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
192
+#define NVME_PMREBS_RBB(pmrebs) \
193
+ ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
194
+#define NVME_PMREBS_PMRWBZ(pmrebs) \
195
+ ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
196
+
197
+#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
198
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
199
+#define NVME_PMREBS_SET_RBB(pmrebs, val) \
200
+ (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
201
+#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
202
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
203
+
204
+enum NvmePmrswtpShift {
205
+ PMRSWTP_PMRSWTU_SHIFT = 0,
206
+ PMRSWTP_PMRSWTV_SHIFT = 8,
207
+};
208
+
209
+enum NvmePmrswtpMask {
210
+ PMRSWTP_PMRSWTU_MASK = 0xf,
211
+ PMRSWTP_PMRSWTV_MASK = 0xffffff,
212
+};
213
+
214
+#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
215
+ ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
216
+#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
217
+ ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
218
+
219
+#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
220
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
221
+#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
222
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
223
+
224
+enum NvmePmrmscShift {
225
+ PMRMSC_CMSE_SHIFT = 1,
226
+ PMRMSC_CBA_SHIFT = 12,
227
+};
228
+
229
+enum NvmePmrmscMask {
230
+ PMRMSC_CMSE_MASK = 0x1,
231
+ PMRMSC_CBA_MASK = 0xfffffffffffff,
232
+};
233
+
234
+#define NVME_PMRMSC_CMSE(pmrmsc) \
235
+ ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
236
+#define NVME_PMRMSC_CBA(pmrmsc) \
237
+ ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
238
+
239
+#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
240
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
241
+#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
242
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
243
+
244
typedef struct NvmeCmd {
245
uint8_t opcode;
246
uint8_t fuse;
247
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
248
index XXXXXXX..XXXXXXX 100644
249
--- a/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
251
@@ -XXX,XX +XXX,XX @@
252
* -drive file=<file>,if=none,id=<drive_id>
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
255
+ * [pmrdev=<mem_backend_file_id>,] \
256
* num_queues=<N[optional]>
257
*
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
259
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
260
+ *
261
+ * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
262
+ * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
263
+ * both provided.
264
+ * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
265
+ * For example:
266
+ * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
267
+ * size=<size> .... -device nvme,...,pmrdev=<mem_id>
268
*/
269
270
#include "qemu/osdep.h"
271
@@ -XXX,XX +XXX,XX @@
272
#include "sysemu/sysemu.h"
273
#include "qapi/error.h"
274
#include "qapi/visitor.h"
275
+#include "sysemu/hostmem.h"
276
#include "sysemu/block-backend.h"
277
+#include "exec/ram_addr.h"
278
279
#include "qemu/log.h"
280
#include "qemu/module.h"
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
283
"invalid write to read only CMBSZ, ignored");
284
return;
285
+ case 0xE00: /* PMRCAP */
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
287
+ "invalid write to PMRCAP register, ignored");
288
+ return;
289
+ case 0xE04: /* TODO PMRCTL */
290
+ break;
291
+ case 0xE08: /* PMRSTS */
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
293
+ "invalid write to PMRSTS register, ignored");
294
+ return;
295
+ case 0xE0C: /* PMREBS */
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
297
+ "invalid write to PMREBS register, ignored");
298
+ return;
299
+ case 0xE10: /* PMRSWTP */
300
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
301
+ "invalid write to PMRSWTP register, ignored");
302
+ return;
303
+ case 0xE14: /* TODO PMRMSC */
304
+ break;
305
default:
306
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
307
"invalid MMIO write,"
308
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
40
}
309
}
41
310
42
- /* FIXME - no need to calculate these if .bdrv_aio_preadv exists */
311
if (addr < sizeof(n->bar)) {
43
- sector_num = offset >> BDRV_SECTOR_BITS;
312
+ /*
44
- nb_sectors = bytes >> BDRV_SECTOR_BITS;
313
+ * When PMRWBM bit 1 is set then read from
45
-
314
+ * from PMRSTS should ensure prior writes
46
- if (!drv->bdrv_aio_preadv) {
315
+ * made it to persistent media
47
- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
316
+ */
48
- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
317
+ if (addr == 0xE08 &&
49
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
50
- }
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
51
-
320
+ 0, n->pmrdev->size);
52
- if (drv->bdrv_co_readv) {
321
+ }
53
- return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
322
memcpy(&val, ptr + addr, size);
54
- } else {
323
} else {
55
+ if (drv->bdrv_aio_preadv) {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
56
BlockAIOCB *acb;
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
57
CoroutineIOCompletion co = {
326
error_setg(errp, "serial property not set");
58
.coroutine = qemu_coroutine_self(),
327
return;
59
};
60
61
- if (drv->bdrv_aio_preadv) {
62
- acb = drv->bdrv_aio_preadv(bs, offset, bytes, qiov, flags,
63
- bdrv_co_io_em_complete, &co);
64
- } else {
65
- acb = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
66
- bdrv_co_io_em_complete, &co);
67
- }
68
+ acb = drv->bdrv_aio_preadv(bs, offset, bytes, qiov, flags,
69
+ bdrv_co_io_em_complete, &co);
70
if (acb == NULL) {
71
return -EIO;
72
} else {
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
74
return co.ret;
75
}
76
}
328
}
77
+
329
+
78
+ sector_num = offset >> BDRV_SECTOR_BITS;
330
+ if (!n->cmb_size_mb && n->pmrdev) {
79
+ nb_sectors = bytes >> BDRV_SECTOR_BITS;
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
80
+
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
81
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
82
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
334
+ g_free(path);
83
+ assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
335
+ return;
84
+ assert(drv->bdrv_co_readv);
336
+ }
85
+
337
+
86
+ return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
338
+ if (!is_power_of_2(n->pmrdev->size)) {
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
340
+ return;
341
+ }
342
+
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
344
+ }
345
+
346
blkconf_blocksizes(&n->conf);
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
348
false, errp)) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
408
+ }
409
msix_uninit_exclusive_bar(pci_dev);
87
}
410
}
88
411
89
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
412
static Property nvme_props[] = {
90
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
91
goto emulate_flags;
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
92
}
415
+ HostMemoryBackend *),
93
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
94
- /* FIXME - no need to calculate these if .bdrv_aio_pwritev exists */
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
95
- sector_num = offset >> BDRV_SECTOR_BITS;
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
96
- nb_sectors = bytes >> BDRV_SECTOR_BITS;
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
97
-
420
index XXXXXXX..XXXXXXX 100644
98
- if (!drv->bdrv_aio_pwritev) {
421
--- a/hw/block/Makefile.objs
99
- assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
422
+++ b/hw/block/Makefile.objs
100
- assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
101
- assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
424
common-obj-$(CONFIG_XEN) += xen-block.o
102
- }
425
common-obj-$(CONFIG_ECC) += ecc.o
103
-
426
common-obj-$(CONFIG_ONENAND) += onenand.o
104
- if (drv->bdrv_co_writev_flags) {
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
105
- ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
428
common-obj-$(CONFIG_SWIM) += swim.o
106
- flags & bs->supported_write_flags);
429
107
- flags &= ~bs->supported_write_flags;
430
common-obj-$(CONFIG_SH4) += tc58128.o
108
- } else if (drv->bdrv_co_writev) {
431
109
- assert(!bs->supported_write_flags);
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
110
- ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
111
- } else {
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
112
+ if (drv->bdrv_aio_pwritev) {
435
113
BlockAIOCB *acb;
436
obj-y += dataplane/
114
CoroutineIOCompletion co = {
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
115
.coroutine = qemu_coroutine_self(),
438
index XXXXXXX..XXXXXXX 100644
116
};
439
--- a/hw/block/trace-events
117
440
+++ b/hw/block/trace-events
118
- if (drv->bdrv_aio_pwritev) {
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
119
- acb = drv->bdrv_aio_pwritev(bs, offset, bytes, qiov,
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
120
- flags & bs->supported_write_flags,
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
121
- bdrv_co_io_em_complete, &co);
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
122
- flags &= ~bs->supported_write_flags;
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
123
- } else {
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
124
- assert(!bs->supported_write_flags);
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
125
- acb = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
126
- bdrv_co_io_em_complete, &co);
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
127
- }
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
128
+ acb = drv->bdrv_aio_pwritev(bs, offset, bytes, qiov,
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
129
+ flags & bs->supported_write_flags,
130
+ bdrv_co_io_em_complete, &co);
131
+ flags &= ~bs->supported_write_flags;
132
if (acb == NULL) {
133
ret = -EIO;
134
} else {
135
qemu_coroutine_yield();
136
ret = co.ret;
137
}
138
+ goto emulate_flags;
139
+ }
140
+
141
+ sector_num = offset >> BDRV_SECTOR_BITS;
142
+ nb_sectors = bytes >> BDRV_SECTOR_BITS;
143
+
144
+ assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
145
+ assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
146
+ assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
147
+
148
+ if (drv->bdrv_co_writev_flags) {
149
+ ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
150
+ flags & bs->supported_write_flags);
151
+ flags &= ~bs->supported_write_flags;
152
+ } else {
153
+ assert(drv->bdrv_co_writev);
154
+ assert(!bs->supported_write_flags);
155
+ ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
156
}
157
158
emulate_flags:
159
--
452
--
160
2.13.6
453
2.25.3
161
454
162
455
diff view generated by jsdifflib
1
All block job drivers support .set_speed and all of them duplicate the
1
The QMP handler qmp_object_add() and the implementation of --object in
2
same code to implement it. Move that code to blockjob.c and remove the
2
qemu-storage-daemon can share most of the code. Currently,
3
now useless callback.
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
5
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
7
new function user_creatable_add_dict() that can get an additional
8
parameter. The handling of "props" is only required for compatibility
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
4
11
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
---
13
---
10
include/block/blockjob.h | 2 ++
14
include/qom/object_interfaces.h | 12 ++++++++++++
11
include/block/blockjob_int.h | 3 ---
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
12
block/backup.c | 13 -------------
16
qom/qom-qmp-cmds.c | 24 +-----------------------
13
block/commit.c | 14 --------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
14
block/mirror.c | 26 ++++++--------------------
15
block/stream.c | 14 --------------
16
blockjob.c | 12 ++++--------
17
7 files changed, 12 insertions(+), 72 deletions(-)
18
18
19
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
20
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/blockjob.h
21
--- a/include/qom/object_interfaces.h
22
+++ b/include/block/blockjob.h
22
+++ b/include/qom/object_interfaces.h
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
24
const QDict *qdict,
25
Visitor *v, Error **errp);
26
27
+/**
28
+ * user_creatable_add_dict:
29
+ * @qdict: the object definition
30
+ * @errp: if an error occurs, a pointer to an area to store the error
31
+ *
32
+ * Create an instance of the user creatable object that is defined by
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
35
+ * initialize the object properties.
36
+ */
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
38
+
39
/**
40
* user_creatable_add_opts:
41
* @opts: the object definition
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/qom/object_interfaces.c
45
+++ b/qom/object_interfaces.c
23
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
24
#include "block/block.h"
47
#include "qapi/qmp/qerror.h"
25
#include "qemu/ratelimit.h"
48
#include "qapi/qmp/qjson.h"
26
49
#include "qapi/qmp/qstring.h"
27
+#define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */
50
+#include "qapi/qobject-input-visitor.h"
51
#include "qom/object_interfaces.h"
52
#include "qemu/help_option.h"
53
#include "qemu/module.h"
54
@@ -XXX,XX +XXX,XX @@ out:
55
return obj;
56
}
57
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
59
+{
60
+ Visitor *v;
61
+ Object *obj;
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
28
+
64
+
29
typedef struct BlockJobDriver BlockJobDriver;
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
30
typedef struct BlockJobTxn BlockJobTxn;
66
+ if (!type) {
31
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
32
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
86
{
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
33
index XXXXXXX..XXXXXXX 100644
88
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/blockjob_int.h
89
--- a/qom/qom-qmp-cmds.c
35
+++ b/include/block/blockjob_int.h
90
+++ b/qom/qom-qmp-cmds.c
36
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
91
@@ -XXX,XX +XXX,XX @@
37
/** String describing the operation, part of query-block-jobs QMP API */
92
#include "qapi/qapi-commands-qom.h"
38
BlockJobType job_type;
93
#include "qapi/qmp/qdict.h"
39
94
#include "qapi/qmp/qerror.h"
40
- /** Optional callback for job types that support setting a speed limit */
95
-#include "qapi/qobject-input-visitor.h"
41
- void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
96
#include "qemu/cutils.h"
97
#include "qom/object_interfaces.h"
98
#include "qom/qom-qobject.h"
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
100
{
101
QObject *props;
102
QDict *pdict;
103
- Visitor *v;
104
- Object *obj;
105
- g_autofree char *type = NULL;
106
- g_autofree char *id = NULL;
42
-
107
-
43
/** Mandatory: Entrypoint for the Coroutine. */
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
44
CoroutineEntry *start;
109
- if (!type) {
45
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
46
diff --git a/block/backup.c b/block/backup.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/backup.c
49
+++ b/block/backup.c
50
@@ -XXX,XX +XXX,XX @@
51
#include "qemu/error-report.h"
52
53
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
54
-#define SLICE_TIME 100000000ULL /* ns */
55
56
typedef struct BackupBlockJob {
57
BlockJob common;
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_before_write_notify(
59
return backup_do_cow(job, req->offset, req->bytes, NULL, true);
60
}
61
62
-static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
63
-{
64
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
65
-
66
- if (speed < 0) {
67
- error_setg(errp, QERR_INVALID_PARAMETER, "speed");
68
- return;
111
- return;
69
- }
112
- }
70
- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
113
- qdict_del(qdict, "qom-type");
71
-}
72
-
114
-
73
static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
74
{
116
- if (!id) {
75
BdrvDirtyBitmap *bm;
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
76
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
77
.instance_size = sizeof(BackupBlockJob),
78
.job_type = BLOCK_JOB_TYPE_BACKUP,
79
.start = backup_run,
80
- .set_speed = backup_set_speed,
81
.commit = backup_commit,
82
.abort = backup_abort,
83
.clean = backup_clean,
84
diff --git a/block/commit.c b/block/commit.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/commit.c
87
+++ b/block/commit.c
88
@@ -XXX,XX +XXX,XX @@ enum {
89
COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */
90
};
91
92
-#define SLICE_TIME 100000000ULL /* ns */
93
-
94
typedef struct CommitBlockJob {
95
BlockJob common;
96
BlockDriverState *commit_top_bs;
97
@@ -XXX,XX +XXX,XX @@ out:
98
block_job_defer_to_main_loop(&s->common, commit_complete, data);
99
}
100
101
-static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
102
-{
103
- CommitBlockJob *s = container_of(job, CommitBlockJob, common);
104
-
105
- if (speed < 0) {
106
- error_setg(errp, QERR_INVALID_PARAMETER, "speed");
107
- return;
118
- return;
108
- }
119
- }
109
- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
120
- qdict_del(qdict, "id");
110
-}
121
111
-
122
props = qdict_get(qdict, "props");
112
static const BlockJobDriver commit_job_driver = {
123
if (props) {
113
.instance_size = sizeof(CommitBlockJob),
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
114
.job_type = BLOCK_JOB_TYPE_COMMIT,
125
qobject_unref(pdict);
115
- .set_speed = commit_set_speed,
126
}
116
.start = commit_run,
127
117
};
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
118
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
119
diff --git a/block/mirror.c b/block/mirror.c
130
- visit_free(v);
120
index XXXXXXX..XXXXXXX 100644
131
- object_unref(obj);
121
--- a/block/mirror.c
132
+ user_creatable_add_dict(qdict, errp);
122
+++ b/block/mirror.c
123
@@ -XXX,XX +XXX,XX @@
124
#include "qemu/ratelimit.h"
125
#include "qemu/bitmap.h"
126
127
-#define SLICE_TIME 100000000ULL /* ns */
128
#define MAX_IN_FLIGHT 16
129
#define MAX_IO_BYTES (1 << 20) /* 1 Mb */
130
#define DEFAULT_MIRROR_BUF_SIZE (MAX_IN_FLIGHT * MAX_IO_BYTES)
131
@@ -XXX,XX +XXX,XX @@ static void mirror_throttle(MirrorBlockJob *s)
132
{
133
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
134
135
- if (now - s->last_pause_ns > SLICE_TIME) {
136
+ if (now - s->last_pause_ns > BLOCK_JOB_SLICE_TIME) {
137
s->last_pause_ns = now;
138
block_job_sleep_ns(&s->common, 0);
139
} else {
140
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
141
142
/* Note that even when no rate limit is applied we need to yield
143
* periodically with no pending I/O so that bdrv_drain_all() returns.
144
- * We do so every SLICE_TIME nanoseconds, or when there is an error,
145
- * or when the source is clean, whichever comes first.
146
- */
147
+ * We do so every BLKOCK_JOB_SLICE_TIME nanoseconds, or when there is
148
+ * an error, or when the source is clean, whichever comes first. */
149
delta = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->last_pause_ns;
150
- if (delta < SLICE_TIME &&
151
+ if (delta < BLOCK_JOB_SLICE_TIME &&
152
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
153
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
154
(cnt == 0 && s->in_flight > 0)) {
155
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
156
ret = 0;
157
158
if (s->synced && !should_complete) {
159
- delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0);
160
+ delay_ns = (s->in_flight == 0 &&
161
+ cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0);
162
}
163
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
164
block_job_sleep_ns(&s->common, delay_ns);
165
@@ -XXX,XX +XXX,XX @@ immediate_exit:
166
block_job_defer_to_main_loop(&s->common, mirror_exit, data);
167
}
133
}
168
134
169
-static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp)
135
void qmp_object_del(const char *id, Error **errp)
170
-{
171
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
172
-
173
- if (speed < 0) {
174
- error_setg(errp, QERR_INVALID_PARAMETER, "speed");
175
- return;
176
- }
177
- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
178
-}
179
-
180
static void mirror_complete(BlockJob *job, Error **errp)
181
{
182
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
183
@@ -XXX,XX +XXX,XX @@ static void mirror_drain(BlockJob *job)
184
static const BlockJobDriver mirror_job_driver = {
185
.instance_size = sizeof(MirrorBlockJob),
186
.job_type = BLOCK_JOB_TYPE_MIRROR,
187
- .set_speed = mirror_set_speed,
188
.start = mirror_run,
189
.complete = mirror_complete,
190
.pause = mirror_pause,
191
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
192
static const BlockJobDriver commit_active_job_driver = {
193
.instance_size = sizeof(MirrorBlockJob),
194
.job_type = BLOCK_JOB_TYPE_COMMIT,
195
- .set_speed = mirror_set_speed,
196
.start = mirror_run,
197
.complete = mirror_complete,
198
.pause = mirror_pause,
199
diff --git a/block/stream.c b/block/stream.c
200
index XXXXXXX..XXXXXXX 100644
201
--- a/block/stream.c
202
+++ b/block/stream.c
203
@@ -XXX,XX +XXX,XX @@ enum {
204
STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
205
};
206
207
-#define SLICE_TIME 100000000ULL /* ns */
208
-
209
typedef struct StreamBlockJob {
210
BlockJob common;
211
BlockDriverState *base;
212
@@ -XXX,XX +XXX,XX @@ out:
213
block_job_defer_to_main_loop(&s->common, stream_complete, data);
214
}
215
216
-static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
217
-{
218
- StreamBlockJob *s = container_of(job, StreamBlockJob, common);
219
-
220
- if (speed < 0) {
221
- error_setg(errp, QERR_INVALID_PARAMETER, "speed");
222
- return;
223
- }
224
- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
225
-}
226
-
227
static const BlockJobDriver stream_job_driver = {
228
.instance_size = sizeof(StreamBlockJob),
229
.job_type = BLOCK_JOB_TYPE_STREAM,
230
- .set_speed = stream_set_speed,
231
.start = stream_run,
232
};
233
234
diff --git a/blockjob.c b/blockjob.c
235
index XXXXXXX..XXXXXXX 100644
236
--- a/blockjob.c
237
+++ b/blockjob.c
238
@@ -XXX,XX +XXX,XX @@ static bool block_job_timer_pending(BlockJob *job)
239
240
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
241
{
242
- Error *local_err = NULL;
243
int64_t old_speed = job->speed;
244
245
- if (!job->driver->set_speed) {
246
- error_setg(errp, QERR_UNSUPPORTED);
247
- return;
248
- }
249
if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) {
250
return;
251
}
252
- job->driver->set_speed(job, speed, &local_err);
253
- if (local_err) {
254
- error_propagate(errp, local_err);
255
+ if (speed < 0) {
256
+ error_setg(errp, QERR_INVALID_PARAMETER, "speed");
257
return;
258
}
259
260
+ ratelimit_set_speed(&job->limit, speed, BLOCK_JOB_SLICE_TIME);
261
+
262
job->speed = speed;
263
if (speed && speed <= old_speed) {
264
return;
265
--
136
--
266
2.13.6
137
2.25.3
267
138
268
139
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
After processing the option string with the keyval parser, we get a
2
QDict that contains only strings. This QDict must be fed to a keyval
3
visitor which converts the strings into the right data types.
2
4
3
We are gradually moving away from sector-based interfaces, towards
5
qmp_object_add(), however, uses the normal QObject input visitor, which
4
byte-based. Make the change for the last few sector-based callbacks
6
expects a QDict where all properties already have the QType that matches
5
in the rbd driver.
7
the data type required by the QOM object type.
6
8
7
Note that the driver was already using byte-based calls for
9
Change the --object implementation in qemu-storage-daemon so that it
8
performing actual I/O, so this just gets rid of a round trip
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
9
of scaling; however, as I don't know if RBD is tolerant of
11
directly instead and pass it a new keyval boolean that decides which
10
non-sector AIO operations, I went with the conservate approach
12
visitor must be used.
11
of adding .bdrv_refresh_limits to override the block layer
12
defaults back to the pre-patch value of 512.
13
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
16
---
17
block/rbd.c | 40 ++++++++++++++++++++++------------------
17
include/qom/object_interfaces.h | 6 +++++-
18
1 file changed, 22 insertions(+), 18 deletions(-)
18
qemu-storage-daemon.c | 4 +---
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
19
22
20
diff --git a/block/rbd.c b/block/rbd.c
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
21
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
22
--- a/block/rbd.c
25
--- a/include/qom/object_interfaces.h
23
+++ b/block/rbd.c
26
+++ b/include/qom/object_interfaces.h
24
@@ -XXX,XX +XXX,XX @@ done:
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
28
/**
29
* user_creatable_add_dict:
30
* @qdict: the object definition
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
32
+ * assume that all @qdict values are strings); otherwise, use
33
+ * the normal QObject visitor (i.e. assume all @qdict values
34
+ * have the QType expected by the QOM object type)
35
* @errp: if an error occurs, a pointer to an area to store the error
36
*
37
* Create an instance of the user creatable object that is defined by
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
39
* ID from the key 'id'. The remaining entries in @qdict are used to
40
* initialize the object properties.
41
*/
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
44
45
/**
46
* user_creatable_add_opts:
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/qemu-storage-daemon.c
50
+++ b/qemu-storage-daemon.c
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
52
QemuOpts *opts;
53
const char *type;
54
QDict *args;
55
- QObject *ret_data = NULL;
56
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
58
* unconditionall try QemuOpts first. */
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
60
qemu_opts_del(opts);
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
25
}
76
}
26
77
27
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
28
+static void qemu_rbd_refresh_limits(BlockDriverState *bs, Error **errp)
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
29
+{
30
+ /* XXX Does RBD support AIO on less than 512-byte alignment? */
31
+ bs->bl.request_alignment = 512;
32
+}
33
+
34
+
35
static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
36
Error **errp)
37
{
80
{
38
@@ -XXX,XX +XXX,XX @@ failed:
81
Visitor *v;
39
return NULL;
82
Object *obj;
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
84
}
85
qdict_del(qdict, "id");
86
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
88
+ if (keyval) {
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
90
+ } else {
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
92
+ }
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
94
visit_free(v);
95
object_unref(obj);
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/qom/qom-qmp-cmds.c
99
+++ b/qom/qom-qmp-cmds.c
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
101
qobject_unref(pdict);
102
}
103
104
- user_creatable_add_dict(qdict, errp);
105
+ user_creatable_add_dict(qdict, false, errp);
40
}
106
}
41
107
42
-static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
108
void qmp_object_del(const char *id, Error **errp)
43
- int64_t sector_num,
44
- QEMUIOVector *qiov,
45
- int nb_sectors,
46
- BlockCompletionFunc *cb,
47
- void *opaque)
48
+static BlockAIOCB *qemu_rbd_aio_preadv(BlockDriverState *bs,
49
+ uint64_t offset, uint64_t bytes,
50
+ QEMUIOVector *qiov, int flags,
51
+ BlockCompletionFunc *cb,
52
+ void *opaque)
53
{
54
- return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
55
- (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
56
+ return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
57
RBD_AIO_READ);
58
}
59
60
-static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
61
- int64_t sector_num,
62
- QEMUIOVector *qiov,
63
- int nb_sectors,
64
- BlockCompletionFunc *cb,
65
- void *opaque)
66
+static BlockAIOCB *qemu_rbd_aio_pwritev(BlockDriverState *bs,
67
+ uint64_t offset, uint64_t bytes,
68
+ QEMUIOVector *qiov, int flags,
69
+ BlockCompletionFunc *cb,
70
+ void *opaque)
71
{
72
- return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
73
- (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
74
+ return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
75
RBD_AIO_WRITE);
76
}
77
78
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
79
.format_name = "rbd",
80
.instance_size = sizeof(BDRVRBDState),
81
.bdrv_parse_filename = qemu_rbd_parse_filename,
82
+ .bdrv_refresh_limits = qemu_rbd_refresh_limits,
83
.bdrv_file_open = qemu_rbd_open,
84
.bdrv_close = qemu_rbd_close,
85
.bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
86
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
87
.bdrv_truncate = qemu_rbd_truncate,
88
.protocol_name = "rbd",
89
90
- .bdrv_aio_readv = qemu_rbd_aio_readv,
91
- .bdrv_aio_writev = qemu_rbd_aio_writev,
92
+ .bdrv_aio_preadv = qemu_rbd_aio_preadv,
93
+ .bdrv_aio_pwritev = qemu_rbd_aio_pwritev,
94
95
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
96
.bdrv_aio_flush = qemu_rbd_aio_flush,
97
--
109
--
98
2.13.6
110
2.25.3
99
111
100
112
diff view generated by jsdifflib
Deleted patch
1
Every job gets a non-NULL job->txn on creation, but it doesn't
2
necessarily keep it until it is decommissioned: Finalising a job removes
3
it from its transaction. Therefore, calling 'blockdev-job-finalize' a
4
second time on an already concluded job causes an assertion failure.
5
1
6
Remove job->txn from the assertion in block_job_finalize() to fix this.
7
block_job_do_finalize() still has the same assertion, but if a job is
8
already removed from its transaction, block_job_apply_verb() will
9
already error out before we run into that assertion.
10
11
Cc: qemu-stable@nongnu.org
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
16
---
17
blockjob.c | 2 +-
18
1 file changed, 1 insertion(+), 1 deletion(-)
19
20
diff --git a/blockjob.c b/blockjob.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/blockjob.c
23
+++ b/blockjob.c
24
@@ -XXX,XX +XXX,XX @@ void block_job_complete(BlockJob *job, Error **errp)
25
26
void block_job_finalize(BlockJob *job, Error **errp)
27
{
28
- assert(job && job->id && job->txn);
29
+ assert(job && job->id);
30
if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
31
return;
32
}
33
--
34
2.13.6
35
36
diff view generated by jsdifflib
Deleted patch
1
Every block job has a RateLimit, and they all do the exact same thing
2
with it, so it should be common infrastructure. Move the struct field
3
for a start.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
---
10
include/block/blockjob.h | 4 ++++
11
block/backup.c | 5 ++---
12
block/commit.c | 5 ++---
13
block/mirror.c | 6 +++---
14
block/stream.c | 5 ++---
15
5 files changed, 13 insertions(+), 12 deletions(-)
16
17
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/blockjob.h
20
+++ b/include/block/blockjob.h
21
@@ -XXX,XX +XXX,XX @@
22
#define BLOCKJOB_H
23
24
#include "block/block.h"
25
+#include "qemu/ratelimit.h"
26
27
typedef struct BlockJobDriver BlockJobDriver;
28
typedef struct BlockJobTxn BlockJobTxn;
29
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
30
/** Speed that was set with @block_job_set_speed. */
31
int64_t speed;
32
33
+ /** Rate limiting data structure for implementing @speed. */
34
+ RateLimit limit;
35
+
36
/** The completion function that will be called when the job completes. */
37
BlockCompletionFunc *cb;
38
39
diff --git a/block/backup.c b/block/backup.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/backup.c
42
+++ b/block/backup.c
43
@@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob {
44
/* bitmap for sync=incremental */
45
BdrvDirtyBitmap *sync_bitmap;
46
MirrorSyncMode sync_mode;
47
- RateLimit limit;
48
BlockdevOnError on_source_error;
49
BlockdevOnError on_target_error;
50
CoRwlock flush_rwlock;
51
@@ -XXX,XX +XXX,XX @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
52
error_setg(errp, QERR_INVALID_PARAMETER, "speed");
53
return;
54
}
55
- ratelimit_set_speed(&s->limit, speed, SLICE_TIME);
56
+ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
57
}
58
59
static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
60
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
61
* (without, VM does not reboot)
62
*/
63
if (job->common.speed) {
64
- uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
65
+ uint64_t delay_ns = ratelimit_calculate_delay(&job->common.limit,
66
job->bytes_read);
67
job->bytes_read = 0;
68
block_job_sleep_ns(&job->common, delay_ns);
69
diff --git a/block/commit.c b/block/commit.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/commit.c
72
+++ b/block/commit.c
73
@@ -XXX,XX +XXX,XX @@ enum {
74
75
typedef struct CommitBlockJob {
76
BlockJob common;
77
- RateLimit limit;
78
BlockDriverState *commit_top_bs;
79
BlockBackend *top;
80
BlockBackend *base;
81
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque)
82
block_job_progress_update(&s->common, n);
83
84
if (copy && s->common.speed) {
85
- delay_ns = ratelimit_calculate_delay(&s->limit, n);
86
+ delay_ns = ratelimit_calculate_delay(&s->common.limit, n);
87
} else {
88
delay_ns = 0;
89
}
90
@@ -XXX,XX +XXX,XX @@ static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
91
error_setg(errp, QERR_INVALID_PARAMETER, "speed");
92
return;
93
}
94
- ratelimit_set_speed(&s->limit, speed, SLICE_TIME);
95
+ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
96
}
97
98
static const BlockJobDriver commit_job_driver = {
99
diff --git a/block/mirror.c b/block/mirror.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/mirror.c
102
+++ b/block/mirror.c
103
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBuffer {
104
105
typedef struct MirrorBlockJob {
106
BlockJob common;
107
- RateLimit limit;
108
BlockBackend *target;
109
BlockDriverState *mirror_top_bs;
110
BlockDriverState *source;
111
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
112
offset += io_bytes;
113
nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity);
114
if (s->common.speed) {
115
- delay_ns = ratelimit_calculate_delay(&s->limit, io_bytes_acct);
116
+ delay_ns = ratelimit_calculate_delay(&s->common.limit,
117
+ io_bytes_acct);
118
}
119
}
120
return delay_ns;
121
@@ -XXX,XX +XXX,XX @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp)
122
error_setg(errp, QERR_INVALID_PARAMETER, "speed");
123
return;
124
}
125
- ratelimit_set_speed(&s->limit, speed, SLICE_TIME);
126
+ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
127
}
128
129
static void mirror_complete(BlockJob *job, Error **errp)
130
diff --git a/block/stream.c b/block/stream.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/stream.c
133
+++ b/block/stream.c
134
@@ -XXX,XX +XXX,XX @@ enum {
135
136
typedef struct StreamBlockJob {
137
BlockJob common;
138
- RateLimit limit;
139
BlockDriverState *base;
140
BlockdevOnError on_error;
141
char *backing_file_str;
142
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn stream_run(void *opaque)
143
/* Publish progress */
144
block_job_progress_update(&s->common, n);
145
if (copy && s->common.speed) {
146
- delay_ns = ratelimit_calculate_delay(&s->limit, n);
147
+ delay_ns = ratelimit_calculate_delay(&s->common.limit, n);
148
} else {
149
delay_ns = 0;
150
}
151
@@ -XXX,XX +XXX,XX @@ static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
152
error_setg(errp, QERR_INVALID_PARAMETER, "speed");
153
return;
154
}
155
- ratelimit_set_speed(&s->limit, speed, SLICE_TIME);
156
+ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME);
157
}
158
159
static const BlockJobDriver stream_job_driver = {
160
--
161
2.13.6
162
163
diff view generated by jsdifflib
Deleted patch
1
The backup block job directly accesses the driver field in BlockJob. Add
2
a wrapper for getting it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
---
9
include/block/blockjob.h | 7 +++++++
10
block/backup.c | 8 +++++---
11
blockjob.c | 5 +++++
12
3 files changed, 17 insertions(+), 3 deletions(-)
13
14
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/blockjob.h
17
+++ b/include/block/blockjob.h
18
@@ -XXX,XX +XXX,XX @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job);
19
*/
20
bool block_job_is_internal(BlockJob *job);
21
22
+/**
23
+ * block_job_driver:
24
+ *
25
+ * Returns the driver associated with a block job.
26
+ */
27
+const BlockJobDriver *block_job_driver(BlockJob *job);
28
+
29
#endif
30
diff --git a/block/backup.c b/block/backup.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/backup.c
33
+++ b/block/backup.c
34
@@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob {
35
HBitmap *copy_bitmap;
36
} BackupBlockJob;
37
38
+static const BlockJobDriver backup_job_driver;
39
+
40
/* See if in-flight requests overlap and wait for them to complete */
41
static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job,
42
int64_t start,
43
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
44
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
45
int64_t len;
46
47
- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
48
+ assert(block_job_driver(job) == &backup_job_driver);
49
50
if (backup_job->sync_mode != MIRROR_SYNC_MODE_NONE) {
51
error_setg(errp, "The backup job only supports block checkpoint in"
52
@@ -XXX,XX +XXX,XX @@ void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
53
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
54
int64_t start, end;
55
56
- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
57
+ assert(block_job_driver(job) == &backup_job_driver);
58
59
start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size);
60
end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size);
61
@@ -XXX,XX +XXX,XX @@ void backup_cow_request_begin(CowRequest *req, BlockJob *job,
62
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
63
int64_t start, end;
64
65
- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP);
66
+ assert(block_job_driver(job) == &backup_job_driver);
67
68
start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size);
69
end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size);
70
diff --git a/blockjob.c b/blockjob.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/blockjob.c
73
+++ b/blockjob.c
74
@@ -XXX,XX +XXX,XX @@ static bool block_job_started(BlockJob *job)
75
return job->co;
76
}
77
78
+const BlockJobDriver *block_job_driver(BlockJob *job)
79
+{
80
+ return job->driver;
81
+}
82
+
83
/**
84
* All jobs must allow a pause point before entering their job proper. This
85
* ensures that jobs can be paused prior to being started, then resumed later.
86
--
87
2.13.6
88
89
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Commit abd3622cc03cf41ed542126a540385f30a4c0175 added a case to 122
4
regarding how the qcow2 driver handles an incorrect compressed data
5
length value. This does not really fit into 122, as that file is
6
supposed to contain qemu-img convert test cases, which this case is not.
7
So this patch splits it off into its own file; maybe we will even get
8
more qcow2-only compression tests in the future.
9
10
Also, that test case does not work with refcount_bits=1, so mark that
11
option as unsupported.
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Message-id: 20180406164108.26118-1-mreitz@redhat.com
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Alberto Garcia <berto@igalia.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
tests/qemu-iotests/122 | 47 ----------------------
20
tests/qemu-iotests/122.out | 33 ----------------
21
tests/qemu-iotests/214 | 97 ++++++++++++++++++++++++++++++++++++++++++++++
22
tests/qemu-iotests/214.out | 35 +++++++++++++++++
23
tests/qemu-iotests/group | 1 +
24
5 files changed, 133 insertions(+), 80 deletions(-)
25
create mode 100755 tests/qemu-iotests/214
26
create mode 100644 tests/qemu-iotests/214.out
27
28
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
29
index XXXXXXX..XXXXXXX 100755
30
--- a/tests/qemu-iotests/122
31
+++ b/tests/qemu-iotests/122
32
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 1024k 1022k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _fil
33
34
35
echo
36
-echo "=== Corrupted size field in compressed cluster descriptor ==="
37
-echo
38
-# Create an empty image and fill half of it with compressed data.
39
-# The L2 entries of the two compressed clusters are located at
40
-# 0x800000 and 0x800008, their original values are 0x4008000000a00000
41
-# and 0x4008000000a00802 (5 sectors for compressed data each).
42
-_make_test_img 8M -o cluster_size=2M
43
-$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
44
- 2>&1 | _filter_qemu_io | _filter_testdir
45
-
46
-# Reduce size of compressed data to 4 sectors: this corrupts the image.
47
-poke_file "$TEST_IMG" $((0x800000)) "\x40\x06"
48
-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
49
-
50
-# 'qemu-img check' however doesn't see anything wrong because it
51
-# doesn't try to decompress the data and the refcounts are consistent.
52
-# TODO: update qemu-img so this can be detected.
53
-_check_test_img
54
-
55
-# Increase size of compressed data to the maximum (8192 sectors).
56
-# This makes QEMU read more data (8192 sectors instead of 5, host
57
-# addresses [0xa00000, 0xdfffff]), but the decompression algorithm
58
-# stops once we have enough to restore the uncompressed cluster, so
59
-# the rest of the data is ignored.
60
-poke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe"
61
-# Do it also for the second compressed cluster (L2 entry at 0x800008).
62
-# In this case the compressed data would span 3 host clusters
63
-# (host addresses: [0xa00802, 0xe00801])
64
-poke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe"
65
-
66
-# Here the image is too small so we're asking QEMU to read beyond the
67
-# end of the image.
68
-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
69
-# But if we grow the image we won't be reading beyond its end anymore.
70
-$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
71
-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
72
-
73
-# The refcount data is however wrong because due to the increased size
74
-# of the compressed data it now reaches the following host clusters.
75
-# This can be repaired by qemu-img check by increasing the refcount of
76
-# those clusters.
77
-# TODO: update qemu-img to correct the compressed cluster size instead.
78
-_check_test_img -r all
79
-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
80
-$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
81
-
82
-echo
83
echo "=== Full allocation with -S 0 ==="
84
echo
85
86
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
87
index XXXXXXX..XXXXXXX 100644
88
--- a/tests/qemu-iotests/122.out
89
+++ b/tests/qemu-iotests/122.out
90
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 1047552
91
read 1046528/1046528 bytes at offset 1048576
92
1022 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
93
94
-=== Corrupted size field in compressed cluster descriptor ===
95
-
96
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
97
-wrote 2097152/2097152 bytes at offset 0
98
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
99
-wrote 2097152/2097152 bytes at offset 2097152
100
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
101
-read failed: Input/output error
102
-No errors were found on the image.
103
-read 4194304/4194304 bytes at offset 0
104
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
105
-wrote 4194304/4194304 bytes at offset 4194304
106
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
107
-read 4194304/4194304 bytes at offset 0
108
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
109
-ERROR cluster 6 refcount=1 reference=3
110
-ERROR cluster 7 refcount=1 reference=2
111
-Repairing cluster 6 refcount=1 reference=3
112
-Repairing cluster 7 refcount=1 reference=2
113
-Repairing OFLAG_COPIED data cluster: l2_entry=8000000000c00000 refcount=3
114
-Repairing OFLAG_COPIED data cluster: l2_entry=8000000000e00000 refcount=2
115
-The following inconsistencies were found and repaired:
116
-
117
- 0 leaked clusters
118
- 4 corruptions
119
-
120
-Double checking the fixed image now...
121
-No errors were found on the image.
122
-read 4194304/4194304 bytes at offset 0
123
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
124
-read 4194304/4194304 bytes at offset 4194304
125
-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
126
-
127
=== Full allocation with -S 0 ===
128
129
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
130
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
131
new file mode 100755
132
index XXXXXXX..XXXXXXX
133
--- /dev/null
134
+++ b/tests/qemu-iotests/214
135
@@ -XXX,XX +XXX,XX @@
136
+#!/bin/bash
137
+#
138
+# Test qcow2 image compression
139
+#
140
+# Copyright (C) 2018 Igalia, S.L.
141
+# Author: Alberto Garcia <berto@igalia.com>
142
+#
143
+# This program is free software; you can redistribute it and/or modify
144
+# it under the terms of the GNU General Public License as published by
145
+# the Free Software Foundation; either version 2 of the License, or
146
+# (at your option) any later version.
147
+#
148
+# This program is distributed in the hope that it will be useful,
149
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
150
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151
+# GNU General Public License for more details.
152
+#
153
+# You should have received a copy of the GNU General Public License
154
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
155
+#
156
+
157
+seq=$(basename "$0")
158
+echo "QA output created by $seq"
159
+
160
+here=$PWD
161
+status=1    # failure is the default!
162
+
163
+_cleanup()
164
+{
165
+ _cleanup_test_img
166
+}
167
+trap "_cleanup; exit \$status" 0 1 2 3 15
168
+
169
+# get standard environment, filters and checks
170
+. ./common.rc
171
+. ./common.filter
172
+
173
+_supported_fmt qcow2
174
+_supported_proto file
175
+_supported_os Linux
176
+
177
+# Repairing the corrupted image requires qemu-img check to store a
178
+# refcount up to 3, which requires at least two refcount bits.
179
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
180
+
181
+
182
+echo
183
+echo "=== Corrupted size field in compressed cluster descriptor ==="
184
+echo
185
+# Create an empty image and fill half of it with compressed data.
186
+# The L2 entries of the two compressed clusters are located at
187
+# 0x800000 and 0x800008, their original values are 0x4008000000a00000
188
+# and 0x4008000000a00802 (5 sectors for compressed data each).
189
+_make_test_img 8M -o cluster_size=2M
190
+$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
191
+ 2>&1 | _filter_qemu_io | _filter_testdir
192
+
193
+# Reduce size of compressed data to 4 sectors: this corrupts the image.
194
+poke_file "$TEST_IMG" $((0x800000)) "\x40\x06"
195
+$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
196
+
197
+# 'qemu-img check' however doesn't see anything wrong because it
198
+# doesn't try to decompress the data and the refcounts are consistent.
199
+# TODO: update qemu-img so this can be detected.
200
+_check_test_img
201
+
202
+# Increase size of compressed data to the maximum (8192 sectors).
203
+# This makes QEMU read more data (8192 sectors instead of 5, host
204
+# addresses [0xa00000, 0xdfffff]), but the decompression algorithm
205
+# stops once we have enough to restore the uncompressed cluster, so
206
+# the rest of the data is ignored.
207
+poke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe"
208
+# Do it also for the second compressed cluster (L2 entry at 0x800008).
209
+# In this case the compressed data would span 3 host clusters
210
+# (host addresses: [0xa00802, 0xe00801])
211
+poke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe"
212
+
213
+# Here the image is too small so we're asking QEMU to read beyond the
214
+# end of the image.
215
+$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
216
+# But if we grow the image we won't be reading beyond its end anymore.
217
+$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
218
+$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
219
+
220
+# The refcount data is however wrong because due to the increased size
221
+# of the compressed data it now reaches the following host clusters.
222
+# This can be repaired by qemu-img check by increasing the refcount of
223
+# those clusters.
224
+# TODO: update qemu-img to correct the compressed cluster size instead.
225
+_check_test_img -r all
226
+$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
227
+$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
228
+
229
+# success, all done
230
+echo '*** done'
231
+rm -f $seq.full
232
+status=0
233
diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out
234
new file mode 100644
235
index XXXXXXX..XXXXXXX
236
--- /dev/null
237
+++ b/tests/qemu-iotests/214.out
238
@@ -XXX,XX +XXX,XX @@
239
+QA output created by 214
240
+
241
+=== Corrupted size field in compressed cluster descriptor ===
242
+
243
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
244
+wrote 2097152/2097152 bytes at offset 0
245
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
246
+wrote 2097152/2097152 bytes at offset 2097152
247
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
248
+read failed: Input/output error
249
+No errors were found on the image.
250
+read 4194304/4194304 bytes at offset 0
251
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
252
+wrote 4194304/4194304 bytes at offset 4194304
253
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+read 4194304/4194304 bytes at offset 0
255
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
256
+ERROR cluster 6 refcount=1 reference=3
257
+ERROR cluster 7 refcount=1 reference=2
258
+Repairing cluster 6 refcount=1 reference=3
259
+Repairing cluster 7 refcount=1 reference=2
260
+Repairing OFLAG_COPIED data cluster: l2_entry=8000000000c00000 refcount=3
261
+Repairing OFLAG_COPIED data cluster: l2_entry=8000000000e00000 refcount=2
262
+The following inconsistencies were found and repaired:
263
+
264
+ 0 leaked clusters
265
+ 4 corruptions
266
+
267
+Double checking the fixed image now...
268
+No errors were found on the image.
269
+read 4194304/4194304 bytes at offset 0
270
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
271
+read 4194304/4194304 bytes at offset 4194304
272
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+*** done
274
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
275
index XXXXXXX..XXXXXXX 100644
276
--- a/tests/qemu-iotests/group
277
+++ b/tests/qemu-iotests/group
278
@@ -XXX,XX +XXX,XX @@
279
211 rw auto quick
280
212 rw auto quick
281
213 rw auto quick
282
+214 rw auto
283
218 rw auto quick
284
--
285
2.13.6
286
287
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Compressed clusters are not supposed to have the COPIED bit set.
4
"qemu-img check" detects that and prints an error message reporting
5
the number of the affected host cluster. This doesn't make much sense
6
because compressed clusters are not aligned to host clusters, so it
7
would be better to report the offset instead. Plus, the calculation is
8
wrong and it uses the raw L2 entry as if it was simply an offset.
9
10
This patch fixes the error message and reports the offset of the
11
compressed cluster.
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Message-id: 0f687957feb72e80c740403191a47e607c2463fe.1523376013.git.berto@igalia.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/qcow2-refcount.c | 4 ++--
18
1 file changed, 2 insertions(+), 2 deletions(-)
19
20
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qcow2-refcount.c
23
+++ b/block/qcow2-refcount.c
24
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
25
case QCOW2_CLUSTER_COMPRESSED:
26
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
27
if (l2_entry & QCOW_OFLAG_COPIED) {
28
- fprintf(stderr, "ERROR: cluster %" PRId64 ": "
29
+ fprintf(stderr, "ERROR: coffset=0x%" PRIx64 ": "
30
"copied flag must never be set for compressed "
31
- "clusters\n", l2_entry >> s->cluster_bits);
32
+ "clusters\n", l2_entry & s->cluster_offset_mask);
33
l2_entry &= ~QCOW_OFLAG_COPIED;
34
res->corruptions++;
35
}
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
We have just reduced the refcount cache size to the minimum unless
4
the user explicitly requests a larger one, so we have to update the
5
documentation to reflect this change.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Message-id: c5f0bde23558dd9d33b21fffc76ac9953cc19c56.1523968389.git.berto@igalia.com
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
docs/qcow2-cache.txt | 33 ++++++++++++++++-----------------
13
1 file changed, 16 insertions(+), 17 deletions(-)
14
15
diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt
16
index XXXXXXX..XXXXXXX 100644
17
--- a/docs/qcow2-cache.txt
18
+++ b/docs/qcow2-cache.txt
19
@@ -XXX,XX +XXX,XX @@ There are three options available, and all of them take bytes:
20
"refcount-cache-size": maximum size of the refcount block cache
21
"cache-size": maximum size of both caches combined
22
23
-There are two things that need to be taken into account:
24
+There are a few things that need to be taken into account:
25
26
- Both caches must have a size that is a multiple of the cluster size
27
(or the cache entry size: see "Using smaller cache sizes" below).
28
29
- - If you only set one of the options above, QEMU will automatically
30
- adjust the others so that the L2 cache is 4 times bigger than the
31
- refcount cache.
32
+ - The default L2 cache size is 8 clusters or 1MB (whichever is more),
33
+ and the minimum is 2 clusters (or 2 cache entries, see below).
34
35
-This means that these options are equivalent:
36
+ - The default (and minimum) refcount cache size is 4 clusters.
37
38
- -drive file=hd.qcow2,l2-cache-size=2097152
39
- -drive file=hd.qcow2,refcount-cache-size=524288
40
- -drive file=hd.qcow2,cache-size=2621440
41
+ - If only "cache-size" is specified then QEMU will assign as much
42
+ memory as possible to the L2 cache before increasing the refcount
43
+ cache size.
44
45
-The reason for this 1/4 ratio is to ensure that both caches cover the
46
-same amount of disk space. Note however that this is only valid with
47
-the default value of refcount_bits (16). If you are using a different
48
-value you might want to calculate both cache sizes yourself since QEMU
49
-will always use the same 1/4 ratio.
50
+Unlike L2 tables, refcount blocks are not used during normal I/O but
51
+only during allocations and internal snapshots. In most cases they are
52
+accessed sequentially (even during random guest I/O) so increasing the
53
+refcount cache size won't have any measurable effect in performance
54
+(this can change if you are using internal snapshots, so you may want
55
+to think about increasing the cache size if you use them heavily).
56
57
-It's also worth mentioning that there's no strict need for both caches
58
-to cover the same amount of disk space. The refcount cache is used
59
-much less often than the L2 cache, so it's perfectly reasonable to
60
-keep it small.
61
+Before QEMU 2.12 the refcount cache had a default size of 1/4 of the
62
+L2 cache size. This resulted in unnecessarily large caches, so now the
63
+refcount cache is as small as possible unless overridden by the user.
64
65
66
Using smaller cache entries
67
--
68
2.13.6
69
70
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Currently, common.qemu only allows to match for results indicating
4
success. The only way to fail is by provoking a timeout. However,
5
sometimes we do have a defined failure output and can match for that,
6
which saves us from having to wait for the timeout in case of failure.
7
Because failure can sometimes just result in a _notrun in the test, it
8
is actually important to care about being able to fail quickly.
9
10
Also, sometimes we simply do not get any specific output in case of
11
success. The only way to handle this currently would be to define an
12
error message as the string to look for, which means that actual success
13
results in a timeout. This is really bad because it unnecessarily slows
14
down a succeeding test.
15
16
Therefore, this patch adds a new parameter $success_or_failure to
17
_timed_wait_for and _send_qemu_cmd. Setting this to a non-empty string
18
makes both commands expect two match parameters: If the first matches,
19
the function succeeds. If the second matches, the function fails.
20
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Message-id: 20180406151731.4285-2-mreitz@redhat.com
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
tests/qemu-iotests/common.qemu | 58 +++++++++++++++++++++++++++++++++++++-----
26
1 file changed, 51 insertions(+), 7 deletions(-)
27
28
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
29
index XXXXXXX..XXXXXXX 100644
30
--- a/tests/qemu-iotests/common.qemu
31
+++ b/tests/qemu-iotests/common.qemu
32
@@ -XXX,XX +XXX,XX @@ _in_fd=4
33
# response is not echoed out.
34
# If $mismatch_only is set, only non-matching responses will
35
# be echoed.
36
+#
37
+# If $success_or_failure is set, the meaning of the arguments is
38
+# changed as follows:
39
+# $2: A string to search for in the response; if found, this indicates
40
+# success and ${QEMU_STATUS[$1]} is set to 0.
41
+# $3: A string to search for in the response; if found, this indicates
42
+# failure and the test is either aborted (if $qemu_error_no_exit
43
+# is not set) or ${QEMU_STATUS[$1]} is set to -1 (otherwise).
44
function _timed_wait_for()
45
{
46
local h=${1}
47
shift
48
49
+ if [ -z "${success_or_failure}" ]; then
50
+ success_match=${*}
51
+ failure_match=
52
+ else
53
+ success_match=${1}
54
+ failure_match=${2}
55
+ fi
56
+
57
+ timeout=yes
58
+
59
QEMU_STATUS[$h]=0
60
while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
61
do
62
@@ -XXX,XX +XXX,XX @@ function _timed_wait_for()
63
echo "${resp}" | _filter_testdir | _filter_qemu \
64
| _filter_qemu_io | _filter_qmp | _filter_hmp
65
fi
66
- grep -q "${*}" < <(echo "${resp}")
67
+ if [ -n "${failure_match}" ]; then
68
+ grep -q "${failure_match}" < <(echo "${resp}")
69
+ if [ $? -eq 0 ]; then
70
+ timeout=
71
+ break
72
+ fi
73
+ fi
74
+ grep -q "${success_match}" < <(echo "${resp}")
75
if [ $? -eq 0 ]; then
76
return
77
- elif [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then
78
+ fi
79
+ if [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then
80
echo "${resp}" | _filter_testdir | _filter_qemu \
81
| _filter_qemu_io | _filter_qmp | _filter_hmp
82
fi
83
@@ -XXX,XX +XXX,XX @@ function _timed_wait_for()
84
done
85
QEMU_STATUS[$h]=-1
86
if [ -z "${qemu_error_no_exit}" ]; then
87
- echo "Timeout waiting for ${*} on handle ${h}"
88
- exit 1 # Timeout means the test failed
89
+ if [ -n "${timeout}" ]; then
90
+ echo "Timeout waiting for ${success_match} on handle ${h}"
91
+ else
92
+ echo "Wrong response matching ${failure_match} on handle ${h}"
93
+ fi
94
+ exit 1 # Timeout or wrong match mean the test failed
95
fi
96
}
97
98
@@ -XXX,XX +XXX,XX @@ function _timed_wait_for()
99
# If $qemu_error_no_exit is set, then even if the expected response
100
# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in
101
# that case.
102
+#
103
+# If $success_or_failure is set, then the last two strings are the
104
+# strings the response will be scanned for. The first of the two
105
+# indicates success, the latter indicates failure. Failure is handled
106
+# like a timeout.
107
function _send_qemu_cmd()
108
{
109
local h=${1}
110
@@ -XXX,XX +XXX,XX @@ function _send_qemu_cmd()
111
use_error="no"
112
fi
113
# This array element extraction is done to accommodate pathnames with spaces
114
- cmd=${@: 1:${#@}-1}
115
- shift $(($# - 1))
116
+ if [ -z "${success_or_failure}" ]; then
117
+ cmd=${@: 1:${#@}-1}
118
+ shift $(($# - 1))
119
+ else
120
+ cmd=${@: 1:${#@}-2}
121
+ shift $(($# - 2))
122
+ fi
123
124
while [ ${count} -gt 0 ]
125
do
126
echo "${cmd}" >&${QEMU_IN[${h}]}
127
if [ -n "${1}" ]; then
128
- qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}"
129
+ if [ -z "${success_or_failure}" ]; then
130
+ qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}"
131
+ else
132
+ qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}"
133
+ fi
134
if [ ${QEMU_STATUS[$h]} -eq 0 ]; then
135
return
136
fi
137
--
138
2.13.6
139
140
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
userfaultfd support depends on the host kernel, so it may not be
4
available. If so, 181 and 201 should be skipped.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20180406151731.4285-3-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/181 | 13 +++++++++++++
11
tests/qemu-iotests/201 | 13 +++++++++++++
12
2 files changed, 26 insertions(+)
13
14
diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/181
17
+++ b/tests/qemu-iotests/181
18
@@ -XXX,XX +XXX,XX @@ echo
19
# Enable postcopy-ram capability both on source and destination
20
silent=yes
21
_send_qemu_cmd $dest 'migrate_set_capability postcopy-ram on' "(qemu)"
22
+
23
+qemu_error_no_exit=yes success_or_failure=yes \
24
+ _send_qemu_cmd $dest '' "(qemu)" "Postcopy is not supported"
25
+if [ ${QEMU_STATUS[$dest]} -lt 0 ]; then
26
+ _send_qemu_cmd $dest '' "(qemu)"
27
+
28
+ _send_qemu_cmd $src 'quit' ""
29
+ _send_qemu_cmd $dest 'quit' ""
30
+ wait=1 _cleanup_qemu
31
+
32
+ _notrun 'Postcopy is not supported'
33
+fi
34
+
35
_send_qemu_cmd $src 'migrate_set_speed 4k' "(qemu)"
36
_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)"
37
_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)"
38
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
39
index XXXXXXX..XXXXXXX 100755
40
--- a/tests/qemu-iotests/201
41
+++ b/tests/qemu-iotests/201
42
@@ -XXX,XX +XXX,XX @@ echo
43
44
silent=yes
45
_send_qemu_cmd $dest 'migrate_set_capability postcopy-ram on' "(qemu)"
46
+
47
+qemu_error_no_exit=yes success_or_failure=yes \
48
+ _send_qemu_cmd $dest '' "(qemu)" "Postcopy is not supported"
49
+if [ ${QEMU_STATUS[$dest]} -lt 0 ]; then
50
+ _send_qemu_cmd $dest '' "(qemu)"
51
+
52
+ _send_qemu_cmd $src 'quit' ""
53
+ _send_qemu_cmd $dest 'quit' ""
54
+ wait=1 _cleanup_qemu
55
+
56
+ _notrun 'Postcopy is not supported'
57
+fi
58
+
59
_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)"
60
_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)"
61
62
--
63
2.13.6
64
65
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
This adds a simple copy-on-read filter driver. It relies on the already
4
existing COR functionality in the central block layer code, which may be
5
moved here once we no longer need it there.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20180421132929.21610-2-mreitz@redhat.com
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
qapi/block-core.json | 5 +-
14
block/copy-on-read.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++
15
block/Makefile.objs | 2 +-
16
3 files changed, 176 insertions(+), 2 deletions(-)
17
create mode 100644 block/copy-on-read.c
18
19
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
index XXXXXXX..XXXXXXX 100644
21
--- a/qapi/block-core.json
22
+++ b/qapi/block-core.json
23
@@ -XXX,XX +XXX,XX @@
24
# @vxhs: Since 2.10
25
# @throttle: Since 2.11
26
# @nvme: Since 2.12
27
+# @copy-on-read: Since 2.13
28
#
29
# Since: 2.9
30
##
31
{ 'enum': 'BlockdevDriver',
32
- 'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop',
33
+ 'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop', 'copy-on-read',
34
'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
35
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
36
'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', 'qcow2', 'qed',
37
@@ -XXX,XX +XXX,XX @@
38
'blkverify': 'BlockdevOptionsBlkverify',
39
'bochs': 'BlockdevOptionsGenericFormat',
40
'cloop': 'BlockdevOptionsGenericFormat',
41
+ 'copy-on-read':'BlockdevOptionsGenericFormat',
42
'dmg': 'BlockdevOptionsGenericFormat',
43
'file': 'BlockdevOptionsFile',
44
'ftp': 'BlockdevOptionsCurlFtp',
45
@@ -XXX,XX +XXX,XX @@
46
'blkverify': 'BlockdevCreateNotSupported',
47
'bochs': 'BlockdevCreateNotSupported',
48
'cloop': 'BlockdevCreateNotSupported',
49
+ 'copy-on-read': 'BlockdevCreateNotSupported',
50
'dmg': 'BlockdevCreateNotSupported',
51
'file': 'BlockdevCreateOptionsFile',
52
'ftp': 'BlockdevCreateNotSupported',
53
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
54
new file mode 100644
55
index XXXXXXX..XXXXXXX
56
--- /dev/null
57
+++ b/block/copy-on-read.c
58
@@ -XXX,XX +XXX,XX @@
59
+/*
60
+ * Copy-on-read filter block driver
61
+ *
62
+ * Copyright (c) 2018 Red Hat, Inc.
63
+ *
64
+ * Author:
65
+ * Max Reitz <mreitz@redhat.com>
66
+ *
67
+ * This program is free software; you can redistribute it and/or
68
+ * modify it under the terms of the GNU General Public License as
69
+ * published by the Free Software Foundation; either version 2 or
70
+ * (at your option) version 3 of the License.
71
+ *
72
+ * This program is distributed in the hope that it will be useful,
73
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
74
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75
+ * GNU General Public License for more details.
76
+ *
77
+ * You should have received a copy of the GNU General Public License
78
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
79
+ */
80
+
81
+#include "qemu/osdep.h"
82
+#include "block/block_int.h"
83
+
84
+
85
+static int cor_open(BlockDriverState *bs, QDict *options, int flags,
86
+ Error **errp)
87
+{
88
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
89
+ errp);
90
+ if (!bs->file) {
91
+ return -EINVAL;
92
+ }
93
+
94
+ bs->supported_write_flags = BDRV_REQ_FUA &
95
+ bs->file->bs->supported_write_flags;
96
+
97
+ bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
98
+ bs->file->bs->supported_zero_flags;
99
+
100
+ return 0;
101
+}
102
+
103
+
104
+static void cor_close(BlockDriverState *bs)
105
+{
106
+}
107
+
108
+
109
+#define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
110
+ | BLK_PERM_WRITE \
111
+ | BLK_PERM_RESIZE)
112
+#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
113
+
114
+static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
115
+ const BdrvChildRole *role,
116
+ BlockReopenQueue *reopen_queue,
117
+ uint64_t perm, uint64_t shared,
118
+ uint64_t *nperm, uint64_t *nshared)
119
+{
120
+ if (c == NULL) {
121
+ *nperm = (perm & PERM_PASSTHROUGH) | BLK_PERM_WRITE_UNCHANGED;
122
+ *nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
123
+ return;
124
+ }
125
+
126
+ *nperm = (perm & PERM_PASSTHROUGH) |
127
+ (c->perm & PERM_UNCHANGED);
128
+ *nshared = (shared & PERM_PASSTHROUGH) |
129
+ (c->shared_perm & PERM_UNCHANGED);
130
+}
131
+
132
+
133
+static int64_t cor_getlength(BlockDriverState *bs)
134
+{
135
+ return bdrv_getlength(bs->file->bs);
136
+}
137
+
138
+
139
+static int cor_truncate(BlockDriverState *bs, int64_t offset,
140
+ PreallocMode prealloc, Error **errp)
141
+{
142
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
143
+}
144
+
145
+
146
+static int coroutine_fn cor_co_preadv(BlockDriverState *bs,
147
+ uint64_t offset, uint64_t bytes,
148
+ QEMUIOVector *qiov, int flags)
149
+{
150
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov,
151
+ flags | BDRV_REQ_COPY_ON_READ);
152
+}
153
+
154
+
155
+static int coroutine_fn cor_co_pwritev(BlockDriverState *bs,
156
+ uint64_t offset, uint64_t bytes,
157
+ QEMUIOVector *qiov, int flags)
158
+{
159
+
160
+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
161
+}
162
+
163
+
164
+static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
165
+ int64_t offset, int bytes,
166
+ BdrvRequestFlags flags)
167
+{
168
+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
169
+}
170
+
171
+
172
+static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
173
+ int64_t offset, int bytes)
174
+{
175
+ return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
176
+}
177
+
178
+
179
+static void cor_eject(BlockDriverState *bs, bool eject_flag)
180
+{
181
+ bdrv_eject(bs->file->bs, eject_flag);
182
+}
183
+
184
+
185
+static void cor_lock_medium(BlockDriverState *bs, bool locked)
186
+{
187
+ bdrv_lock_medium(bs->file->bs, locked);
188
+}
189
+
190
+
191
+static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
192
+ BlockDriverState *candidate)
193
+{
194
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
195
+}
196
+
197
+
198
+BlockDriver bdrv_copy_on_read = {
199
+ .format_name = "copy-on-read",
200
+
201
+ .bdrv_open = cor_open,
202
+ .bdrv_close = cor_close,
203
+ .bdrv_child_perm = cor_child_perm,
204
+
205
+ .bdrv_getlength = cor_getlength,
206
+ .bdrv_truncate = cor_truncate,
207
+
208
+ .bdrv_co_preadv = cor_co_preadv,
209
+ .bdrv_co_pwritev = cor_co_pwritev,
210
+ .bdrv_co_pwrite_zeroes = cor_co_pwrite_zeroes,
211
+ .bdrv_co_pdiscard = cor_co_pdiscard,
212
+
213
+ .bdrv_eject = cor_eject,
214
+ .bdrv_lock_medium = cor_lock_medium,
215
+
216
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
217
+
218
+ .bdrv_recurse_is_first_non_filter = cor_recurse_is_first_non_filter,
219
+
220
+ .has_variable_length = true,
221
+ .is_filter = true,
222
+};
223
+
224
+static void bdrv_copy_on_read_init(void)
225
+{
226
+ bdrv_register(&bdrv_copy_on_read);
227
+}
228
+
229
+block_init(bdrv_copy_on_read_init);
230
diff --git a/block/Makefile.objs b/block/Makefile.objs
231
index XXXXXXX..XXXXXXX 100644
232
--- a/block/Makefile.objs
233
+++ b/block/Makefile.objs
234
@@ -XXX,XX +XXX,XX @@ block-obj-y += accounting.o dirty-bitmap.o
235
block-obj-y += write-threshold.o
236
block-obj-y += backup.o
237
block-obj-$(CONFIG_REPLICATION) += replication.o
238
-block-obj-y += throttle.o
239
+block-obj-y += throttle.o copy-on-read.o
240
241
block-obj-y += crypto.o
242
243
--
244
2.13.6
245
246
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Currently we never actually check whether the WRITE_UNCHANGED
4
permission has been taken for unchanging writes. But the one check that
5
is commented out checks both WRITE and WRITE_UNCHANGED; and considering
6
that WRITE_UNCHANGED is already documented as being weaker than WRITE,
7
we should probably explicitly document WRITE to include WRITE_UNCHANGED.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Message-id: 20180421132929.21610-3-mreitz@redhat.com
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
include/block/block.h | 3 +++
17
1 file changed, 3 insertions(+)
18
19
diff --git a/include/block/block.h b/include/block/block.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block.h
22
+++ b/include/block/block.h
23
@@ -XXX,XX +XXX,XX @@ enum {
24
* This permission (which is weaker than BLK_PERM_WRITE) is both enough and
25
* required for writes to the block node when the caller promises that
26
* the visible disk content doesn't change.
27
+ *
28
+ * As the BLK_PERM_WRITE permission is strictly stronger, either is
29
+ * sufficient to perform an unchanging write.
30
*/
31
BLK_PERM_WRITE_UNCHANGED = 0x04,
32
33
--
34
2.13.6
35
36
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Message-id: 20180421132929.21610-5-mreitz@redhat.com
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/io.c | 6 ++++--
11
1 file changed, 4 insertions(+), 2 deletions(-)
12
13
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/io.c
16
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
18
/* FIXME: Should we (perhaps conditionally) be setting
19
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
20
* that still correctly reads as zero? */
21
- ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, 0);
22
+ ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum,
23
+ BDRV_REQ_WRITE_UNCHANGED);
24
} else {
25
/* This does not change the data on the disk, it is not
26
* necessary to flush even in cache=writethrough mode.
27
*/
28
ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
29
- &local_qiov, 0);
30
+ &local_qiov,
31
+ BDRV_REQ_WRITE_UNCHANGED);
32
}
33
34
if (ret < 0) {
35
--
36
2.13.6
37
38
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
We just need to forward it to quorum's children (except in case of a
4
rewrite because of corruption), but for that we first have to support
5
flags in child requests at all.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20180421132929.21610-6-mreitz@redhat.com
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/quorum.c | 19 +++++++++++++------
15
1 file changed, 13 insertions(+), 6 deletions(-)
16
17
diff --git a/block/quorum.c b/block/quorum.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/quorum.c
20
+++ b/block/quorum.c
21
@@ -XXX,XX +XXX,XX @@ struct QuorumAIOCB {
22
/* Request metadata */
23
uint64_t offset;
24
uint64_t bytes;
25
+ int flags;
26
27
QEMUIOVector *qiov; /* calling IOV */
28
29
@@ -XXX,XX +XXX,XX @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b)
30
static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
31
QEMUIOVector *qiov,
32
uint64_t offset,
33
- uint64_t bytes)
34
+ uint64_t bytes,
35
+ int flags)
36
{
37
BDRVQuorumState *s = bs->opaque;
38
QuorumAIOCB *acb = g_new(QuorumAIOCB, 1);
39
@@ -XXX,XX +XXX,XX @@ static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
40
.bs = bs,
41
.offset = offset,
42
.bytes = bytes,
43
+ .flags = flags,
44
.qiov = qiov,
45
.votes.compare = quorum_sha256_compare,
46
.votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list),
47
@@ -XXX,XX +XXX,XX @@ static void quorum_rewrite_entry(void *opaque)
48
BDRVQuorumState *s = acb->bs->opaque;
49
50
/* Ignore any errors, it's just a correction attempt for already
51
- * corrupted data. */
52
+ * corrupted data.
53
+ * Mask out BDRV_REQ_WRITE_UNCHANGED because this overwrites the
54
+ * area with different data from the other children. */
55
bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes,
56
- acb->qiov, 0);
57
+ acb->qiov, acb->flags & ~BDRV_REQ_WRITE_UNCHANGED);
58
59
/* Wake up the caller after the last rewrite */
60
acb->rewrite_count--;
61
@@ -XXX,XX +XXX,XX @@ static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
62
uint64_t bytes, QEMUIOVector *qiov, int flags)
63
{
64
BDRVQuorumState *s = bs->opaque;
65
- QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
66
+ QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
67
int ret;
68
69
acb->is_read = true;
70
@@ -XXX,XX +XXX,XX @@ static void write_quorum_entry(void *opaque)
71
72
sacb->bs = s->children[i]->bs;
73
sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes,
74
- acb->qiov, 0);
75
+ acb->qiov, acb->flags);
76
if (sacb->ret == 0) {
77
acb->success_count++;
78
} else {
79
@@ -XXX,XX +XXX,XX @@ static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
80
uint64_t bytes, QEMUIOVector *qiov, int flags)
81
{
82
BDRVQuorumState *s = bs->opaque;
83
- QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
84
+ QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
85
int i, ret;
86
87
for (i = 0; i < s->num_children; i++) {
88
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
89
}
90
s->next_child_index = s->num_children;
91
92
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED;
93
+
94
g_free(opened);
95
goto exit;
96
97
--
98
2.13.6
99
100
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Message-id: 20180421132929.21610-8-mreitz@redhat.com
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/197 | 1 +
11
1 file changed, 1 insertion(+)
12
13
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/197
16
+++ b/tests/qemu-iotests/197
17
@@ -XXX,XX +XXX,XX @@ esac
18
_cleanup()
19
{
20
_cleanup_test_img
21
+ rm -f "$TEST_WRAP"
22
rm -f "$BLKDBG_CONF"
23
}
24
trap "_cleanup; exit \$status" 0 1 2 3 15
25
--
26
2.13.6
27
28
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
iotest 197 tests copy-on-read using the (now old) copy-on-read flag.
4
Copy it to 215 and modify it to use the COR filter driver instead.
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20180421132929.21610-9-mreitz@redhat.com
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/215 | 120 +++++++++++++++++++++++++++++++++++++++++++++
12
tests/qemu-iotests/215.out | 26 ++++++++++
13
tests/qemu-iotests/group | 1 +
14
3 files changed, 147 insertions(+)
15
create mode 100755 tests/qemu-iotests/215
16
create mode 100644 tests/qemu-iotests/215.out
17
18
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
19
new file mode 100755
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/qemu-iotests/215
23
@@ -XXX,XX +XXX,XX @@
24
+#!/bin/bash
25
+#
26
+# Test case for copy-on-read into qcow2, using the COR filter driver
27
+#
28
+# Copyright (C) 2018 Red Hat, Inc.
29
+#
30
+# This program is free software; you can redistribute it and/or modify
31
+# it under the terms of the GNU General Public License as published by
32
+# the Free Software Foundation; either version 2 of the License, or
33
+# (at your option) any later version.
34
+#
35
+# This program is distributed in the hope that it will be useful,
36
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
37
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38
+# GNU General Public License for more details.
39
+#
40
+# You should have received a copy of the GNU General Public License
41
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
42
+#
43
+
44
+seq="$(basename $0)"
45
+echo "QA output created by $seq"
46
+
47
+here="$PWD"
48
+status=1 # failure is the default!
49
+
50
+# get standard environment, filters and checks
51
+. ./common.rc
52
+. ./common.filter
53
+
54
+TEST_WRAP="$TEST_DIR/t.wrap.qcow2"
55
+BLKDBG_CONF="$TEST_DIR/blkdebug.conf"
56
+
57
+# Sanity check: our use of blkdebug fails if $TEST_DIR contains spaces
58
+# or other problems
59
+case "$TEST_DIR" in
60
+ *[^-_a-zA-Z0-9/]*)
61
+ _notrun "Suspicious TEST_DIR='$TEST_DIR', cowardly refusing to run" ;;
62
+esac
63
+
64
+_cleanup()
65
+{
66
+ _cleanup_test_img
67
+ rm -f "$TEST_WRAP"
68
+ rm -f "$BLKDBG_CONF"
69
+}
70
+trap "_cleanup; exit \$status" 0 1 2 3 15
71
+
72
+# Test is supported for any backing file; but we force qcow2 for our wrapper.
73
+_supported_fmt generic
74
+_supported_proto generic
75
+_supported_os Linux
76
+# LUKS support may be possible, but it complicates things.
77
+_unsupported_fmt luks
78
+
79
+echo
80
+echo '=== Copy-on-read ==='
81
+echo
82
+
83
+# Prep the images
84
+# VPC rounds image sizes to a specific geometry, force a specific size.
85
+if [ "$IMGFMT" = "vpc" ]; then
86
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size")
87
+fi
88
+_make_test_img 4G
89
+$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
90
+IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
91
+ _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
92
+$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
93
+
94
+# Ensure that a read of two clusters, but where one is already allocated,
95
+# does not re-write the allocated cluster
96
+cat > "$BLKDBG_CONF" <<EOF
97
+[inject-error]
98
+event = "cor_write"
99
+sector = "2048"
100
+EOF
101
+$QEMU_IO -c "open \
102
+ -o driver=copy-on-read,file.driver=blkdebug,file.config=$BLKDBG_CONF,file.image.driver=qcow2 $TEST_WRAP" \
103
+ -c "read -P 0 1M 128k" | _filter_qemu_io
104
+
105
+# Read the areas we want copied. A zero-length read should still be a
106
+# no-op. The next read is under 2G, but aligned so that rounding to
107
+# clusters copies more than 2G of zeroes. The final read will pick up
108
+# the non-zero data in the same cluster. Since a 2G read may exhaust
109
+# memory on some machines (particularly 32-bit), we skip the test if
110
+# that fails due to memory pressure.
111
+$QEMU_IO \
112
+ -c "open -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \
113
+ -c "read 0 0" \
114
+ | _filter_qemu_io
115
+output=$($QEMU_IO \
116
+ -c "open -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \
117
+ -c "read -P 0 1k $((2*1024*1024*1024 - 512))" \
118
+ 2>&1 | _filter_qemu_io)
119
+case $output in
120
+ *allocate*)
121
+ _notrun "Insufficent memory to run test" ;;
122
+ *) printf '%s\n' "$output" ;;
123
+esac
124
+$QEMU_IO \
125
+ -c "open -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \
126
+ -c "read -P 0 $((3*1024*1024*1024 + 1024)) 1k" \
127
+ | _filter_qemu_io
128
+
129
+# Copy-on-read is incompatible with read-only
130
+$QEMU_IO \
131
+ -c "open -r -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \
132
+ 2>&1 | _filter_testdir
133
+
134
+# Break the backing chain, and show that images are identical, and that
135
+# we properly copied over explicit zeros.
136
+$QEMU_IMG rebase -u -b "" -f qcow2 "$TEST_WRAP"
137
+$QEMU_IO -f qcow2 -c map "$TEST_WRAP"
138
+_check_test_img
139
+$QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP"
140
+
141
+# success, all done
142
+echo '*** done'
143
+status=0
144
diff --git a/tests/qemu-iotests/215.out b/tests/qemu-iotests/215.out
145
new file mode 100644
146
index XXXXXXX..XXXXXXX
147
--- /dev/null
148
+++ b/tests/qemu-iotests/215.out
149
@@ -XXX,XX +XXX,XX @@
150
+QA output created by 215
151
+
152
+=== Copy-on-read ===
153
+
154
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296
155
+wrote 1024/1024 bytes at offset 3221225472
156
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
157
+Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
158
+wrote 65536/65536 bytes at offset 1048576
159
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
160
+read 131072/131072 bytes at offset 1048576
161
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
162
+read 0/0 bytes at offset 0
163
+0 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
164
+read 2147483136/2147483136 bytes at offset 1024
165
+2 GiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
166
+read 1024/1024 bytes at offset 3221226496
167
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
+can't open device TEST_DIR/t.wrap.qcow2: Block node is read-only
169
+2 GiB (0x80010000) bytes allocated at offset 0 bytes (0x0)
170
+1023.938 MiB (0x3fff0000) bytes not allocated at offset 2 GiB (0x80010000)
171
+64 KiB (0x10000) bytes allocated at offset 3 GiB (0xc0000000)
172
+1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000)
173
+No errors were found on the image.
174
+Images are identical.
175
+*** done
176
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
177
index XXXXXXX..XXXXXXX 100644
178
--- a/tests/qemu-iotests/group
179
+++ b/tests/qemu-iotests/group
180
@@ -XXX,XX +XXX,XX @@
181
212 rw auto quick
182
213 rw auto quick
183
214 rw auto
184
+215 rw auto quick
185
218 rw auto quick
186
--
187
2.13.6
188
189
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Some block drivers (iscsi and file-posix when dealing with device files)
4
do not actually support truncation, even though they provide a
5
.bdrv_truncate() method and will happily return success when providing a
6
new size that does not exceed the current size. This is because these
7
drivers expect the user to resize the image outside of qemu and then
8
provide qemu with that information through the block_resize command
9
(compare cb1b83e740384b4e0d950f3d7c81c02b8ce86c2e).
10
11
Of course, anyone using qemu-img resize will find that behavior useless.
12
So we should check the actual size of the image after the supposedly
13
successful truncation took place, emit an error if nothing changed and
14
emit a warning if the target size was not met.
15
16
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1523065
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Message-id: 20180421163957.29872-1-mreitz@redhat.com
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
qemu-img.c | 39 +++++++++++++++++++++++++++++++++++----
23
1 file changed, 35 insertions(+), 4 deletions(-)
24
25
diff --git a/qemu-img.c b/qemu-img.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/qemu-img.c
28
+++ b/qemu-img.c
29
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
30
Error *err = NULL;
31
int c, ret, relative;
32
const char *filename, *fmt, *size;
33
- int64_t n, total_size, current_size;
34
+ int64_t n, total_size, current_size, new_size;
35
bool quiet = false;
36
BlockBackend *blk = NULL;
37
PreallocMode prealloc = PREALLOC_MODE_OFF;
38
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
39
}
40
41
ret = blk_truncate(blk, total_size, prealloc, &err);
42
- if (!ret) {
43
- qprintf(quiet, "Image resized.\n");
44
- } else {
45
+ if (ret < 0) {
46
error_report_err(err);
47
+ goto out;
48
+ }
49
+
50
+ new_size = blk_getlength(blk);
51
+ if (new_size < 0) {
52
+ error_report("Failed to verify truncated image length: %s",
53
+ strerror(-new_size));
54
+ ret = -1;
55
+ goto out;
56
}
57
+
58
+ /* Some block drivers implement a truncation method, but only so
59
+ * the user can cause qemu to refresh the image's size from disk.
60
+ * The idea is that the user resizes the image outside of qemu and
61
+ * then invokes block_resize to inform qemu about it.
62
+ * (This includes iscsi and file-posix for device files.)
63
+ * Of course, that is not the behavior someone invoking
64
+ * qemu-img resize would find useful, so we catch that behavior
65
+ * here and tell the user. */
66
+ if (new_size != total_size && new_size == current_size) {
67
+ error_report("Image was not resized; resizing may not be supported "
68
+ "for this image");
69
+ ret = -1;
70
+ goto out;
71
+ }
72
+
73
+ if (new_size != total_size) {
74
+ warn_report("Image should have been resized to %" PRIi64
75
+ " bytes, but was resized to %" PRIi64 " bytes",
76
+ total_size, new_size);
77
+ }
78
+
79
+ qprintf(quiet, "Image resized.\n");
80
+
81
out:
82
blk_unref(blk);
83
if (ret) {
84
--
85
2.13.6
86
87
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Add BDRV_REQ_WRITE_UNCHANGED to the list of flags honored during pwrite
4
and pwrite_zeroes, and also add a note on when you absolutely need to
5
support it.
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20180502140359.18222-1-mreitz@redhat.com
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
include/block/block_int.h | 18 ++++++++++++++++--
13
1 file changed, 16 insertions(+), 2 deletions(-)
14
15
diff --git a/include/block/block_int.h b/include/block/block_int.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/block_int.h
18
+++ b/include/block/block_int.h
19
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
20
/* I/O Limits */
21
BlockLimits bl;
22
23
- /* Flags honored during pwrite (so far: BDRV_REQ_FUA) */
24
+ /* Flags honored during pwrite (so far: BDRV_REQ_FUA,
25
+ * BDRV_REQ_WRITE_UNCHANGED).
26
+ * If a driver does not support BDRV_REQ_WRITE_UNCHANGED, those
27
+ * writes will be issued as normal writes without the flag set.
28
+ * This is important to note for drivers that do not explicitly
29
+ * request a WRITE permission for their children and instead take
30
+ * the same permissions as their parent did (this is commonly what
31
+ * block filters do). Such drivers have to be aware that the
32
+ * parent may have taken a WRITE_UNCHANGED permission only and is
33
+ * issuing such requests. Drivers either must make sure that
34
+ * these requests do not result in plain WRITE accesses (usually
35
+ * by supporting BDRV_REQ_WRITE_UNCHANGED, and then forwarding
36
+ * every incoming write request as-is, including potentially that
37
+ * flag), or they have to explicitly take the WRITE permission for
38
+ * their children. */
39
unsigned int supported_write_flags;
40
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
41
- * BDRV_REQ_MAY_UNMAP) */
42
+ * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
43
unsigned int supported_zero_flags;
44
45
/* the following member gives a name to every node on the bs graph. */
46
--
47
2.13.6
48
49
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Currently, qemu-io only uses string-valued blockdev options (as all are
4
converted directly from QemuOpts) -- with one exception: -U adds the
5
force-share option as a boolean. This in itself is already a bit
6
questionable, but a real issue is that it also assumes the value already
7
existing in the options QDict would be a boolean, which is wrong.
8
9
That has the following effect:
10
11
$ ./qemu-io -r -U --image-opts \
12
driver=file,filename=/dev/null,force-share=off
13
[1] 15200 segmentation fault (core dumped) ./qemu-io -r -U
14
--image-opts driver=file,filename=/dev/null,force-share=off
15
16
Since @opts is converted from QemuOpts, the value must be a string, and
17
we have to compare it as such. Consequently, it makes sense to also set
18
it as a string instead of a boolean.
19
20
Cc: qemu-stable@nongnu.org
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Message-id: 20180502202051.15493-2-mreitz@redhat.com
23
Reviewed-by: Eric Blake <eblake@redhat.com>
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
---
26
qemu-io.c | 4 ++--
27
1 file changed, 2 insertions(+), 2 deletions(-)
28
29
diff --git a/qemu-io.c b/qemu-io.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/qemu-io.c
32
+++ b/qemu-io.c
33
@@ -XXX,XX +XXX,XX @@ static int openfile(char *name, int flags, bool writethrough, bool force_share,
34
opts = qdict_new();
35
}
36
if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE)
37
- && !qdict_get_bool(opts, BDRV_OPT_FORCE_SHARE)) {
38
+ && strcmp(qdict_get_str(opts, BDRV_OPT_FORCE_SHARE), "on")) {
39
error_report("-U conflicts with image options");
40
qobject_unref(opts);
41
return 1;
42
}
43
- qdict_put_bool(opts, BDRV_OPT_FORCE_SHARE, true);
44
+ qdict_put_str(opts, BDRV_OPT_FORCE_SHARE, "on");
45
}
46
qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err);
47
if (!qemuio_blk) {
48
--
49
2.13.6
50
51
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
img_open_opts() takes a QemuOpts and converts them to a QDict, so all
4
values therein are strings. Then it may try to call qdict_get_bool(),
5
however, which will fail with a segmentation fault every time:
6
7
$ ./qemu-img info -U --image-opts \
8
driver=file,filename=/dev/null,force-share=off
9
[1] 27869 segmentation fault (core dumped) ./qemu-img info -U
10
--image-opts driver=file,filename=/dev/null,force-share=off
11
12
Fix this by using qdict_get_str() and comparing the value as a string.
13
Also, when adding a force-share value to the QDict, add it as a string
14
so it fits the rest of the dict.
15
16
Cc: qemu-stable@nongnu.org
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Message-id: 20180502202051.15493-3-mreitz@redhat.com
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
qemu-img.c | 4 ++--
23
1 file changed, 2 insertions(+), 2 deletions(-)
24
25
diff --git a/qemu-img.c b/qemu-img.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/qemu-img.c
28
+++ b/qemu-img.c
29
@@ -XXX,XX +XXX,XX @@ static BlockBackend *img_open_opts(const char *optstr,
30
options = qemu_opts_to_qdict(opts, NULL);
31
if (force_share) {
32
if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
33
- && !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) {
34
+ && strcmp(qdict_get_str(options, BDRV_OPT_FORCE_SHARE), "on")) {
35
error_report("--force-share/-U conflicts with image options");
36
qobject_unref(options);
37
return NULL;
38
}
39
- qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
40
+ qdict_put_str(options, BDRV_OPT_FORCE_SHARE, "on");
41
}
42
blk = blk_new_open(NULL, NULL, options, flags, &local_err);
43
if (!blk) {
44
--
45
2.13.6
46
47
diff view generated by jsdifflib
Deleted patch
1
From: Max Reitz <mreitz@redhat.com>
2
1
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20180502202051.15493-4-mreitz@redhat.com
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/153 | 17 +++++++++++++++++
9
tests/qemu-iotests/153.out | 16 ++++++++++++++++
10
2 files changed, 33 insertions(+)
11
12
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/153
15
+++ b/tests/qemu-iotests/153
16
@@ -XXX,XX +XXX,XX @@ _run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
17
18
_cleanup_qemu
19
20
+echo
21
+echo "== Detecting -U and force-share conflicts =="
22
+
23
+echo
24
+echo 'No conflict:'
25
+$QEMU_IMG info -U --image-opts driver=null-co,force-share=on
26
+echo
27
+echo 'Conflict:'
28
+$QEMU_IMG info -U --image-opts driver=null-co,force-share=off
29
+
30
+echo
31
+echo 'No conflict:'
32
+$QEMU_IO -c 'open -r -U -o driver=null-co,force-share=on'
33
+echo
34
+echo 'Conflict:'
35
+$QEMU_IO -c 'open -r -U -o driver=null-co,force-share=off'
36
+
37
# success, all done
38
echo "*** done"
39
rm -f $seq.full
40
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
41
index XXXXXXX..XXXXXXX 100644
42
--- a/tests/qemu-iotests/153.out
43
+++ b/tests/qemu-iotests/153.out
44
@@ -XXX,XX +XXX,XX @@ Is another process using the image?
45
Closing the other
46
47
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
48
+
49
+== Detecting -U and force-share conflicts ==
50
+
51
+No conflict:
52
+image: null-co://
53
+file format: null-co
54
+virtual size: 1.0G (1073741824 bytes)
55
+disk size: unavailable
56
+
57
+Conflict:
58
+qemu-img: --force-share/-U conflicts with image options
59
+
60
+No conflict:
61
+
62
+Conflict:
63
+-U conflicts with image options
64
*** done
65
--
66
2.13.6
67
68
diff view generated by jsdifflib