1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
1
The following changes since commit fe8d2d5737ab20ed0118863f5eb888cae37122ab:
2
2
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
3
Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-3.0-pull-request' into staging (2018-07-04 22:38:10 +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 eaae29ef89d498d0eac553c77b554f310a47f809:
9
for you to fetch changes up to 7c20c808a5cbf5d244735bc78fc3138c739c1946:
10
10
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
11
file-posix: Unlock FD after creation (2018-07-05 11:07:58 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- Fix resize (extending) of short overlays
16
- qcow2: Use worker threads for compression to improve performance of
17
- nvme: introduce PMR support from NVMe 1.4 spec
17
'qemu-img convert -W' and compressed backup jobs
18
- qemu-storage-daemon: Fix non-string --object properties
18
- blklogwrites: New filter driver to log write requests to an image in
19
the dm-log-writes format
20
- file-posix: Fix image locking during image creation
21
- crypto: Fix memory leak in error path
22
- Error out instead of silently truncating node names
19
23
20
----------------------------------------------------------------
24
----------------------------------------------------------------
21
Alberto Garcia (1):
25
Aapo Vienamo (1):
22
qcow2: Add incompatibility note between backing files and raw external data files
26
block: Add blklogwrites
23
27
24
Andrzej Jakowski (1):
28
Ari Sundholm (4):
25
nvme: introduce PMR support from NVMe 1.4 spec
29
block: Move two block permission constants to the relevant enum
30
block/blklogwrites: Change log_sector_size from int64_t to uint64_t
31
block/blklogwrites: Add an option for appending to an old log
32
block/blklogwrites: Add an option for the update interval of the log superblock
26
33
27
Kevin Wolf (12):
34
Kevin Wolf (2):
28
block: Add flags to BlockDriver.bdrv_co_truncate()
35
block: Don't silently truncate node names
29
block: Add flags to bdrv(_co)_truncate()
36
block/crypto: Fix memory leak in create error path
30
block-backend: Add flags to blk_truncate()
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
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
40
37
41
Paolo Bonzini (1):
38
Max Reitz (2):
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
39
file-posix: Fix creation locking
40
file-posix: Unlock FD after creation
43
41
44
docs/interop/qcow2.txt | 3 +
42
Vladimir Sementsov-Ogievskiy (3):
45
hw/block/nvme.h | 2 +
43
qemu-img: allow compressed not-in-order writes
46
include/block/block.h | 5 +-
44
qcow2: refactor data compression
47
include/block/block_int.h | 10 +-
45
qcow2: add compress threads
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
49
include/qom/object_interfaces.h | 16 +++
50
include/sysemu/block-backend.h | 2 +-
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
96
46
47
qapi/block-core.json | 38 ++-
48
block/qcow2.h | 3 +
49
include/block/block.h | 7 +
50
block.c | 12 +-
51
block/blklogwrites.c | 547 ++++++++++++++++++++++++++++++++++++++++++
52
block/crypto.c | 2 +-
53
block/file-posix.c | 21 +-
54
block/qcow2.c | 138 ++++++++---
55
qemu-img.c | 5 -
56
MAINTAINERS | 6 +
57
block/Makefile.objs | 1 +
58
tests/qemu-iotests/051 | 15 ++
59
tests/qemu-iotests/051.out | 23 ++
60
tests/qemu-iotests/051.pc.out | 23 ++
61
14 files changed, 791 insertions(+), 50 deletions(-)
62
create mode 100644 block/blklogwrites.c
97
63
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Backing files and raw external data files are mutually exclusive.
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.
7
8
Suggested-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
docs/interop/qcow2.txt | 3 +++
15
1 file changed, 3 insertions(+)
16
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
18
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/interop/qcow2.txt
20
+++ b/docs/interop/qcow2.txt
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
22
is stored (NB: The string is not null terminated). 0 if the
23
image doesn't have a backing file.
24
25
+ Note: backing files are incompatible with raw external data
26
+ files (auto-clear feature bit 1).
27
+
28
16 - 19: backing_file_size
29
Length of the backing file name in bytes. Must not be
30
longer than 1023 bytes. Undefined if the image doesn't have
31
--
32
2.25.3
33
34
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
Test 244 checks the expected behavior of qcow2 external data files
4
with respect to zero and discarded clusters. Filesystems however
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.
9
10
This fixes docker tests on RHEL8.
11
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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
tests/qemu-iotests/244 | 10 ++++++++--
19
tests/qemu-iotests/244.out | 9 ++++++---
20
2 files changed, 14 insertions(+), 5 deletions(-)
21
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
52
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/244.out
54
+++ b/tests/qemu-iotests/244.out
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
57
read 1048576/1048576 bytes at offset 1048576
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
59
-read 2097152/2097152 bytes at offset 2097152
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
61
read 1048576/1048576 bytes at offset 4194304
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
63
read 1048576/1048576 bytes at offset 5242880
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
65
read 4194304/4194304 bytes at offset 2097152
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
67
68
-Images are identical.
69
+read 1048576/1048576 bytes at offset 0
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
71
+read 1048576/1048576 bytes at offset 1048576
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
73
+read 3145728/3145728 bytes at offset 3145728
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
qcow2 file size after I/O: 327680
76
77
=== bdrv_co_block_status test for file and offset=0 ===
78
--
79
2.25.3
80
81
diff view generated by jsdifflib
1
Now that node level interface bdrv_truncate() supports passing request
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
flags to the block driver, expose this on the BlockBackend level, too.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
No reason to forbid them, and they are needed to improve performance
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
with compress-threads in further patches.
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
8
---
11
include/sysemu/block-backend.h | 2 +-
9
qemu-img.c | 5 -----
12
block.c | 3 ++-
10
1 file changed, 5 deletions(-)
13
block/block-backend.c | 4 ++--
14
block/commit.c | 4 ++--
15
block/crypto.c | 2 +-
16
block/mirror.c | 2 +-
17
block/qcow2.c | 4 ++--
18
block/qed.c | 2 +-
19
block/vdi.c | 2 +-
20
block/vhdx.c | 4 ++--
21
block/vmdk.c | 6 +++---
22
block/vpc.c | 2 +-
23
blockdev.c | 2 +-
24
qemu-img.c | 2 +-
25
qemu-io-cmds.c | 2 +-
26
15 files changed, 22 insertions(+), 21 deletions(-)
27
11
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
34
int bytes);
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
36
- PreallocMode prealloc, Error **errp);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
40
int64_t pos, int size);
41
diff --git a/block.c b/block.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block.c
44
+++ b/block.c
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
46
int64_t size;
47
int ret;
48
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
51
+ &local_err);
52
if (ret < 0 && ret != -ENOTSUP) {
53
error_propagate(errp, local_err);
54
return ret;
55
diff --git a/block/block-backend.c b/block/block-backend.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/block-backend.c
58
+++ b/block/block-backend.c
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
60
}
61
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
63
- PreallocMode prealloc, Error **errp)
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
65
{
66
if (!blk_is_available(blk)) {
67
error_setg(errp, "No medium inserted");
68
return -ENOMEDIUM;
69
}
70
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
73
}
74
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
76
diff --git a/block/commit.c b/block/commit.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block/commit.c
79
+++ b/block/commit.c
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
}
82
83
if (base_len < len) {
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
86
if (ret) {
87
goto out;
88
}
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
90
* grow the backing file image if possible. If not possible,
91
* we must return an error */
92
if (length > backing_length) {
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
95
&local_err);
96
if (ret < 0) {
97
error_report_err(local_err);
98
diff --git a/block/crypto.c b/block/crypto.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/crypto.c
101
+++ b/block/crypto.c
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
103
* which will be used by the crypto header
104
*/
105
return blk_truncate(data->blk, data->size + headerlen, false,
106
- data->prealloc, errp);
107
+ data->prealloc, 0, errp);
108
}
109
110
111
diff --git a/block/mirror.c b/block/mirror.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/mirror.c
114
+++ b/block/mirror.c
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
116
117
if (s->bdev_length > base_length) {
118
ret = blk_truncate(s->target, s->bdev_length, false,
119
- PREALLOC_MODE_OFF, NULL);
120
+ PREALLOC_MODE_OFF, 0, NULL);
121
if (ret < 0) {
122
goto immediate_exit;
123
}
124
diff --git a/block/qcow2.c b/block/qcow2.c
125
index XXXXXXX..XXXXXXX 100644
126
--- a/block/qcow2.c
127
+++ b/block/qcow2.c
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
129
130
/* Okay, now that we have a valid image, let's give it the right size */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
132
- errp);
133
+ 0, errp);
134
if (ret < 0) {
135
error_prepend(errp, "Could not resize image: ");
136
goto out;
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
138
* Amending image options should ensure that the image has
139
* exactly the given new values, so pass exact=true here.
140
*/
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
143
blk_unref(blk);
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) {
157
goto out;
158
}
159
diff --git a/block/vdi.c b/block/vdi.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/vdi.c
162
+++ b/block/vdi.c
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
164
165
if (image_type == VDI_TYPE_STATIC) {
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
167
- PREALLOC_MODE_OFF, errp);
168
+ PREALLOC_MODE_OFF, 0, errp);
169
if (ret < 0) {
170
error_prepend(errp, "Failed to statically allocate file");
171
goto exit;
172
diff --git a/block/vhdx.c b/block/vhdx.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/block/vhdx.c
175
+++ b/block/vhdx.c
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
177
/* All zeroes, so we can just extend the file - the end of the BAT
178
* is the furthest thing we have written yet */
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
180
- errp);
181
+ 0, errp);
182
if (ret < 0) {
183
goto exit;
184
}
185
} else if (type == VHDX_TYPE_FIXED) {
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
187
- PREALLOC_MODE_OFF, errp);
188
+ PREALLOC_MODE_OFF, 0, errp);
189
if (ret < 0) {
190
goto exit;
191
}
192
diff --git a/block/vmdk.c b/block/vmdk.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/vmdk.c
195
+++ b/block/vmdk.c
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
197
int gd_buf_size;
198
199
if (flat) {
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
202
goto exit;
203
}
204
magic = cpu_to_be32(VMDK4_MAGIC);
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
206
}
207
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
209
- PREALLOC_MODE_OFF, errp);
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
12
diff --git a/qemu-img.c b/qemu-img.c
250
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
14
--- a/qemu-img.c
252
+++ b/qemu-img.c
15
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
16
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
17
goto fail_getopt;
255
* success when the image has not actually been resized.
18
}
256
*/
19
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
20
- if (!s.wr_in_order && s.compressed) {
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
21
- error_report("Out of order write and compress are mutually exclusive");
259
if (!ret) {
22
- goto fail_getopt;
260
qprintf(quiet, "Image resized.\n");
23
- }
261
} else {
24
-
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
25
if (tgt_image_opts && !skip_create) {
263
index XXXXXXX..XXXXXXX 100644
26
error_report("--target-image-opts requires use of -n flag");
264
--- a/qemu-io-cmds.c
27
goto fail_getopt;
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;
275
--
28
--
276
2.25.3
29
2.13.6
277
30
278
31
diff view generated by jsdifflib
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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.
6
2
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
3
Make a separate function for compression to be parallelized later.
8
and if the protocol driver can ensure that the new area reads as zeros,
4
- use .avail_out field instead of .next_out to calculate size of
9
we can skip setting the zero flag in the qcow2 layer.
5
compressed data. It looks more natural and it allows to keep dest to
6
be void pointer
7
- set avail_out to be at least one byte less than input, to be sure
8
avoid inefficient compression earlier
10
9
11
Unfortunately, the same approach doesn't work for metadata
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
preallocation, so we'll still set the zero flag there.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
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>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
12
---
20
block/qcow2.c | 22 +++++++++++++++++++---
13
block/qcow2.c | 78 ++++++++++++++++++++++++++++++++++++++---------------------
21
tests/qemu-iotests/274.out | 4 ++--
14
1 file changed, 51 insertions(+), 27 deletions(-)
22
2 files changed, 21 insertions(+), 5 deletions(-)
23
15
24
diff --git a/block/qcow2.c b/block/qcow2.c
16
diff --git a/block/qcow2.c b/block/qcow2.c
25
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2.c
18
--- a/block/qcow2.c
27
+++ b/block/qcow2.c
19
+++ b/block/qcow2.c
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
20
@@ -XXX,XX +XXX,XX @@
29
/* Allocate the data area */
21
*/
30
new_file_size = allocation_start +
22
31
nb_new_data_clusters * s->cluster_size;
23
#include "qemu/osdep.h"
32
- /* Image file grows, so @exact does not matter */
24
+
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
25
+#define ZLIB_CONST
34
- errp);
26
+#include <zlib.h>
35
+ /*
27
+
36
+ * Image file grows, so @exact does not matter.
28
#include "block/block_int.h"
37
+ *
29
#include "block/qdict.h"
38
+ * If we need to zero out the new area, try first whether the protocol
30
#include "sysemu/block-backend.h"
39
+ * driver can already take care of this.
31
#include "qemu/module.h"
40
+ */
32
-#include <zlib.h>
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
33
#include "qcow2.h"
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
34
#include "qemu/error-report.h"
43
+ BDRV_REQ_ZERO_WRITE, NULL);
35
#include "qapi/error.h"
44
+ if (ret >= 0) {
36
@@ -XXX,XX +XXX,XX @@ fail:
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
37
return ret;
46
+ }
38
}
47
+ } else {
39
48
+ ret = -1;
40
+/*
49
+ }
41
+ * qcow2_compress()
50
+ if (ret < 0) {
42
+ *
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
43
+ * @dest - destination buffer, at least of @size-1 bytes
52
+ errp);
44
+ * @src - source buffer, @size bytes
53
+ }
45
+ *
46
+ * Returns: compressed size on success
47
+ * -1 if compression is inefficient
48
+ * -2 on any other error
49
+ */
50
+static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
51
+{
52
+ ssize_t ret;
53
+ z_stream strm;
54
+
55
+ /* best compression, small window, no zlib header */
56
+ memset(&strm, 0, sizeof(strm));
57
+ ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
58
+ -12, 9, Z_DEFAULT_STRATEGY);
59
+ if (ret != 0) {
60
+ return -2;
61
+ }
62
+
63
+ /* strm.next_in is not const in old zlib versions, such as those used on
64
+ * OpenBSD/NetBSD, so cast the const away */
65
+ strm.avail_in = size;
66
+ strm.next_in = (void *) src;
67
+ strm.avail_out = size - 1;
68
+ strm.next_out = dest;
69
+
70
+ ret = deflate(&strm, Z_FINISH);
71
+ if (ret == Z_STREAM_END) {
72
+ ret = size - 1 - strm.avail_out;
73
+ } else {
74
+ ret = (ret == Z_OK ? -1 : -2);
75
+ }
76
+
77
+ deflateEnd(&strm);
78
+
79
+ return ret;
80
+}
81
+
82
/* XXX: put compressed sectors first, then all the cluster aligned
83
tables to avoid losing bytes in alignment */
84
static coroutine_fn int
85
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
86
BDRVQcow2State *s = bs->opaque;
87
QEMUIOVector hd_qiov;
88
struct iovec iov;
89
- z_stream strm;
90
- int ret, out_len;
91
+ int ret;
92
+ size_t out_len;
93
uint8_t *buf, *out_buf;
94
int64_t cluster_offset;
95
96
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
97
98
out_buf = g_malloc(s->cluster_size);
99
100
- /* best compression, small window, no zlib header */
101
- memset(&strm, 0, sizeof(strm));
102
- ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
103
- Z_DEFLATED, -12,
104
- 9, Z_DEFAULT_STRATEGY);
105
- if (ret != 0) {
106
+ out_len = qcow2_compress(out_buf, buf, s->cluster_size);
107
+ if (out_len == -2) {
108
ret = -EINVAL;
109
goto fail;
110
- }
111
-
112
- strm.avail_in = s->cluster_size;
113
- strm.next_in = (uint8_t *)buf;
114
- strm.avail_out = s->cluster_size;
115
- strm.next_out = out_buf;
116
-
117
- ret = deflate(&strm, Z_FINISH);
118
- if (ret != Z_STREAM_END && ret != Z_OK) {
119
- deflateEnd(&strm);
120
- ret = -EINVAL;
121
- goto fail;
122
- }
123
- out_len = strm.next_out - out_buf;
124
-
125
- deflateEnd(&strm);
126
-
127
- if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
128
+ } else if (out_len == -1) {
129
/* could not compress: write normal cluster */
130
ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0);
54
if (ret < 0) {
131
if (ret < 0) {
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
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/274.out
60
+++ b/tests/qemu-iotests/274.out
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
63
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
67
68
=== preallocation=full ===
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
79
--
132
--
80
2.25.3
133
2.13.6
81
134
82
135
diff view generated by jsdifflib
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
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.
6
2
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Do data compression in separate threads. This significantly improve
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
4
performance for qemu-img convert with -W (allow async writes) and -c
9
Reviewed-by: Eric Blake <eblake@redhat.com>
5
(compressed) options.
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
9
---
13
block/qcow2-cluster.c | 2 +-
10
block/qcow2.h | 3 +++
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
11
block/qcow2.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
15
2 files changed, 35 insertions(+), 1 deletion(-)
12
2 files changed, 64 insertions(+), 1 deletion(-)
16
13
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
14
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
16
--- a/block/qcow2.h
20
+++ b/block/qcow2-cluster.c
17
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
18
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
22
/* Caller must pass aligned values, except at image end */
19
* override) */
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
20
char *image_backing_file;
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
21
char *image_backing_format;
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
22
+
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
23
+ CoQueue compress_wait_queue;
27
24
+ int nb_compress_threads;
28
/* The zero flag is only supported by version 3 and newer */
25
} BDRVQcow2State;
29
if (s->qcow_version < 3) {
26
27
typedef struct Qcow2COWRegion {
30
diff --git a/block/qcow2.c b/block/qcow2.c
28
diff --git a/block/qcow2.c b/block/qcow2.c
31
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2.c
30
--- a/block/qcow2.c
33
+++ b/block/qcow2.c
31
+++ b/block/qcow2.c
32
@@ -XXX,XX +XXX,XX @@
33
#include "qapi/qobject-input-visitor.h"
34
#include "qapi/qapi-visit-block-core.h"
35
#include "crypto.h"
36
+#include "block/thread-pool.h"
37
38
/*
39
Differences with QCOW:
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
40
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
35
41
qcow2_check_refcounts(bs, &result, 0);
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
}
42
}
45
43
#endif
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
48
+
44
+
49
+ /*
45
+ qemu_co_queue_init(&s->compress_wait_queue);
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
52
+ * at the end of the image (which it is here).
53
+ */
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
55
+ if (ret < 0) {
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
57
+ goto fail;
58
+ }
59
+
46
+
60
+ /* Write explicit zeros for the unaligned head */
47
return ret;
61
+ if (zero_start > old_length) {
48
62
+ uint64_t len = zero_start - old_length;
49
fail:
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
50
@@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
64
+ QEMUIOVector qiov;
51
return ret;
65
+ qemu_iovec_init_buf(&qiov, buf, len);
52
}
53
54
+#define MAX_COMPRESS_THREADS 4
66
+
55
+
67
+ qemu_co_mutex_unlock(&s->lock);
56
+typedef struct Qcow2CompressData {
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
57
+ void *dest;
69
+ qemu_co_mutex_lock(&s->lock);
58
+ const void *src;
59
+ size_t size;
60
+ ssize_t ret;
61
+} Qcow2CompressData;
70
+
62
+
71
+ qemu_vfree(buf);
63
+static int qcow2_compress_pool_func(void *opaque)
72
+ if (ret < 0) {
64
+{
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
65
+ Qcow2CompressData *data = opaque;
74
+ goto fail;
66
+
75
+ }
67
+ data->ret = qcow2_compress(data->dest, data->src, data->size);
76
+ }
68
+
69
+ return 0;
70
+}
71
+
72
+static void qcow2_compress_complete(void *opaque, int ret)
73
+{
74
+ qemu_coroutine_enter(opaque);
75
+}
76
+
77
+/* See qcow2_compress definition for parameters description */
78
+static ssize_t qcow2_co_compress(BlockDriverState *bs,
79
+ void *dest, const void *src, size_t size)
80
+{
81
+ BDRVQcow2State *s = bs->opaque;
82
+ BlockAIOCB *acb;
83
+ ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
84
+ Qcow2CompressData arg = {
85
+ .dest = dest,
86
+ .src = src,
87
+ .size = size,
88
+ };
89
+
90
+ while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
91
+ qemu_co_queue_wait(&s->compress_wait_queue, NULL);
77
+ }
92
+ }
78
+
93
+
79
if (prealloc != PREALLOC_MODE_OFF) {
94
+ s->nb_compress_threads++;
80
/* Flush metadata before actually changing the image size */
95
+ acb = thread_pool_submit_aio(pool, qcow2_compress_pool_func, &arg,
81
ret = qcow2_write_caches(bs);
96
+ qcow2_compress_complete,
97
+ qemu_coroutine_self());
98
+
99
+ if (!acb) {
100
+ s->nb_compress_threads--;
101
+ return -EINVAL;
102
+ }
103
+ qemu_coroutine_yield();
104
+ s->nb_compress_threads--;
105
+ qemu_co_queue_next(&s->compress_wait_queue);
106
+
107
+ return arg.ret;
108
+}
109
+
110
/* XXX: put compressed sectors first, then all the cluster aligned
111
tables to avoid losing bytes in alignment */
112
static coroutine_fn int
113
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
114
115
out_buf = g_malloc(s->cluster_size);
116
117
- out_len = qcow2_compress(out_buf, buf, s->cluster_size);
118
+ out_len = qcow2_co_compress(bs, out_buf, buf, s->cluster_size);
119
if (out_len == -2) {
120
ret = -EINVAL;
121
goto fail;
82
--
122
--
83
2.25.3
123
2.13.6
84
124
85
125
diff view generated by jsdifflib
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
1
From: Ari Sundholm <ari@tuxera.com>
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
bdrv_truncate().
4
2
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
This allows using the two constants outside of block.c, which will
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
happen in a subsequent patch.
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Ari Sundholm <ari@tuxera.com>
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
8
---
12
include/block/block.h | 5 +++--
9
include/block/block.h | 7 +++++++
13
block/block-backend.c | 2 +-
10
block.c | 6 ------
14
block/crypto.c | 2 +-
11
2 files changed, 7 insertions(+), 6 deletions(-)
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(-)
26
12
27
diff --git a/include/block/block.h b/include/block/block.h
13
diff --git a/include/block/block.h b/include/block/block.h
28
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block.h
15
--- a/include/block/block.h
30
+++ b/include/block/block.h
16
+++ b/include/block/block.h
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
17
@@ -XXX,XX +XXX,XX @@ enum {
32
void bdrv_refresh_filename(BlockDriverState *bs);
18
BLK_PERM_GRAPH_MOD = 0x10,
33
19
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
20
BLK_PERM_ALL = 0x1f,
35
- PreallocMode prealloc, Error **errp);
21
+
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
22
+ DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ
37
+ Error **errp);
23
+ | BLK_PERM_WRITE
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
24
+ | BLK_PERM_WRITE_UNCHANGED
39
- PreallocMode prealloc, Error **errp);
25
+ | BLK_PERM_RESIZE,
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
26
+
41
27
+ DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH,
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
28
};
43
int64_t bdrv_getlength(BlockDriverState *bs);
29
44
diff --git a/block/block-backend.c b/block/block-backend.c
30
char *bdrv_perm_names(uint64_t perm);
31
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
46
--- a/block/block-backend.c
33
--- a/block.c
47
+++ b/block/block-backend.c
34
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
35
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
49
return -ENOMEDIUM;
36
return 0;
50
}
51
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
54
}
37
}
55
38
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
39
-#define DEFAULT_PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \
57
diff --git a/block/crypto.c b/block/crypto.c
40
- | BLK_PERM_WRITE \
58
index XXXXXXX..XXXXXXX 100644
41
- | BLK_PERM_WRITE_UNCHANGED \
59
--- a/block/crypto.c
42
- | BLK_PERM_RESIZE)
60
+++ b/block/crypto.c
43
-#define DEFAULT_PERM_UNCHANGED (BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH)
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
44
-
62
45
void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c,
63
offset += payload_offset;
46
const BdrvChildRole *role,
64
47
BlockReopenQueue *reopen_queue,
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)
70
diff --git a/block/io.c b/block/io.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/io.c
73
+++ b/block/io.c
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
75
* 'offset' bytes in length.
76
*/
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
78
- PreallocMode prealloc, Error **errp)
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
80
+ Error **errp)
81
{
82
BlockDriverState *bs = child->bs;
83
BlockDriver *drv = bs->drv;
84
BdrvTrackedRequest req;
85
- BdrvRequestFlags flags = 0;
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;
334
--
48
--
335
2.25.3
49
2.13.6
336
50
337
51
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
From: Aapo Vienamo <aapo@tuxera.com>
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
2
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
Implements a block device write logging system, similar to Linux kernel
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
device mapper dm-log-writes. The write operations that are performed
5
on a block device are logged to a file or another block device. The
6
write log format is identical to the dm-log-writes format. Currently,
7
log markers are not supported.
8
9
This functionality can be used for crash consistency and fs consistency
10
testing. By implementing it in qemu, tests utilizing write logs can be
11
be used to test non-Linux drivers and older kernels.
12
13
The driver accepts an optional parameter to set the sector size used
14
for logging. This makes the driver require all requests to be aligned
15
to this sector size and also makes offsets and sizes of writes in the
16
log metadata to be expressed in terms of this value (the log format has
17
a granularity of one sector for offsets and sizes). This allows
18
accurate logging of writes to guest block devices that have unusual
19
sector sizes.
20
21
The implementation is based on the blkverify and blkdebug block
22
drivers.
23
24
Signed-off-by: Aapo Vienamo <aapo@tuxera.com>
25
Signed-off-by: Ari Sundholm <ari@tuxera.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
27
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
28
qapi/block-core.json | 33 +++-
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
29
block/blklogwrites.c | 414 +++++++++++++++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/group | 1 +
30
MAINTAINERS | 6 +
10
3 files changed, 424 insertions(+)
31
block/Makefile.objs | 1 +
11
create mode 100755 tests/qemu-iotests/274
32
4 files changed, 448 insertions(+), 6 deletions(-)
12
create mode 100644 tests/qemu-iotests/274.out
33
create mode 100644 block/blklogwrites.c
13
34
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
35
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
new file mode 100755
36
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX
37
--- a/qapi/block-core.json
17
--- /dev/null
38
+++ b/qapi/block-core.json
18
+++ b/tests/qemu-iotests/274
19
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python3
40
# @throttle: Since 2.11
41
# @nvme: Since 2.12
42
# @copy-on-read: Since 3.0
43
+# @blklogwrites: Since 3.0
44
#
45
# Since: 2.9
46
##
47
{ 'enum': 'BlockdevDriver',
48
- 'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop', 'copy-on-read',
49
- 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
50
- 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
51
- 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', 'qcow2', 'qed',
52
- 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
53
- 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
54
+ 'data': [ 'blkdebug', 'blklogwrites', 'blkverify', 'bochs', 'cloop',
55
+ 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
56
+ 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
57
+ 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
58
+ 'qcow2', 'qed', 'quorum', 'raw', 'rbd', 'replication', 'sheepdog',
59
+ 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
60
61
##
62
# @BlockdevOptionsFile:
63
@@ -XXX,XX +XXX,XX @@
64
'*set-state': ['BlkdebugSetStateOptions'] } }
65
66
##
67
+# @BlockdevOptionsBlklogwrites:
21
+#
68
+#
22
+# Copyright (C) 2019 Red Hat, Inc.
69
+# Driver specific block device options for blklogwrites.
23
+#
70
+#
24
+# This program is free software; you can redistribute it and/or modify
71
+# @file: block device
25
+# it under the terms of the GNU General Public License as published by
26
+# the Free Software Foundation; either version 2 of the License, or
27
+# (at your option) any later version.
28
+#
72
+#
29
+# This program is distributed in the hope that it will be useful,
73
+# @log: block device used to log writes to @file
30
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
31
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
+# GNU General Public License for more details.
33
+#
74
+#
34
+# You should have received a copy of the GNU General Public License
75
+# @log-sector-size: sector size used in logging writes to @file, determines
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
76
+# granularity of offsets and sizes of writes (default: 512)
36
+#
77
+#
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
78
+# Since: 3.0
38
+#
79
+##
39
+# Some tests for short backing files and short overlays
80
+{ 'struct': 'BlockdevOptionsBlklogwrites',
40
+
81
+ 'data': { 'file': 'BlockdevRef',
41
+import iotests
82
+ 'log': 'BlockdevRef',
42
+
83
+ '*log-sector-size': 'uint32' } }
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
84
+
44
+iotests.verify_platform(['linux'])
85
+##
45
+
86
# @BlockdevOptionsBlkverify:
46
+size_short = 1 * 1024 * 1024
87
#
47
+size_long = 2 * 1024 * 1024
88
# Driver specific block device options for blkverify.
48
+size_diff = size_long - size_short
89
@@ -XXX,XX +XXX,XX @@
49
+
90
'discriminator': 'driver',
50
+def create_chain() -> None:
91
'data': {
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
92
'blkdebug': 'BlockdevOptionsBlkdebug',
52
+ str(size_long))
93
+ 'blklogwrites':'BlockdevOptionsBlklogwrites',
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
94
'blkverify': 'BlockdevOptionsBlkverify',
54
+ str(size_short))
95
'bochs': 'BlockdevOptionsGenericFormat',
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
96
'cloop': 'BlockdevOptionsGenericFormat',
56
+ str(size_long))
97
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
57
+
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
59
+
60
+def create_vm() -> iotests.VM:
61
+ vm = iotests.VM()
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
66
+ % iotests.imgfmt)
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
68
+ return vm
69
+
70
+with iotests.FilePath('base') as base, \
71
+ iotests.FilePath('mid') as mid, \
72
+ iotests.FilePath('top') as top:
73
+
74
+ iotests.log('== Commit tests ==')
75
+
76
+ create_chain()
77
+
78
+ iotests.log('=== Check visible data ===')
79
+
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
82
+
83
+ iotests.log('=== Checking allocation status ===')
84
+
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
87
+ base)
88
+
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
91
+ mid)
92
+
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
95
+ top)
96
+
97
+ iotests.log('=== Checking map ===')
98
+
99
+ iotests.qemu_img_log('map', '--output=json', base)
100
+ iotests.qemu_img_log('map', '--output=human', base)
101
+ iotests.qemu_img_log('map', '--output=json', mid)
102
+ iotests.qemu_img_log('map', '--output=human', mid)
103
+ iotests.qemu_img_log('map', '--output=json', top)
104
+ iotests.qemu_img_log('map', '--output=human', top)
105
+
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
107
+
108
+ iotests.qemu_img_log('commit', top)
109
+ iotests.img_info_log(mid)
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
112
+
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
114
+
115
+ create_chain()
116
+ with create_vm() as vm:
117
+ vm.launch()
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
119
+
120
+ iotests.img_info_log(mid)
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
123
+
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
125
+
126
+ create_chain()
127
+ with create_vm() as vm:
128
+ vm.launch()
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
130
+ job_id='job0', auto_dismiss=False)
131
+ vm.run_job('job0', wait=5)
132
+
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
176
new file mode 100644
98
new file mode 100644
177
index XXXXXXX..XXXXXXX
99
index XXXXXXX..XXXXXXX
178
--- /dev/null
100
--- /dev/null
179
+++ b/tests/qemu-iotests/274.out
101
+++ b/block/blklogwrites.c
180
@@ -XXX,XX +XXX,XX @@
102
@@ -XXX,XX +XXX,XX @@
181
+== Commit tests ==
103
+/*
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
104
+ * Write logging blk driver based on blkverify and blkdebug.
183
+
105
+ *
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
106
+ * Copyright (c) 2017 Tuomas Tynkkynen <tuomas@tuxera.com>
185
+
107
+ * Copyright (c) 2018 Aapo Vienamo <aapo@tuxera.com>
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
108
+ * Copyright (c) 2018 Ari Sundholm <ari@tuxera.com>
187
+
109
+ *
188
+wrote 2097152/2097152 bytes at offset 0
110
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
111
+ * See the COPYING file in the top-level directory.
190
+
112
+ */
191
+=== Check visible data ===
113
+
192
+read 1048576/1048576 bytes at offset 0
114
+#include "qemu/osdep.h"
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
115
+#include "qapi/error.h"
194
+
116
+#include "qemu/sockets.h" /* for EINPROGRESS on Windows */
195
+read 1048576/1048576 bytes at offset 1048576
117
+#include "block/block_int.h"
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
118
+#include "qapi/qmp/qdict.h"
197
+
119
+#include "qapi/qmp/qstring.h"
198
+=== Checking allocation status ===
120
+#include "qemu/cutils.h"
199
+1048576/1048576 bytes allocated at offset 0 bytes
121
+#include "qemu/option.h"
200
+1048576/1048576 bytes allocated at offset 1 MiB
122
+
201
+
123
+/* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */
202
+0/1048576 bytes allocated at offset 0 bytes
124
+
203
+0/0 bytes allocated at offset 1 MiB
125
+#define LOG_FLUSH_FLAG (1 << 0)
204
+
126
+#define LOG_FUA_FLAG (1 << 1)
205
+0/1048576 bytes allocated at offset 0 bytes
127
+#define LOG_DISCARD_FLAG (1 << 2)
206
+0/1048576 bytes allocated at offset 1 MiB
128
+#define LOG_MARK_FLAG (1 << 3)
207
+
129
+
208
+=== Checking map ===
130
+#define WRITE_LOG_VERSION 1ULL
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
131
+#define WRITE_LOG_MAGIC 0x6a736677736872ULL
210
+
132
+
211
+Offset Length Mapped to File
133
+/* All fields are little-endian. */
212
+0 0x200000 0x50000 TEST_DIR/PID-base
134
+struct log_write_super {
213
+
135
+ uint64_t magic;
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
136
+ uint64_t version;
215
+
137
+ uint64_t nr_entries;
216
+Offset Length Mapped to File
138
+ uint32_t sectorsize;
217
+0 0x100000 0x50000 TEST_DIR/PID-base
139
+} QEMU_PACKED;
218
+
140
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
141
+struct log_write_entry {
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
142
+ uint64_t sector;
221
+
143
+ uint64_t nr_sectors;
222
+Offset Length Mapped to File
144
+ uint64_t flags;
223
+0 0x100000 0x50000 TEST_DIR/PID-base
145
+ uint64_t data_len;
224
+
146
+} QEMU_PACKED;
225
+=== Testing qemu-img commit (top -> mid) ===
147
+
226
+Image committed.
148
+/* End of disk format structures. */
227
+
149
+
228
+image: TEST_IMG
150
+typedef struct {
229
+file format: IMGFMT
151
+ BdrvChild *log_file;
230
+virtual size: 2 MiB (2097152 bytes)
152
+ uint32_t sectorsize;
231
+cluster_size: 65536
153
+ uint32_t sectorbits;
232
+backing file: TEST_DIR/PID-base
154
+ uint64_t cur_log_sector;
233
+Format specific information:
155
+ uint64_t nr_entries;
234
+ compat: 1.1
156
+} BDRVBlkLogWritesState;
235
+ lazy refcounts: false
157
+
236
+ refcount bits: 16
158
+static QemuOptsList runtime_opts = {
237
+ corrupt: false
159
+ .name = "blklogwrites",
238
+
160
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
239
+read 1048576/1048576 bytes at offset 0
161
+ .desc = {
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
162
+ {
241
+
163
+ .name = "log-sector-size",
242
+read 1048576/1048576 bytes at offset 1048576
164
+ .type = QEMU_OPT_SIZE,
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
165
+ .help = "Log sector size",
244
+
166
+ },
245
+=== Testing HMP commit (top -> mid) ===
167
+ { /* end of list */ }
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
168
+ },
247
+
169
+};
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
170
+
249
+
171
+static inline uint32_t blk_log_writes_log2(uint32_t value)
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
172
+{
251
+
173
+ assert(value > 0);
252
+wrote 2097152/2097152 bytes at offset 0
174
+ return 31 - clz32(value);
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
175
+}
254
+
176
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
177
+static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
256
+{"return": ""}
178
+ Error **errp)
257
+image: TEST_IMG
179
+{
258
+file format: IMGFMT
180
+ BDRVBlkLogWritesState *s = bs->opaque;
259
+virtual size: 2 MiB (2097152 bytes)
181
+ QemuOpts *opts;
260
+cluster_size: 65536
182
+ Error *local_err = NULL;
261
+backing file: TEST_DIR/PID-base
183
+ int ret;
262
+Format specific information:
184
+ int64_t log_sector_size;
263
+ compat: 1.1
185
+
264
+ lazy refcounts: false
186
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
265
+ refcount bits: 16
187
+ qemu_opts_absorb_qdict(opts, options, &local_err);
266
+ corrupt: false
188
+ if (local_err) {
267
+
189
+ ret = -EINVAL;
268
+read 1048576/1048576 bytes at offset 0
190
+ error_propagate(errp, local_err);
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
191
+ goto fail;
270
+
192
+ }
271
+read 1048576/1048576 bytes at offset 1048576
193
+
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+ /* Open the file */
273
+
195
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
274
+=== Testing QMP active commit (top -> mid) ===
196
+ &local_err);
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
197
+ if (local_err) {
276
+
198
+ ret = -EINVAL;
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
199
+ error_propagate(errp, local_err);
278
+
200
+ goto fail;
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
201
+ }
280
+
202
+
281
+wrote 2097152/2097152 bytes at offset 0
203
+ log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
204
+ BDRV_SECTOR_SIZE);
283
+
205
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
206
+ if (log_sector_size < 0 || log_sector_size > (1ull << 23) ||
285
+{"return": {}}
207
+ !is_power_of_2(log_sector_size))
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
208
+ {
287
+{"return": {}}
209
+ ret = -EINVAL;
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
210
+ error_setg(errp, "Invalid log sector size %"PRId64, log_sector_size);
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
211
+ goto fail;
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
212
+ }
291
+{"return": {}}
213
+
292
+image: TEST_IMG
214
+ s->sectorsize = log_sector_size;
293
+file format: IMGFMT
215
+ s->sectorbits = blk_log_writes_log2(log_sector_size);
294
+virtual size: 2 MiB (2097152 bytes)
216
+ s->cur_log_sector = 1;
295
+cluster_size: 65536
217
+ s->nr_entries = 0;
296
+backing file: TEST_DIR/PID-base
218
+
297
+Format specific information:
219
+ /* Open the log file */
298
+ compat: 1.1
220
+ s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
299
+ lazy refcounts: false
221
+ &local_err);
300
+ refcount bits: 16
222
+ if (local_err) {
301
+ corrupt: false
223
+ ret = -EINVAL;
302
+
224
+ error_propagate(errp, local_err);
303
+read 1048576/1048576 bytes at offset 0
225
+ goto fail;
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
226
+ }
305
+
227
+
306
+read 1048576/1048576 bytes at offset 1048576
228
+ ret = 0;
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
229
+fail:
308
+
230
+ if (ret < 0) {
309
+== Resize tests ==
231
+ bdrv_unref_child(bs, bs->file);
310
+=== preallocation=off ===
232
+ bs->file = NULL;
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
233
+ }
312
+
234
+ qemu_opts_del(opts);
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
235
+ return ret;
314
+
236
+}
315
+wrote 65536/65536 bytes at offset 5368709120
237
+
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
238
+static void blk_log_writes_close(BlockDriverState *bs)
317
+
239
+{
318
+Image resized.
240
+ BDRVBlkLogWritesState *s = bs->opaque;
319
+
241
+
320
+read 65536/65536 bytes at offset 5368709120
242
+ bdrv_unref_child(bs, s->log_file);
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
243
+ s->log_file = NULL;
322
+
244
+}
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
245
+
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
246
+static int64_t blk_log_writes_getlength(BlockDriverState *bs)
325
+
247
+{
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
248
+ return bdrv_getlength(bs->file->bs);
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
249
+}
328
+
250
+
329
+=== preallocation=metadata ===
251
+static void blk_log_writes_refresh_filename(BlockDriverState *bs,
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
252
+ QDict *options)
331
+
253
+{
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
254
+ BDRVBlkLogWritesState *s = bs->opaque;
333
+
255
+
334
+wrote 65536/65536 bytes at offset 33285996544
256
+ /* bs->file->bs has already been refreshed */
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
257
+ bdrv_refresh_filename(s->log_file->bs);
336
+
258
+
337
+Image resized.
259
+ if (bs->file->bs->full_open_options
338
+
260
+ && s->log_file->bs->full_open_options)
339
+read 65536/65536 bytes at offset 33285996544
261
+ {
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
262
+ QDict *opts = qdict_new();
341
+
263
+ qdict_put_str(opts, "driver", "blklogwrites");
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
264
+
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
265
+ qobject_ref(bs->file->bs->full_open_options);
344
+
266
+ qdict_put_obj(opts, "file", QOBJECT(bs->file->bs->full_open_options));
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
267
+ qobject_ref(s->log_file->bs->full_open_options);
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
268
+ qdict_put_obj(opts, "log",
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
269
+ QOBJECT(s->log_file->bs->full_open_options));
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
270
+ qdict_put_int(opts, "log-sector-size", s->sectorsize);
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
271
+
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
272
+ bs->full_open_options = opts;
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
273
+ }
352
+
274
+}
353
+=== preallocation=falloc ===
275
+
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
355
+
277
+ const BdrvChildRole *role,
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
278
+ BlockReopenQueue *ro_q,
357
+
279
+ uint64_t perm, uint64_t shrd,
358
+wrote 65536/65536 bytes at offset 9437184
280
+ uint64_t *nperm, uint64_t *nshrd)
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
281
+{
360
+
282
+ if (!c) {
361
+Image resized.
283
+ *nperm = perm & DEFAULT_PERM_PASSTHROUGH;
362
+
284
+ *nshrd = (shrd & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
363
+read 65536/65536 bytes at offset 9437184
285
+ return;
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
286
+ }
365
+
287
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
288
+ if (!strcmp(c->name, "log")) {
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
289
+ bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
368
+
290
+ } else {
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
291
+ bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
292
+ }
371
+
293
+}
372
+=== preallocation=full ===
294
+
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
295
+static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
374
+
296
+{
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
297
+ BDRVBlkLogWritesState *s = bs->opaque;
376
+
298
+ bs->bl.request_alignment = s->sectorsize;
377
+wrote 65536/65536 bytes at offset 11534336
299
+}
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
300
+
379
+
301
+static int coroutine_fn
380
+Image resized.
302
+blk_log_writes_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
381
+
303
+ QEMUIOVector *qiov, int flags)
382
+read 65536/65536 bytes at offset 11534336
304
+{
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
384
+
306
+}
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
307
+
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
308
+typedef struct BlkLogWritesFileReq {
387
+
309
+ BlockDriverState *bs;
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
310
+ uint64_t offset;
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
311
+ uint64_t bytes;
390
+
312
+ int file_flags;
391
+=== preallocation=off ===
313
+ QEMUIOVector *qiov;
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+ int (*func)(struct BlkLogWritesFileReq *r);
393
+
315
+ int file_ret;
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
316
+} BlkLogWritesFileReq;
395
+
317
+
396
+wrote 65536/65536 bytes at offset 259072
318
+typedef struct {
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
319
+ BlockDriverState *bs;
398
+
320
+ QEMUIOVector *qiov;
399
+Image resized.
321
+ struct log_write_entry entry;
400
+
322
+ uint64_t zero_size;
401
+read 65536/65536 bytes at offset 259072
323
+ int log_ret;
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
324
+} BlkLogWritesLogReq;
403
+
325
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
326
+static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
327
+{
406
+
328
+ BDRVBlkLogWritesState *s = lr->bs->opaque;
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
329
+ uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits;
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
330
+
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
331
+ s->nr_entries++;
410
+
332
+ s->cur_log_sector +=
411
+=== preallocation=off ===
333
+ ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits;
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
334
+
413
+
335
+ lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size,
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
336
+ lr->qiov, 0);
415
+
337
+
416
+wrote 65536/65536 bytes at offset 344064
338
+ /* Logging for the "write zeroes" operation */
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
339
+ if (lr->log_ret == 0 && lr->zero_size) {
418
+
340
+ cur_log_offset = s->cur_log_sector << s->sectorbits;
419
+Image resized.
341
+ s->cur_log_sector +=
420
+
342
+ ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits;
421
+read 65536/65536 bytes at offset 344064
343
+
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
344
+ lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset,
423
+
345
+ lr->zero_size, 0);
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
346
+ }
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
347
+
426
+
348
+ /* Update super block on flush */
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
349
+ if (lr->log_ret == 0 && lr->entry.flags & LOG_FLUSH_FLAG) {
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
350
+ struct log_write_super super = {
429
+
351
+ .magic = cpu_to_le64(WRITE_LOG_MAGIC),
430
+=== preallocation=off ===
352
+ .version = cpu_to_le64(WRITE_LOG_VERSION),
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
353
+ .nr_entries = cpu_to_le64(s->nr_entries),
432
+
354
+ .sectorsize = cpu_to_le32(s->sectorsize),
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
355
+ };
434
+
356
+ void *zeroes = g_malloc0(s->sectorsize - sizeof(super));
435
+wrote 65536/65536 bytes at offset 446464
357
+ QEMUIOVector qiov;
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
358
+
437
+
359
+ qemu_iovec_init(&qiov, 2);
438
+Image resized.
360
+ qemu_iovec_add(&qiov, &super, sizeof(super));
439
+
361
+ qemu_iovec_add(&qiov, zeroes, s->sectorsize - sizeof(super));
440
+read 65536/65536 bytes at offset 446464
362
+
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
363
+ lr->log_ret =
442
+
364
+ bdrv_co_pwritev(s->log_file, 0, s->sectorsize, &qiov, 0);
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
365
+ if (lr->log_ret == 0) {
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
366
+ lr->log_ret = bdrv_co_flush(s->log_file->bs);
445
+
367
+ }
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
368
+ qemu_iovec_destroy(&qiov);
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
369
+ g_free(zeroes);
448
+
370
+ }
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
371
+}
372
+
373
+static void coroutine_fn blk_log_writes_co_do_file(BlkLogWritesFileReq *fr)
374
+{
375
+ fr->file_ret = fr->func(fr);
376
+}
377
+
378
+static int coroutine_fn
379
+blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
380
+ QEMUIOVector *qiov, int flags,
381
+ int (*file_func)(BlkLogWritesFileReq *r),
382
+ uint64_t entry_flags, bool is_zero_write)
383
+{
384
+ QEMUIOVector log_qiov;
385
+ size_t niov = qiov ? qiov->niov : 0;
386
+ BDRVBlkLogWritesState *s = bs->opaque;
387
+ BlkLogWritesFileReq fr = {
388
+ .bs = bs,
389
+ .offset = offset,
390
+ .bytes = bytes,
391
+ .file_flags = flags,
392
+ .qiov = qiov,
393
+ .func = file_func,
394
+ };
395
+ BlkLogWritesLogReq lr = {
396
+ .bs = bs,
397
+ .qiov = &log_qiov,
398
+ .entry = {
399
+ .sector = cpu_to_le64(offset >> s->sectorbits),
400
+ .nr_sectors = cpu_to_le64(bytes >> s->sectorbits),
401
+ .flags = cpu_to_le64(entry_flags),
402
+ .data_len = 0,
403
+ },
404
+ .zero_size = is_zero_write ? bytes : 0,
405
+ };
406
+ void *zeroes = g_malloc0(s->sectorsize - sizeof(lr.entry));
407
+
408
+ assert((1 << s->sectorbits) == s->sectorsize);
409
+ assert(bs->bl.request_alignment == s->sectorsize);
410
+ assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
411
+ assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
412
+
413
+ qemu_iovec_init(&log_qiov, niov + 2);
414
+ qemu_iovec_add(&log_qiov, &lr.entry, sizeof(lr.entry));
415
+ qemu_iovec_add(&log_qiov, zeroes, s->sectorsize - sizeof(lr.entry));
416
+ if (qiov) {
417
+ qemu_iovec_concat(&log_qiov, qiov, 0, qiov->size);
418
+ }
419
+
420
+ blk_log_writes_co_do_file(&fr);
421
+ blk_log_writes_co_do_log(&lr);
422
+
423
+ qemu_iovec_destroy(&log_qiov);
424
+ g_free(zeroes);
425
+
426
+ if (lr.log_ret < 0) {
427
+ return lr.log_ret;
428
+ }
429
+
430
+ return fr.file_ret;
431
+}
432
+
433
+static int coroutine_fn
434
+blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr)
435
+{
436
+ return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes,
437
+ fr->qiov, fr->file_flags);
438
+}
439
+
440
+static int coroutine_fn
441
+blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr)
442
+{
443
+ return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes,
444
+ fr->file_flags);
445
+}
446
+
447
+static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
448
+{
449
+ return bdrv_co_flush(fr->bs->file->bs);
450
+}
451
+
452
+static int coroutine_fn
453
+blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
454
+{
455
+ return bdrv_co_pdiscard(fr->bs->file->bs, fr->offset, fr->bytes);
456
+}
457
+
458
+static int coroutine_fn
459
+blk_log_writes_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
460
+ QEMUIOVector *qiov, int flags)
461
+{
462
+ return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
463
+ blk_log_writes_co_do_file_pwritev, 0, false);
464
+}
465
+
466
+static int coroutine_fn
467
+blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
468
+ BdrvRequestFlags flags)
469
+{
470
+ return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
471
+ blk_log_writes_co_do_file_pwrite_zeroes, 0,
472
+ true);
473
+}
474
+
475
+static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
476
+{
477
+ return blk_log_writes_co_log(bs, 0, 0, NULL, 0,
478
+ blk_log_writes_co_do_file_flush,
479
+ LOG_FLUSH_FLAG, false);
480
+}
481
+
482
+static int coroutine_fn
483
+blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
484
+{
485
+ return blk_log_writes_co_log(bs, offset, count, NULL, 0,
486
+ blk_log_writes_co_do_file_pdiscard,
487
+ LOG_DISCARD_FLAG, false);
488
+}
489
+
490
+static BlockDriver bdrv_blk_log_writes = {
491
+ .format_name = "blklogwrites",
492
+ .instance_size = sizeof(BDRVBlkLogWritesState),
493
+
494
+ .bdrv_open = blk_log_writes_open,
495
+ .bdrv_close = blk_log_writes_close,
496
+ .bdrv_getlength = blk_log_writes_getlength,
497
+ .bdrv_refresh_filename = blk_log_writes_refresh_filename,
498
+ .bdrv_child_perm = blk_log_writes_child_perm,
499
+ .bdrv_refresh_limits = blk_log_writes_refresh_limits,
500
+
501
+ .bdrv_co_preadv = blk_log_writes_co_preadv,
502
+ .bdrv_co_pwritev = blk_log_writes_co_pwritev,
503
+ .bdrv_co_pwrite_zeroes = blk_log_writes_co_pwrite_zeroes,
504
+ .bdrv_co_flush_to_disk = blk_log_writes_co_flush_to_disk,
505
+ .bdrv_co_pdiscard = blk_log_writes_co_pdiscard,
506
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
507
+
508
+ .is_filter = true,
509
+};
510
+
511
+static void bdrv_blk_log_writes_init(void)
512
+{
513
+ bdrv_register(&bdrv_blk_log_writes);
514
+}
515
+
516
+block_init(bdrv_blk_log_writes_init);
517
diff --git a/MAINTAINERS b/MAINTAINERS
450
index XXXXXXX..XXXXXXX 100644
518
index XXXXXXX..XXXXXXX 100644
451
--- a/tests/qemu-iotests/group
519
--- a/MAINTAINERS
452
+++ b/tests/qemu-iotests/group
520
+++ b/MAINTAINERS
453
@@ -XXX,XX +XXX,XX @@
521
@@ -XXX,XX +XXX,XX @@ S: Supported
454
270 rw backing quick
522
F: block/quorum.c
455
272 rw
523
L: qemu-block@nongnu.org
456
273 backing quick
524
457
+274 rw backing
525
+blklogwrites
458
277 rw quick
526
+M: Ari Sundholm <ari@tuxera.com>
459
279 rw backing quick
527
+L: qemu-block@nongnu.org
460
280 rw migration quick
528
+S: Supported
529
+F: block/blklogwrites.c
530
+
531
blkverify
532
M: Stefan Hajnoczi <stefanha@redhat.com>
533
L: qemu-block@nongnu.org
534
diff --git a/block/Makefile.objs b/block/Makefile.objs
535
index XXXXXXX..XXXXXXX 100644
536
--- a/block/Makefile.objs
537
+++ b/block/Makefile.objs
538
@@ -XXX,XX +XXX,XX @@ block-obj-y += qed-check.o
539
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
540
block-obj-y += quorum.o
541
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
542
+block-obj-y += blklogwrites.o
543
block-obj-y += block-backend.o snapshot.o qapi.o
544
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
545
block-obj-$(CONFIG_POSIX) += file-posix.o
461
--
546
--
462
2.25.3
547
2.13.6
463
548
464
549
diff view generated by jsdifflib
1
When extending the size of an image that has a backing file larger than
1
If the user passes a too long node name string, we silently truncate it
2
its old size, make sure that the backing file data doesn't become
2
to fit into BlockDriverState.node_name, i.e. to 31 characters. Apart
3
visible in the guest, but the added area is properly zeroed out.
3
from surprising the user when the node has a different name than
4
requested, this also bypasses the check for duplicate names, so that the
5
same name can be assigned to multiple nodes.
4
6
5
Consider the following scenario where the overlay is shorter than its
7
Fix this by just making too long node names an error.
6
backing file:
7
8
8
base.qcow2: AAAAAAAA
9
Reported-by: Peter Krempa <pkrempa@redhat.com>
9
overlay.qcow2: BBBB
10
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
14
15
A similar case happens with the various variants of a commit job when an
16
intermediate file is short (- for unallocated):
17
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>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
11
---
36
block/io.c | 25 +++++++++++++++++++++++++
12
block.c | 6 ++++++
37
1 file changed, 25 insertions(+)
13
tests/qemu-iotests/051 | 15 +++++++++++++++
14
tests/qemu-iotests/051.out | 23 +++++++++++++++++++++++
15
tests/qemu-iotests/051.pc.out | 23 +++++++++++++++++++++++
16
4 files changed, 67 insertions(+)
38
17
39
diff --git a/block/io.c b/block/io.c
18
diff --git a/block.c b/block.c
40
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
41
--- a/block/io.c
20
--- a/block.c
42
+++ b/block/io.c
21
+++ b/block.c
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
22
@@ -XXX,XX +XXX,XX @@ static void bdrv_assign_node_name(BlockDriverState *bs,
44
goto out;
23
goto out;
45
}
24
}
46
25
47
+ /*
26
+ /* Make sure that the node name isn't truncated */
48
+ * If the image has a backing file that is large enough that it would
27
+ if (strlen(node_name) >= sizeof(bs->node_name)) {
49
+ * provide data for the new area, we cannot leave it unallocated because
28
+ error_setg(errp, "Node name too long");
50
+ * then the backing file content would become visible. Instead, zero-fill
29
+ goto out;
51
+ * the new area.
52
+ *
53
+ * Note that if the image has a backing file, but was opened without the
54
+ * backing file, taking care of keeping things consistent with that backing
55
+ * file is the user's responsibility.
56
+ */
57
+ if (new_bytes && bs->backing) {
58
+ int64_t backing_len;
59
+
60
+ backing_len = bdrv_getlength(backing_bs(bs));
61
+ if (backing_len < 0) {
62
+ ret = backing_len;
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
64
+ goto out;
65
+ }
66
+
67
+ if (backing_len > old_size) {
68
+ flags |= BDRV_REQ_ZERO_WRITE;
69
+ }
70
+ }
30
+ }
71
+
31
+
72
if (drv->bdrv_co_truncate) {
32
/* copy node name into the bs and insert it into the graph list */
73
if (flags & ~bs->supported_truncate_flags) {
33
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
74
error_setg(errp, "Block driver does not support requested flags");
34
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
35
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
36
index XXXXXXX..XXXXXXX 100755
37
--- a/tests/qemu-iotests/051
38
+++ b/tests/qemu-iotests/051
39
@@ -XXX,XX +XXX,XX @@ run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2
40
run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2
41
42
echo
43
+echo === Node names ===
44
+echo
45
+
46
+# Maximum length: 31 characters
47
+run_qemu -drive file="$TEST_IMG",node-name=x123456789012345678901234567890
48
+run_qemu -drive file="$TEST_IMG",node-name=x1234567890123456789012345678901
49
+
50
+# First character must be alphabetic
51
+# Following characters alphanumeric or -._
52
+run_qemu -drive file="$TEST_IMG",node-name=All-Types.of_all0wed_chars
53
+run_qemu -drive file="$TEST_IMG",node-name=123foo
54
+run_qemu -drive file="$TEST_IMG",node-name=_foo
55
+run_qemu -drive file="$TEST_IMG",node-name=foo#12
56
+
57
+echo
58
echo === Device without drive ===
59
echo
60
61
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
62
index XXXXXXX..XXXXXXX 100644
63
--- a/tests/qemu-iotests/051.out
64
+++ b/tests/qemu-iotests/051.out
65
@@ -XXX,XX +XXX,XX @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
66
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format'
67
68
69
+=== Node names ===
70
+
71
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=x123456789012345678901234567890
72
+QEMU X.Y.Z monitor - type 'help' for more information
73
+(qemu) quit
74
+
75
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901
76
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901: Node name too long
77
+
78
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=All-Types.of_all0wed_chars
79
+QEMU X.Y.Z monitor - type 'help' for more information
80
+(qemu) quit
81
+
82
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=123foo
83
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node name
84
+
85
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=_foo
86
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node name
87
+
88
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=foo#12
89
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node name
90
+
91
+
92
=== Device without drive ===
93
94
Testing: -device VIRTIO_SCSI -device scsi-hd
95
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
96
index XXXXXXX..XXXXXXX 100644
97
--- a/tests/qemu-iotests/051.pc.out
98
+++ b/tests/qemu-iotests/051.pc.out
99
@@ -XXX,XX +XXX,XX @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
100
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format'
101
102
103
+=== Node names ===
104
+
105
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=x123456789012345678901234567890
106
+QEMU X.Y.Z monitor - type 'help' for more information
107
+(qemu) quit
108
+
109
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901
110
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901: Node name too long
111
+
112
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=All-Types.of_all0wed_chars
113
+QEMU X.Y.Z monitor - type 'help' for more information
114
+(qemu) quit
115
+
116
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=123foo
117
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node name
118
+
119
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=_foo
120
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node name
121
+
122
+Testing: -drive file=TEST_DIR/t.qcow2,node-name=foo#12
123
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node name
124
+
125
+
126
=== Device without drive ===
127
128
Testing: -device VIRTIO_SCSI -device scsi-hd
75
--
129
--
76
2.25.3
130
2.13.6
77
131
78
132
diff view generated by jsdifflib
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
1
Fixes: Coverity CID 1393782
2
driver callbacks, and a supported_truncate_flags field in
2
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
BlockDriverState that allows drivers to advertise support for request
3
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
4
flags in the context of truncate.
4
---
5
block/crypto.c | 2 +-
6
1 file changed, 1 insertion(+), 1 deletion(-)
5
7
6
For now, we always pass 0 and no drivers declare support for any flag.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
include/block/block_int.h | 10 +++++++++-
16
block/crypto.c | 3 ++-
17
block/file-posix.c | 2 +-
18
block/file-win32.c | 2 +-
19
block/gluster.c | 1 +
20
block/io.c | 8 +++++++-
21
block/iscsi.c | 2 +-
22
block/nfs.c | 3 ++-
23
block/qcow2.c | 2 +-
24
block/qed.c | 1 +
25
block/raw-format.c | 2 +-
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(-)
31
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
*/
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
39
bool exact, PreallocMode prealloc,
40
- Error **errp);
41
+ BdrvRequestFlags flags, Error **errp);
42
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
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
8
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
10
--- a/block/crypto.c
63
+++ b/block/crypto.c
11
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
12
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
65
13
/* Create protocol layer */
66
static int coroutine_fn
14
ret = bdrv_create_file(filename, opts, errp);
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
15
if (ret < 0) {
68
- PreallocMode prealloc, Error **errp)
16
- return ret;
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
17
+ goto fail;
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;
100
diff --git a/block/gluster.c b/block/gluster.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/gluster.c
103
+++ b/block/gluster.c
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
105
int64_t offset,
106
bool exact,
107
PreallocMode prealloc,
108
+ BdrvRequestFlags flags,
109
Error **errp)
110
{
111
BDRVGlusterState *s = bs->opaque;
112
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
115
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
BlockDriverState *bs = child->bs;
118
BlockDriver *drv = bs->drv;
119
BdrvTrackedRequest req;
120
+ BdrvRequestFlags flags = 0;
121
int64_t old_size, new_bytes;
122
int ret;
123
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
125
}
18
}
126
19
127
if (drv->bdrv_co_truncate) {
20
bs = bdrv_open(filename, NULL, NULL,
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
129
+ if (flags & ~bs->supported_truncate_flags) {
130
+ error_setg(errp, "Block driver does not support requested flags");
131
+ ret = -ENOTSUP;
132
+ goto out;
133
+ }
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
135
} else if (bs->file && drv->is_filter) {
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
137
} else {
138
diff --git a/block/iscsi.c b/block/iscsi.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/iscsi.c
141
+++ b/block/iscsi.c
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
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)
156
157
static int coroutine_fn
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
159
- PreallocMode prealloc, Error **errp)
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
161
+ Error **errp)
162
{
163
NFSClient *client = bs->opaque;
164
int ret;
165
diff --git a/block/qcow2.c b/block/qcow2.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/qcow2.c
168
+++ b/block/qcow2.c
169
@@ -XXX,XX +XXX,XX @@ fail:
170
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
172
bool exact, PreallocMode prealloc,
173
- Error **errp)
174
+ BdrvRequestFlags flags, Error **errp)
175
{
176
BDRVQcow2State *s = bs->opaque;
177
uint64_t old_length;
178
diff --git a/block/qed.c b/block/qed.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/qed.c
181
+++ b/block/qed.c
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
183
int64_t offset,
184
bool exact,
185
PreallocMode prealloc,
186
+ BdrvRequestFlags flags,
187
Error **errp)
188
{
189
BDRVQEDState *s = bs->opaque;
190
diff --git a/block/raw-format.c b/block/raw-format.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/raw-format.c
193
+++ b/block/raw-format.c
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
195
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
197
bool exact, PreallocMode prealloc,
198
- Error **errp)
199
+ BdrvRequestFlags flags, Error **errp)
200
{
201
BDRVRawState *s = bs->opaque;
202
203
diff --git a/block/rbd.c b/block/rbd.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/rbd.c
206
+++ b/block/rbd.c
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
208
int64_t offset,
209
bool exact,
210
PreallocMode prealloc,
211
+ BdrvRequestFlags flags,
212
Error **errp)
213
{
214
int r;
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/sheepdog.c
218
+++ b/block/sheepdog.c
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
220
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
222
bool exact, PreallocMode prealloc,
223
- Error **errp)
224
+ BdrvRequestFlags flags, Error **errp)
225
{
226
BDRVSheepdogState *s = bs->opaque;
227
int ret, fd;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
231
if (offset > s->inode.vdi_size) {
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);
234
if (ret < 0) {
235
return ret;
236
}
237
diff --git a/block/ssh.c b/block/ssh.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/ssh.c
240
+++ b/block/ssh.c
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
242
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
244
bool exact, PreallocMode prealloc,
245
- Error **errp)
246
+ BdrvRequestFlags flags, Error **errp)
247
{
248
BDRVSSHState *s = bs->opaque;
249
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/tests/test-block-iothread.c
253
+++ b/tests/test-block-iothread.c
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
255
256
static int coroutine_fn
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
258
- PreallocMode prealloc, Error **errp)
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
260
+ Error **errp)
261
{
262
return 0;
263
}
264
--
21
--
265
2.25.3
22
2.13.6
266
23
267
24
diff view generated by jsdifflib
1
After processing the option string with the keyval parser, we get a
1
From: Ari Sundholm <ari@tuxera.com>
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.
4
2
5
qmp_object_add(), however, uses the normal QObject input visitor, which
3
This was a simple oversight when working on intermediate versions
6
expects a QDict where all properties already have the QType that matches
4
of the original patch which introduced blklogwrites.
7
the data type required by the QOM object type.
8
5
9
Change the --object implementation in qemu-storage-daemon so that it
6
Signed-off-by: Ari Sundholm <ari@tuxera.com>
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
11
directly instead and pass it a new keyval boolean that decides which
12
visitor must be used.
13
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
8
---
17
include/qom/object_interfaces.h | 6 +++++-
9
block/blklogwrites.c | 8 +++-----
18
qemu-storage-daemon.c | 4 +---
10
1 file changed, 3 insertions(+), 5 deletions(-)
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
22
11
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
12
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
24
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qom/object_interfaces.h
14
--- a/block/blklogwrites.c
26
+++ b/include/qom/object_interfaces.h
15
+++ b/block/blklogwrites.c
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
16
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
28
/**
17
QemuOpts *opts;
29
* user_creatable_add_dict:
18
Error *local_err = NULL;
30
* @qdict: the object definition
19
int ret;
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
20
- int64_t log_sector_size;
32
+ * assume that all @qdict values are strings); otherwise, use
21
+ uint64_t log_sector_size;
33
+ * the normal QObject visitor (i.e. assume all @qdict values
22
34
+ * have the QType expected by the QOM object type)
23
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
35
* @errp: if an error occurs, a pointer to an area to store the error
24
qemu_opts_absorb_qdict(opts, options, &local_err);
36
*
25
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
37
* Create an instance of the user creatable object that is defined by
26
log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
27
BDRV_SECTOR_SIZE);
39
* ID from the key 'id'. The remaining entries in @qdict are used to
28
40
* initialize the object properties.
29
- if (log_sector_size < 0 || log_sector_size > (1ull << 23) ||
41
*/
30
- !is_power_of_2(log_sector_size))
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
31
- {
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
32
+ if (log_sector_size > (1ull << 23) || !is_power_of_2(log_sector_size)) {
44
33
ret = -EINVAL;
45
/**
34
- error_setg(errp, "Invalid log sector size %"PRId64, log_sector_size);
46
* user_creatable_add_opts:
35
+ error_setg(errp, "Invalid log sector size %"PRIu64, log_sector_size);
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
36
goto fail;
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;
76
}
77
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
80
{
81
Visitor *v;
82
Object *obj;
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
84
}
37
}
85
qdict_del(qdict, "id");
38
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);
106
}
107
108
void qmp_object_del(const char *id, Error **errp)
109
--
39
--
110
2.25.3
40
2.13.6
111
41
112
42
diff view generated by jsdifflib
1
The raw format driver can simply forward the flag and let its bs->file
1
From: Ari Sundholm <ari@tuxera.com>
2
child take care of actually providing the zeros.
2
3
3
Suggested by Kevin Wolf. May be useful when testing multiple batches
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
of writes or doing long-term testing involving restarts of the VM.
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Ari Sundholm <ari@tuxera.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>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
8
---
11
block/raw-format.c | 4 +++-
9
qapi/block-core.json | 3 +-
12
1 file changed, 3 insertions(+), 1 deletion(-)
10
block/blklogwrites.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++-----
13
11
2 files changed, 135 insertions(+), 15 deletions(-)
14
diff --git a/block/raw-format.c b/block/raw-format.c
12
13
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/block/raw-format.c
15
--- a/qapi/block-core.json
17
+++ b/block/raw-format.c
16
+++ b/qapi/block-core.json
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
17
@@ -XXX,XX +XXX,XX @@
19
18
{ 'struct': 'BlockdevOptionsBlklogwrites',
20
s->size = offset;
19
'data': { 'file': 'BlockdevRef',
21
offset += s->offset;
20
'log': 'BlockdevRef',
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
21
- '*log-sector-size': 'uint32' } }
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
22
+ '*log-sector-size': 'uint32',
23
+ '*log-append': 'bool' } }
24
25
##
26
# @BlockdevOptionsBlkverify:
27
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/blklogwrites.c
30
+++ b/block/blklogwrites.c
31
@@ -XXX,XX +XXX,XX @@
32
#define LOG_FUA_FLAG (1 << 1)
33
#define LOG_DISCARD_FLAG (1 << 2)
34
#define LOG_MARK_FLAG (1 << 3)
35
+#define LOG_FLAG_MASK (LOG_FLUSH_FLAG \
36
+ | LOG_FUA_FLAG \
37
+ | LOG_DISCARD_FLAG \
38
+ | LOG_MARK_FLAG)
39
40
#define WRITE_LOG_VERSION 1ULL
41
#define WRITE_LOG_MAGIC 0x6a736677736872ULL
42
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
43
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
44
.desc = {
45
{
46
+ .name = "log-append",
47
+ .type = QEMU_OPT_BOOL,
48
+ .help = "Append to an existing log",
49
+ },
50
+ {
51
.name = "log-sector-size",
52
.type = QEMU_OPT_SIZE,
53
.help = "Log sector size",
54
@@ -XXX,XX +XXX,XX @@ static inline uint32_t blk_log_writes_log2(uint32_t value)
55
return 31 - clz32(value);
24
}
56
}
25
57
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
58
+static inline bool blk_log_writes_sector_size_valid(uint32_t sector_size)
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
59
+{
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
60
+ return sector_size < (1ull << 24) && is_power_of_2(sector_size);
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
61
+}
30
bs->file->bs->supported_zero_flags);
62
+
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
63
+static uint64_t blk_log_writes_find_cur_log_sector(BdrvChild *log,
32
+ BDRV_REQ_ZERO_WRITE;
64
+ uint32_t sector_size,
33
65
+ uint64_t nr_entries,
34
if (bs->probed && !bdrv_is_read_only(bs)) {
66
+ Error **errp)
35
bdrv_refresh_filename(bs->file->bs);
67
+{
68
+ uint64_t cur_sector = 1;
69
+ uint64_t cur_idx = 0;
70
+ uint32_t sector_bits = blk_log_writes_log2(sector_size);
71
+ struct log_write_entry cur_entry;
72
+
73
+ while (cur_idx < nr_entries) {
74
+ int read_ret = bdrv_pread(log, cur_sector << sector_bits, &cur_entry,
75
+ sizeof(cur_entry));
76
+ if (read_ret < 0) {
77
+ error_setg_errno(errp, -read_ret,
78
+ "Failed to read log entry %"PRIu64, cur_idx);
79
+ return (uint64_t)-1ull;
80
+ }
81
+
82
+ if (cur_entry.flags & ~cpu_to_le64(LOG_FLAG_MASK)) {
83
+ error_setg(errp, "Invalid flags 0x%"PRIx64" in log entry %"PRIu64,
84
+ le64_to_cpu(cur_entry.flags), cur_idx);
85
+ return (uint64_t)-1ull;
86
+ }
87
+
88
+ /* Account for the sector of the entry itself */
89
+ ++cur_sector;
90
+
91
+ /*
92
+ * Account for the data of the write.
93
+ * For discards, this data is not present.
94
+ */
95
+ if (!(cur_entry.flags & cpu_to_le64(LOG_DISCARD_FLAG))) {
96
+ cur_sector += le64_to_cpu(cur_entry.nr_sectors);
97
+ }
98
+
99
+ ++cur_idx;
100
+ }
101
+
102
+ return cur_sector;
103
+}
104
+
105
static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
106
Error **errp)
107
{
108
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
109
Error *local_err = NULL;
110
int ret;
111
uint64_t log_sector_size;
112
+ bool log_append;
113
114
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
115
qemu_opts_absorb_qdict(opts, options, &local_err);
116
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
117
goto fail;
118
}
119
120
- log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
121
- BDRV_SECTOR_SIZE);
122
-
123
- if (log_sector_size > (1ull << 23) || !is_power_of_2(log_sector_size)) {
124
- ret = -EINVAL;
125
- error_setg(errp, "Invalid log sector size %"PRIu64, log_sector_size);
126
- goto fail;
127
- }
128
-
129
- s->sectorsize = log_sector_size;
130
- s->sectorbits = blk_log_writes_log2(log_sector_size);
131
- s->cur_log_sector = 1;
132
- s->nr_entries = 0;
133
-
134
/* Open the log file */
135
s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
136
&local_err);
137
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
138
goto fail;
139
}
140
141
+ log_append = qemu_opt_get_bool(opts, "log-append", false);
142
+
143
+ if (log_append) {
144
+ struct log_write_super log_sb = { 0, 0, 0, 0 };
145
+
146
+ if (qemu_opt_find(opts, "log-sector-size")) {
147
+ ret = -EINVAL;
148
+ error_setg(errp, "log-append and log-sector-size are mutually "
149
+ "exclusive");
150
+ goto fail_log;
151
+ }
152
+
153
+ /* Read log superblock or fake one for an empty log */
154
+ if (!bdrv_getlength(s->log_file->bs)) {
155
+ log_sb.magic = cpu_to_le64(WRITE_LOG_MAGIC);
156
+ log_sb.version = cpu_to_le64(WRITE_LOG_VERSION);
157
+ log_sb.nr_entries = cpu_to_le64(0);
158
+ log_sb.sectorsize = cpu_to_le32(BDRV_SECTOR_SIZE);
159
+ } else {
160
+ ret = bdrv_pread(s->log_file, 0, &log_sb, sizeof(log_sb));
161
+ if (ret < 0) {
162
+ error_setg_errno(errp, -ret, "Could not read log superblock");
163
+ goto fail_log;
164
+ }
165
+ }
166
+
167
+ if (log_sb.magic != cpu_to_le64(WRITE_LOG_MAGIC)) {
168
+ ret = -EINVAL;
169
+ error_setg(errp, "Invalid log superblock magic");
170
+ goto fail_log;
171
+ }
172
+
173
+ if (log_sb.version != cpu_to_le64(WRITE_LOG_VERSION)) {
174
+ ret = -EINVAL;
175
+ error_setg(errp, "Unsupported log version %"PRIu64,
176
+ le64_to_cpu(log_sb.version));
177
+ goto fail_log;
178
+ }
179
+
180
+ log_sector_size = le32_to_cpu(log_sb.sectorsize);
181
+ s->cur_log_sector = 1;
182
+ s->nr_entries = 0;
183
+
184
+ if (blk_log_writes_sector_size_valid(log_sector_size)) {
185
+ s->cur_log_sector =
186
+ blk_log_writes_find_cur_log_sector(s->log_file, log_sector_size,
187
+ le64_to_cpu(log_sb.nr_entries), &local_err);
188
+ if (local_err) {
189
+ ret = -EINVAL;
190
+ error_propagate(errp, local_err);
191
+ goto fail_log;
192
+ }
193
+
194
+ s->nr_entries = le64_to_cpu(log_sb.nr_entries);
195
+ }
196
+ } else {
197
+ log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
198
+ BDRV_SECTOR_SIZE);
199
+ s->cur_log_sector = 1;
200
+ s->nr_entries = 0;
201
+ }
202
+
203
+ if (!blk_log_writes_sector_size_valid(log_sector_size)) {
204
+ ret = -EINVAL;
205
+ error_setg(errp, "Invalid log sector size %"PRIu64, log_sector_size);
206
+ goto fail_log;
207
+ }
208
+
209
+ s->sectorsize = log_sector_size;
210
+ s->sectorbits = blk_log_writes_log2(log_sector_size);
211
+
212
ret = 0;
213
+fail_log:
214
+ if (ret < 0) {
215
+ bdrv_unref_child(bs, s->log_file);
216
+ s->log_file = NULL;
217
+ }
218
fail:
219
if (ret < 0) {
220
bdrv_unref_child(bs, bs->file);
36
--
221
--
37
2.25.3
222
2.13.6
38
223
39
224
diff view generated by jsdifflib
1
The QMP handler qmp_object_add() and the implementation of --object in
1
From: Ari Sundholm <ari@tuxera.com>
2
qemu-storage-daemon can share most of the code. Currently,
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
5
2
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
3
This is a way to ensure that the log superblock is periodically
7
new function user_creatable_add_dict() that can get an additional
4
updated. Before, this was only done on flush requests, which may
8
parameter. The handling of "props" is only required for compatibility
5
not be enough if the VM exits abnormally, omitting the final flush.
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
11
6
7
The default interval is 4096 write requests.
8
9
Signed-off-by: Ari Sundholm <ari@tuxera.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
11
---
14
include/qom/object_interfaces.h | 12 ++++++++++++
12
qapi/block-core.json | 6 +++++-
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
13
block/blklogwrites.c | 20 ++++++++++++++++++--
16
qom/qom-qmp-cmds.c | 24 +-----------------------
14
2 files changed, 23 insertions(+), 3 deletions(-)
17
3 files changed, 40 insertions(+), 23 deletions(-)
18
15
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
16
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
21
--- a/include/qom/object_interfaces.h
18
--- a/qapi/block-core.json
22
+++ b/include/qom/object_interfaces.h
19
+++ b/qapi/block-core.json
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
20
@@ -XXX,XX +XXX,XX @@
24
const QDict *qdict,
21
# @log-sector-size: sector size used in logging writes to @file, determines
25
Visitor *v, Error **errp);
22
# granularity of offsets and sizes of writes (default: 512)
26
23
#
27
+/**
24
+# @log-super-update-interval: interval of write requests after which the log
28
+ * user_creatable_add_dict:
25
+# super block is updated to disk (default: 4096)
29
+ * @qdict: the object definition
26
+#
30
+ * @errp: if an error occurs, a pointer to an area to store the error
27
# Since: 3.0
31
+ *
28
##
32
+ * Create an instance of the user creatable object that is defined by
29
{ 'struct': 'BlockdevOptionsBlklogwrites',
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
30
'data': { 'file': 'BlockdevRef',
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
31
'log': 'BlockdevRef',
35
+ * initialize the object properties.
32
'*log-sector-size': 'uint32',
36
+ */
33
- '*log-append': 'bool' } }
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
34
+ '*log-append': 'bool',
38
+
35
+ '*log-super-update-interval': 'uint64' } }
39
/**
36
40
* user_creatable_add_opts:
37
##
41
* @opts: the object definition
38
# @BlockdevOptionsBlkverify:
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
39
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
43
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
44
--- a/qom/object_interfaces.c
41
--- a/block/blklogwrites.c
45
+++ b/qom/object_interfaces.c
42
+++ b/block/blklogwrites.c
46
@@ -XXX,XX +XXX,XX @@
43
@@ -XXX,XX +XXX,XX @@ typedef struct {
47
#include "qapi/qmp/qerror.h"
44
uint32_t sectorbits;
48
#include "qapi/qmp/qjson.h"
45
uint64_t cur_log_sector;
49
#include "qapi/qmp/qstring.h"
46
uint64_t nr_entries;
50
+#include "qapi/qobject-input-visitor.h"
47
+ uint64_t update_interval;
51
#include "qom/object_interfaces.h"
48
} BDRVBlkLogWritesState;
52
#include "qemu/help_option.h"
49
53
#include "qemu/module.h"
50
static QemuOptsList runtime_opts = {
54
@@ -XXX,XX +XXX,XX @@ out:
51
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
55
return obj;
52
.type = QEMU_OPT_SIZE,
56
}
53
.help = "Log sector size",
57
54
},
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
55
+ {
59
+{
56
+ .name = "log-super-update-interval",
60
+ Visitor *v;
57
+ .type = QEMU_OPT_NUMBER,
61
+ Object *obj;
58
+ .help = "Log superblock update interval (# of write requests)",
62
+ g_autofree char *type = NULL;
59
+ },
63
+ g_autofree char *id = NULL;
60
{ /* end of list */ }
64
+
61
},
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
62
};
66
+ if (!type) {
63
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
64
68
+ return;
65
s->sectorsize = log_sector_size;
66
s->sectorbits = blk_log_writes_log2(log_sector_size);
67
+ s->update_interval = qemu_opt_get_number(opts, "log-super-update-interval",
68
+ 4096);
69
+ if (!s->update_interval) {
70
+ ret = -EINVAL;
71
+ error_setg(errp, "Invalid log superblock update interval %"PRIu64,
72
+ s->update_interval);
73
+ goto fail_log;
69
+ }
74
+ }
70
+ qdict_del(qdict, "qom-type");
75
71
+
76
ret = 0;
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
77
fail_log:
73
+ if (!id) {
78
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
79
lr->zero_size, 0);
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
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qom/qom-qmp-cmds.c
90
+++ b/qom/qom-qmp-cmds.c
91
@@ -XXX,XX +XXX,XX @@
92
#include "qapi/qapi-commands-qom.h"
93
#include "qapi/qmp/qdict.h"
94
#include "qapi/qmp/qerror.h"
95
-#include "qapi/qobject-input-visitor.h"
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;
107
-
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
109
- if (!type) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
111
- return;
112
- }
113
- qdict_del(qdict, "qom-type");
114
-
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
116
- if (!id) {
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
118
- return;
119
- }
120
- qdict_del(qdict, "id");
121
122
props = qdict_get(qdict, "props");
123
if (props) {
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
125
qobject_unref(pdict);
126
}
80
}
127
81
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
82
- /* Update super block on flush */
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
83
- if (lr->log_ret == 0 && lr->entry.flags & LOG_FLUSH_FLAG) {
130
- visit_free(v);
84
+ /* Update super block on flush or every update interval */
131
- object_unref(obj);
85
+ if (lr->log_ret == 0 && ((lr->entry.flags & LOG_FLUSH_FLAG)
132
+ user_creatable_add_dict(qdict, errp);
86
+ || (s->nr_entries % s->update_interval == 0)))
133
}
87
+ {
134
88
struct log_write_super super = {
135
void qmp_object_del(const char *id, Error **errp)
89
.magic = cpu_to_le64(WRITE_LOG_MAGIC),
90
.version = cpu_to_le64(WRITE_LOG_VERSION),
136
--
91
--
137
2.25.3
92
2.13.6
138
93
139
94
diff view generated by jsdifflib
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
1
From: Max Reitz <mreitz@redhat.com>
2
OS, so we can advertise the flag and just ignore it.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
raw_apply_lock_bytes() takes a bit mask of "permissions that are NOT
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
shared".
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Also, make the "perm" and "shared" variables uint64_t, because I do not
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
7
particularly like using ~ on signed integers (and other permission masks
8
are usually uint64_t, too).
9
10
Reported-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
13
---
11
block/file-posix.c | 4 ++++
14
block/file-posix.c | 4 ++--
12
1 file changed, 4 insertions(+)
15
1 file changed, 2 insertions(+), 2 deletions(-)
13
16
14
diff --git a/block/file-posix.c b/block/file-posix.c
17
diff --git a/block/file-posix.c b/block/file-posix.c
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/file-posix.c
19
--- a/block/file-posix.c
17
+++ b/block/file-posix.c
20
+++ b/block/file-posix.c
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
21
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
19
#endif
22
{
20
23
BlockdevCreateOptionsFile *file_opts;
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
24
int fd;
22
+ if (S_ISREG(st.st_mode)) {
25
- int perm, shared;
23
+ /* When extending regular files, we get zeros from the OS */
26
+ uint64_t perm, shared;
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
27
int result = 0;
25
+ }
28
26
ret = 0;
29
/* Validate options and set default values */
27
fail:
30
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
31
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
32
33
/* Step one: Take locks */
34
- result = raw_apply_lock_bytes(fd, perm, shared, false, errp);
35
+ result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
36
if (result < 0) {
37
goto out_close;
38
}
29
--
39
--
30
2.25.3
40
2.13.6
31
41
32
42
diff view generated by jsdifflib
Deleted patch
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.
5
1
6
Insert a filter_testfiles() call between both.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
tests/qemu-iotests/iotests.py | 5 +++--
15
1 file changed, 3 insertions(+), 2 deletions(-)
16
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/iotests.py
20
+++ b/tests/qemu-iotests/iotests.py
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
22
for line in output.split('\n'):
23
if 'disk size' in line or 'actual-size' in line:
24
continue
25
- line = line.replace(filename, 'TEST_IMG') \
26
- .replace(imgfmt, 'IMGFMT')
27
+ line = line.replace(filename, 'TEST_IMG')
28
+ line = filter_testfiles(line)
29
+ line = line.replace(imgfmt, 'IMGFMT')
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
33
--
34
2.25.3
35
36
diff view generated by jsdifflib
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
3
Closing the FD does not necessarily mean that it is unlocked. Fix this
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
4
by relinquishing all permission locks before qemu_close().
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.
8
5
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
6
Reported-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.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>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
9
---
16
hw/block/nvme.h | 2 +
10
block/file-posix.c | 17 ++++++++++++++---
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 14 insertions(+), 3 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(-)
22
12
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
13
diff --git a/block/file-posix.c b/block/file-posix.c
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/block/nvme.h
15
--- a/block/file-posix.c
26
+++ b/hw/block/nvme.h
16
+++ b/block/file-posix.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
18
raw_co_create(BlockdevCreateOptions *options, Error **errp)
29
19
{
30
char *serial;
20
BlockdevCreateOptionsFile *file_opts;
31
+ HostMemoryBackend *pmrdev;
21
+ Error *local_err = NULL;
32
+
22
int fd;
33
NvmeNamespace *namespaces;
23
uint64_t perm, shared;
34
NvmeSQueue **sq;
24
int result = 0;
35
NvmeCQueue **cq;
25
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
26
/* Step two: Check that nobody else has taken conflicting locks */
37
index XXXXXXX..XXXXXXX 100644
27
result = raw_check_lock_bytes(fd, perm, shared, errp);
38
--- a/include/block/nvme.h
28
if (result < 0) {
39
+++ b/include/block/nvme.h
29
- goto out_close;
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
30
+ goto out_unlock;
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)
309
}
31
}
310
32
311
if (addr < sizeof(n->bar)) {
33
/* Clear the file by truncating it to 0 */
312
+ /*
34
result = raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, errp);
313
+ * When PMRWBM bit 1 is set then read from
35
if (result < 0) {
314
+ * from PMRSTS should ensure prior writes
36
- goto out_close;
315
+ * made it to persistent media
37
+ goto out_unlock;
316
+ */
317
+ if (addr == 0xE08 &&
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
320
+ 0, n->pmrdev->size);
321
+ }
322
memcpy(&val, ptr + addr, size);
323
} else {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
326
error_setg(errp, "serial property not set");
327
return;
328
}
38
}
329
+
39
330
+ if (!n->cmb_size_mb && n->pmrdev) {
40
if (file_opts->nocow) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
41
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
42
result = raw_regular_truncate(NULL, fd, file_opts->size,
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
43
file_opts->preallocation, errp);
334
+ g_free(path);
44
if (result < 0) {
335
+ return;
45
- goto out_close;
336
+ }
46
+ goto out_unlock;
337
+
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
+ }
47
+ }
345
+
48
+
346
blkconf_blocksizes(&n->conf);
49
+out_unlock:
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
50
+ raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
348
false, errp)) {
51
+ if (local_err) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
52
+ /* The above call should not fail, and if it does, that does
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
53
+ * not mean the whole creation operation has failed. So
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
54
+ * report it the user for their convenience, but do not report
352
55
+ * it to the caller. */
353
+ } else if (n->pmrdev) {
56
+ error_report_err(local_err);
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
}
57
}
399
58
400
for (i = 0; i < n->num_namespaces; i++) {
59
out_close:
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);
410
}
411
412
static Property nvme_props[] = {
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
415
+ HostMemoryBackend *),
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
420
index XXXXXXX..XXXXXXX 100644
421
--- a/hw/block/Makefile.objs
422
+++ b/hw/block/Makefile.objs
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
424
common-obj-$(CONFIG_XEN) += xen-block.o
425
common-obj-$(CONFIG_ECC) += ecc.o
426
common-obj-$(CONFIG_ONENAND) += onenand.o
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
428
common-obj-$(CONFIG_SWIM) += swim.o
429
430
common-obj-$(CONFIG_SH4) += tc58128.o
431
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
435
436
obj-y += dataplane/
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/block/trace-events
440
+++ b/hw/block/trace-events
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
452
--
60
--
453
2.25.3
61
2.13.6
454
62
455
63
diff view generated by jsdifflib