1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
1
The following changes since commit 2e3408b3cc7de4e87a9adafc8c19bfce3abec947:
2
2
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
3
Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-03 09:13:17 -0700)
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 c1fe694357a328c807ae3cc6961c19e923448fcc:
10
10
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
11
coroutine-win32: use QEMU_DEFINE_STATIC_CO_TLS() (2022-05-04 15:55:23 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- Fix resize (extending) of short overlays
16
- Fix and re-enable GLOBAL_STATE_CODE assertions
17
- nvme: introduce PMR support from NVMe 1.4 spec
17
- vhost-user: Fixes for VHOST_USER_ADD/REM_MEM_REG
18
- qemu-storage-daemon: Fix non-string --object properties
18
- vmdk: Fix reopening bs->file
19
- coroutine: use QEMU_DEFINE_STATIC_CO_TLS()
20
- docs/qemu-img: Fix list of formats which implement check
19
21
20
----------------------------------------------------------------
22
----------------------------------------------------------------
21
Alberto Garcia (1):
23
Denis V. Lunev (1):
22
qcow2: Add incompatibility note between backing files and raw external data files
24
qemu-img: properly list formats which have consistency check implemented
23
25
24
Andrzej Jakowski (1):
26
Hanna Reitz (6):
25
nvme: introduce PMR support from NVMe 1.4 spec
27
block: Classify bdrv_get_flags() as I/O function
28
qcow2: Do not reopen data_file in invalidate_cache
29
Revert "main-loop: Disable GLOBAL_STATE_CODE() assertions"
30
iotests: Add regression test for issue 945
31
block/vmdk: Fix reopening bs->file
32
iotests/reopen-file: Test reopening file child
26
33
27
Kevin Wolf (12):
34
Kevin Wolf (3):
28
block: Add flags to BlockDriver.bdrv_co_truncate()
35
docs/vhost-user: Clarifications for VHOST_USER_ADD/REM_MEM_REG
29
block: Add flags to bdrv(_co)_truncate()
36
libvhost-user: Fix extra vu_add/rem_mem_reg reply
30
block-backend: Add flags to blk_truncate()
37
vhost-user: Don't pass file descriptor for VHOST_USER_REM_MEM_REG
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
38
41
Paolo Bonzini (1):
39
Stefan Hajnoczi (3):
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
40
coroutine-ucontext: use QEMU_DEFINE_STATIC_CO_TLS()
41
coroutine: use QEMU_DEFINE_STATIC_CO_TLS()
42
coroutine-win32: use QEMU_DEFINE_STATIC_CO_TLS()
43
43
44
docs/interop/qcow2.txt | 3 +
44
docs/interop/vhost-user.rst | 17 ++++
45
hw/block/nvme.h | 2 +
45
docs/tools/qemu-img.rst | 4 +-
46
include/block/block.h | 5 +-
46
include/block/block-global-state.h | 1 -
47
include/block/block_int.h | 10 +-
47
include/block/block-io.h | 1 +
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
48
include/qemu/main-loop.h | 3 +-
49
include/qom/object_interfaces.h | 16 +++
49
block.c | 2 +-
50
include/sysemu/block-backend.h | 2 +-
50
block/qcow2.c | 104 ++++++++++++---------
51
block.c | 3 +-
51
block/vmdk.c | 56 ++++++++++-
52
block/block-backend.c | 4 +-
52
hw/virtio/vhost-user.c | 2 +-
53
block/commit.c | 4 +-
53
subprojects/libvhost-user/libvhost-user.c | 17 ++--
54
block/crypto.c | 7 +-
54
util/coroutine-ucontext.c | 38 +++++---
55
block/file-posix.c | 6 +-
55
util/coroutine-win32.c | 18 +++-
56
block/file-win32.c | 2 +-
56
util/qemu-coroutine.c | 41 ++++----
57
block/gluster.c | 1 +
57
tests/qemu-iotests/tests/export-incoming-iothread | 81 ++++++++++++++++
58
block/io.c | 43 ++++++-
58
.../tests/export-incoming-iothread.out | 5 +
59
block/iscsi.c | 2 +-
59
tests/qemu-iotests/tests/reopen-file | 89 ++++++++++++++++++
60
block/mirror.c | 2 +-
60
tests/qemu-iotests/tests/reopen-file.out | 5 +
61
block/nfs.c | 3 +-
61
17 files changed, 388 insertions(+), 96 deletions(-)
62
block/parallels.c | 6 +-
62
create mode 100755 tests/qemu-iotests/tests/export-incoming-iothread
63
block/qcow.c | 4 +-
63
create mode 100644 tests/qemu-iotests/tests/export-incoming-iothread.out
64
block/qcow2-cluster.c | 2 +-
64
create mode 100755 tests/qemu-iotests/tests/reopen-file
65
block/qcow2-refcount.c | 2 +-
65
create mode 100644 tests/qemu-iotests/tests/reopen-file.out
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
97
diff view generated by jsdifflib
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
1
From: "Denis V. Lunev" <den@openvz.org>
2
2
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
3
Simple grep for the .bdrv_co_check callback presence gives the following
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
4
list of block drivers
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
5
* QED
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
6
* VDI
7
persistent across system reboot.
7
* VHDX
8
* VMDK
9
* Parallels
10
which have this callback. The presense of the callback means that
11
consistency check is supported.
8
12
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
13
The patch updates documentation accordingly.
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
14
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Denis V. Lunev <den@openvz.org>
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
16
CC: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
17
CC: Hanna Reitz <hreitz@redhat.com>
18
Message-Id: <20220407083932.531965-1-den@openvz.org>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
21
---
16
hw/block/nvme.h | 2 +
22
docs/tools/qemu-img.rst | 4 ++--
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
23
1 file changed, 2 insertions(+), 2 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
24
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
25
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
24
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/block/nvme.h
27
--- a/docs/tools/qemu-img.rst
26
+++ b/hw/block/nvme.h
28
+++ b/docs/tools/qemu-img.rst
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
29
@@ -XXX,XX +XXX,XX @@ Command description:
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
30
``-r all`` fixes all kinds of errors, with a higher risk of choosing the
29
31
wrong fix or hiding corruption that has already occurred.
30
char *serial;
32
31
+ HostMemoryBackend *pmrdev;
33
- Only the formats ``qcow2``, ``qed`` and ``vdi`` support
32
+
34
- consistency checks.
33
NvmeNamespace *namespaces;
35
+ Only the formats ``qcow2``, ``qed``, ``parallels``, ``vhdx``, ``vmdk`` and
34
NvmeSQueue **sq;
36
+ ``vdi`` support consistency checks.
35
NvmeCQueue **cq;
37
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
38
In case the image does not have any inconsistencies, check exits with ``0``.
37
index XXXXXXX..XXXXXXX 100644
39
Other exit codes indicate the kind of inconsistency found or if another error
38
--- a/include/block/nvme.h
39
+++ b/include/block/nvme.h
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
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
}
310
311
if (addr < sizeof(n->bar)) {
312
+ /*
313
+ * When PMRWBM bit 1 is set then read from
314
+ * from PMRSTS should ensure prior writes
315
+ * made it to persistent media
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
}
329
+
330
+ if (!n->cmb_size_mb && n->pmrdev) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
334
+ g_free(path);
335
+ return;
336
+ }
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
+ }
345
+
346
blkconf_blocksizes(&n->conf);
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
348
false, errp)) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
408
+ }
409
msix_uninit_exclusive_bar(pci_dev);
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
--
40
--
453
2.25.3
41
2.35.1
454
455
diff view generated by jsdifflib
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
1
The specification for VHOST_USER_ADD/REM_MEM_REG messages is unclear
2
image is possibly preallocated and then the zero flag is added to all
2
in several points, which has led to clients having incompatible
3
clusters. This means that a copy-on-write operation may be needed when
3
implementations. This changes the specification to be more explicit
4
writing to these clusters, despite having used preallocation, negating
4
about them:
5
one of the major benefits of preallocation.
6
5
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
6
* VHOST_USER_ADD_MEM_REG is not specified as receiving a file
8
and if the protocol driver can ensure that the new area reads as zeros,
7
descriptor, though it obviously does need to do so. All
9
we can skip setting the zero flag in the qcow2 layer.
8
implementations agree on this one, fix the specification.
10
9
11
Unfortunately, the same approach doesn't work for metadata
10
* VHOST_USER_REM_MEM_REG is not specified as receiving a file
12
preallocation, so we'll still set the zero flag there.
11
descriptor either, and it also has no reason to do so. rust-vmm does
12
not send file descriptors for removing a memory region (in agreement
13
with the specification), libvhost-user and QEMU do (which is a bug),
14
though libvhost-user doesn't actually make any use of it.
15
16
Change the specification so that for compatibility QEMU's behaviour
17
becomes legal, even if discouraged, but rust-vmm's behaviour becomes
18
the explicitly recommended mode of operation.
19
20
* VHOST_USER_ADD_MEM_REG doesn't have a documented return value, which
21
is the desired behaviour in the non-postcopy case. It also implemented
22
like this in QEMU and rust-vmm, though libvhost-user is buggy and
23
sometimes sends an unexpected reply. This will be fixed in a separate
24
patch.
25
26
However, in postcopy mode it does reply like VHOST_USER_SET_MEM_TABLE.
27
This behaviour is shared between libvhost-user and QEMU; rust-vmm
28
doesn't implement postcopy mode yet. Mention it explicitly in the
29
spec.
30
31
* The specification doesn't mention how VHOST_USER_REM_MEM_REG
32
identifies the memory region to be removed. Change it to describe the
33
existing behaviour of libvhost-user (guest address, user address and
34
size must match).
13
35
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
37
Message-Id: <20220407133657.155281-2-kwolf@redhat.com>
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
38
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
39
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
40
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
41
---
20
block/qcow2.c | 22 +++++++++++++++++++---
42
docs/interop/vhost-user.rst | 17 +++++++++++++++++
21
tests/qemu-iotests/274.out | 4 ++--
43
1 file changed, 17 insertions(+)
22
2 files changed, 21 insertions(+), 5 deletions(-)
23
44
24
diff --git a/block/qcow2.c b/block/qcow2.c
45
diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
25
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2.c
47
--- a/docs/interop/vhost-user.rst
27
+++ b/block/qcow2.c
48
+++ b/docs/interop/vhost-user.rst
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
49
@@ -XXX,XX +XXX,XX @@ replies. Here is a list of the ones that do:
29
/* Allocate the data area */
50
There are several messages that the master sends with file descriptors passed
30
new_file_size = allocation_start +
51
in the ancillary data:
31
nb_new_data_clusters * s->cluster_size;
52
32
- /* Image file grows, so @exact does not matter */
53
+* ``VHOST_USER_ADD_MEM_REG``
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
54
* ``VHOST_USER_SET_MEM_TABLE``
34
- errp);
55
* ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``)
35
+ /*
56
* ``VHOST_USER_SET_LOG_FD``
36
+ * Image file grows, so @exact does not matter.
57
@@ -XXX,XX +XXX,XX @@ Master message types
37
+ *
58
``VHOST_USER_REM_MEM_REG`` message, this message is used to set and
38
+ * If we need to zero out the new area, try first whether the protocol
59
update the memory tables of the slave device.
39
+ * driver can already take care of this.
60
40
+ */
61
+ Exactly one file descriptor from which the memory is mapped is
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
62
+ passed in the ancillary data.
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
63
+
43
+ BDRV_REQ_ZERO_WRITE, NULL);
64
+ In postcopy mode (see ``VHOST_USER_POSTCOPY_LISTEN``), the slave
44
+ if (ret >= 0) {
65
+ replies with the bases of the memory mapped region to the master.
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
66
+ For further details on postcopy, see ``VHOST_USER_SET_MEM_TABLE``.
46
+ }
67
+ They apply to ``VHOST_USER_ADD_MEM_REG`` accordingly.
47
+ } else {
68
+
48
+ ret = -1;
69
``VHOST_USER_REM_MEM_REG``
49
+ }
70
:id: 38
50
+ if (ret < 0) {
71
:equivalent ioctl: N/A
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
72
@@ -XXX,XX +XXX,XX @@ Master message types
52
+ errp);
73
``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and
53
+ }
74
update the memory tables of the slave device.
54
if (ret < 0) {
75
55
error_prepend(errp, "Failed to resize underlying file: ");
76
+ The memory region to be removed is identified by its guest address,
56
qcow2_free_clusters(bs, allocation_start,
77
+ user address and size. The mmap offset is ignored.
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
78
+
58
index XXXXXXX..XXXXXXX 100644
79
+ No file descriptors SHOULD be passed in the ancillary data. For
59
--- a/tests/qemu-iotests/274.out
80
+ compatibility with existing incorrect implementations, the slave MAY
60
+++ b/tests/qemu-iotests/274.out
81
+ accept messages with one file descriptor. If a file descriptor is
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
82
+ passed, the slave MUST close it without using it otherwise.
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
83
+
63
84
``VHOST_USER_SET_STATUS``
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
85
:id: 39
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
86
:equivalent ioctl: VHOST_VDPA_SET_STATUS
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
--
87
--
80
2.25.3
88
2.35.1
81
82
diff view generated by jsdifflib
1
After processing the option string with the keyval parser, we get a
1
Outside of postcopy mode, neither VHOST_USER_ADD_MEM_REG nor
2
QDict that contains only strings. This QDict must be fed to a keyval
2
VHOST_USER_REM_MEM_REG are supposed to send a reply unless explicitly
3
visitor which converts the strings into the right data types.
3
requested with the need_reply flag. Their current implementation always
4
sends a reply, even if it isn't requested. This confuses the master
5
because it will interpret the reply as a reply for the next message for
6
which it actually expects a reply.
4
7
5
qmp_object_add(), however, uses the normal QObject input visitor, which
8
need_reply is already handled correctly by vu_dispatch(), so just don't
6
expects a QDict where all properties already have the QType that matches
9
send a reply in the non-postcopy part of the message handler for these
7
the data type required by the QOM object type.
10
two commands.
8
11
9
Change the --object implementation in qemu-storage-daemon so that it
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
13
Message-Id: <20220407133657.155281-3-kwolf@redhat.com>
11
directly instead and pass it a new keyval boolean that decides which
14
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
12
visitor must be used.
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
---
17
include/qom/object_interfaces.h | 6 +++++-
18
subprojects/libvhost-user/libvhost-user.c | 9 +++------
18
qemu-storage-daemon.c | 4 +---
19
1 file changed, 3 insertions(+), 6 deletions(-)
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
22
20
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
21
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
24
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qom/object_interfaces.h
23
--- a/subprojects/libvhost-user/libvhost-user.c
26
+++ b/include/qom/object_interfaces.h
24
+++ b/subprojects/libvhost-user/libvhost-user.c
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
25
@@ -XXX,XX +XXX,XX @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
28
/**
26
29
* user_creatable_add_dict:
27
DPRINT("Successfully added new region\n");
30
* @qdict: the object definition
28
dev->nregions++;
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
29
- vmsg_set_reply_u64(vmsg, 0);
32
+ * assume that all @qdict values are strings); otherwise, use
30
- return true;
33
+ * the normal QObject visitor (i.e. assume all @qdict values
31
+ return false;
34
+ * have the QType expected by the QOM object type)
32
}
35
* @errp: if an error occurs, a pointer to an area to store the error
36
*
37
* Create an instance of the user creatable object that is defined by
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
39
* ID from the key 'id'. The remaining entries in @qdict are used to
40
* initialize the object properties.
41
*/
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
44
45
/**
46
* user_creatable_add_opts:
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/qemu-storage-daemon.c
50
+++ b/qemu-storage-daemon.c
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
52
QemuOpts *opts;
53
const char *type;
54
QDict *args;
55
- QObject *ret_data = NULL;
56
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
58
* unconditionall try QemuOpts first. */
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
60
qemu_opts_del(opts);
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
76
}
33
}
77
34
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
35
@@ -XXX,XX +XXX,XX @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
36
}
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
39
- if (found) {
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
40
- vmsg_set_reply_u64(vmsg, 0);
88
+ if (keyval) {
41
- } else {
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
42
+ if (!found) {
90
+ } else {
43
vu_panic(dev, "Specified region not found\n");
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
}
44
}
103
45
104
- user_creatable_add_dict(qdict, errp);
46
close(vmsg->fds[0]);
105
+ user_creatable_add_dict(qdict, false, errp);
47
48
- return true;
49
+ return false;
106
}
50
}
107
51
108
void qmp_object_del(const char *id, Error **errp)
52
static bool
109
--
53
--
110
2.25.3
54
2.35.1
111
112
diff view generated by jsdifflib
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
1
The spec clarifies now that QEMU should not send a file descriptor in a
2
driver callbacks, and a supported_truncate_flags field in
2
request to remove a memory region. Change it accordingly.
3
BlockDriverState that allows drivers to advertise support for request
4
flags in the context of truncate.
5
3
6
For now, we always pass 0 and no drivers declare support for any flag.
4
For libvhost-user, this is a bug fix that makes it compatible with
5
rust-vmm's implementation that doesn't send a file descriptor. Keep
6
accepting, but ignoring a file descriptor for compatibility with older
7
QEMU versions.
7
8
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-Id: <20220407133657.155281-4-kwolf@redhat.com>
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
14
---
15
include/block/block_int.h | 10 +++++++++-
15
hw/virtio/vhost-user.c | 2 +-
16
block/crypto.c | 3 ++-
16
subprojects/libvhost-user/libvhost-user.c | 8 ++++----
17
block/file-posix.c | 2 +-
17
2 files changed, 5 insertions(+), 5 deletions(-)
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
18
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
19
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
33
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
21
--- a/hw/virtio/vhost-user.c
35
+++ b/include/block/block_int.h
22
+++ b/hw/virtio/vhost-user.c
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
23
@@ -XXX,XX +XXX,XX @@ static int send_remove_regions(struct vhost_dev *dev,
37
*/
24
vhost_user_fill_msg_region(&region_buffer, shadow_reg, 0);
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
25
msg->payload.mem_reg.region = region_buffer;
39
bool exact, PreallocMode prealloc,
26
40
- Error **errp);
27
- ret = vhost_user_write(dev, msg, &fd, 1);
41
+ BdrvRequestFlags flags, Error **errp);
28
+ ret = vhost_user_write(dev, msg, NULL, 0);
42
29
if (ret < 0) {
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
30
return ret;
44
bool has_variable_length;
31
}
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
32
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
55
+ */
56
+ unsigned int supported_truncate_flags;
57
58
/* the following member gives a name to every node on the bs graph. */
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
34
--- a/subprojects/libvhost-user/libvhost-user.c
63
+++ b/block/crypto.c
35
+++ b/subprojects/libvhost-user/libvhost-user.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
36
@@ -XXX,XX +XXX,XX @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
65
37
int i;
66
static int coroutine_fn
38
bool found = false;
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
39
68
- PreallocMode prealloc, Error **errp)
40
- if (vmsg->fd_num != 1) {
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
41
+ if (vmsg->fd_num > 1) {
70
+ Error **errp)
42
vmsg_close_fds(vmsg);
71
{
43
- vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd "
72
BlockCrypto *crypto = bs->opaque;
44
+ vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - at most 1 fd "
73
uint64_t payload_offset =
45
"should be sent for this message type", vmsg->fd_num);
74
diff --git a/block/file-posix.c b/block/file-posix.c
46
return false;
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
}
47
}
126
48
127
if (drv->bdrv_co_truncate) {
49
if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
50
- close(vmsg->fds[0]);
129
+ if (flags & ~bs->supported_truncate_flags) {
51
+ vmsg_close_fds(vmsg);
130
+ error_setg(errp, "Block driver does not support requested flags");
52
vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at "
131
+ ret = -ENOTSUP;
53
"least %d bytes and only %d bytes were received",
132
+ goto out;
54
VHOST_USER_MEM_REG_SIZE, vmsg->size);
133
+ }
55
@@ -XXX,XX +XXX,XX @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
56
vu_panic(dev, "Specified region not found\n");
135
} else if (bs->file && drv->is_filter) {
57
}
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
58
137
} else {
59
- close(vmsg->fds[0]);
138
diff --git a/block/iscsi.c b/block/iscsi.c
60
+ vmsg_close_fds(vmsg);
139
index XXXXXXX..XXXXXXX 100644
61
140
--- a/block/iscsi.c
62
return false;
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
}
63
}
264
--
64
--
265
2.25.3
65
2.35.1
266
267
diff view generated by jsdifflib
1
Now that node level interface bdrv_truncate() supports passing request
1
From: Hanna Reitz <hreitz@redhat.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
This function is safe to call in an I/O context, and qcow2_do_open()
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
does so (invoked in an I/O context by qcow2_co_invalidate_cache()).
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
7
Message-Id: <20220427114057.36651-2-hreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
include/sysemu/block-backend.h | 2 +-
11
include/block/block-global-state.h | 1 -
12
block.c | 3 ++-
12
include/block/block-io.h | 1 +
13
block/block-backend.c | 4 ++--
13
block.c | 2 +-
14
block/commit.c | 4 ++--
14
3 files changed, 2 insertions(+), 2 deletions(-)
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
15
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
16
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
29
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
30
--- a/include/sysemu/block-backend.h
18
--- a/include/block/block-global-state.h
31
+++ b/include/sysemu/block-backend.h
19
+++ b/include/block/block-global-state.h
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
20
@@ -XXX,XX +XXX,XX @@ void bdrv_next_cleanup(BdrvNextIterator *it);
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
21
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
34
int bytes);
22
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
23
void *opaque, bool read_only);
36
- PreallocMode prealloc, Error **errp);
24
-int bdrv_get_flags(BlockDriverState *bs);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
25
char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
26
char *bdrv_dirname(BlockDriverState *bs, Error **errp);
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
27
40
int64_t pos, int size);
28
diff --git a/include/block/block-io.h b/include/block/block-io.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block-io.h
31
+++ b/include/block/block-io.h
32
@@ -XXX,XX +XXX,XX @@ int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
33
bool bdrv_is_read_only(BlockDriverState *bs);
34
bool bdrv_is_writable(BlockDriverState *bs);
35
bool bdrv_is_sg(BlockDriverState *bs);
36
+int bdrv_get_flags(BlockDriverState *bs);
37
bool bdrv_is_inserted(BlockDriverState *bs);
38
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
39
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
41
diff --git a/block.c b/block.c
40
diff --git a/block.c b/block.c
42
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
43
--- a/block.c
42
--- a/block.c
44
+++ b/block.c
43
+++ b/block.c
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
44
@@ -XXX,XX +XXX,XX @@ const char *bdrv_get_device_or_node_name(const BlockDriverState *bs)
46
int64_t size;
45
47
int ret;
46
int bdrv_get_flags(BlockDriverState *bs)
48
47
{
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
48
- GLOBAL_STATE_CODE();
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
49
+ IO_CODE();
51
+ &local_err);
50
return bs->open_flags;
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
}
51
}
61
52
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
250
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
252
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
255
* success when the image has not actually been resized.
256
*/
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
259
if (!ret) {
260
qprintf(quiet, "Image resized.\n");
261
} else {
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
263
index XXXXXXX..XXXXXXX 100644
264
--- a/qemu-io-cmds.c
265
+++ b/qemu-io-cmds.c
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
267
* exact=true. It is better to err on the "emit more errors" side
268
* than to be overly permissive.
269
*/
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
272
if (ret < 0) {
273
error_report_err(local_err);
274
return ret;
275
--
53
--
276
2.25.3
54
2.35.1
277
278
diff view generated by jsdifflib
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
1
From: Hanna Reitz <hreitz@redhat.com>
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
2
3
undo any previous preallocation, but just adds the zero flag to all
3
qcow2_co_invalidate_cache() closes and opens the qcow2 file, by calling
4
relevant L2 entries. If an external data file is in use, a write_zeroes
4
qcow2_close() and qcow2_do_open(). These two functions must thus be
5
request to the data file is made instead.
5
usable from both a global-state and an I/O context.
6
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
As they are, they are not safe to call in an I/O context, because they
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
8
use bdrv_unref_child() and bdrv_open_child() to close/open the data_file
9
child, respectively, both of which are global-state functions. When
10
used from qcow2_co_invalidate_cache(), we do not need to close/open the
11
data_file child, though (we do not do this for bs->file or bs->backing
12
either), and so we should skip it in the qcow2_co_invalidate_cache()
13
path.
14
15
To do so, add a parameter to qcow2_do_open() and qcow2_close() to make
16
them skip handling s->data_file, and have qcow2_co_invalidate_cache()
17
exempt it from the memset() on the BDRVQcow2State.
18
19
(Note that the QED driver similarly closes/opens the QED image by
20
invoking bdrv_qed_close()+bdrv_qed_do_open(), but both functions seem
21
safe to use in an I/O context.)
22
23
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/945
24
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
25
Message-Id: <20220427114057.36651-3-hreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
26
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
28
---
13
block/qcow2-cluster.c | 2 +-
29
block/qcow2.c | 104 ++++++++++++++++++++++++++++++--------------------
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
30
1 file changed, 62 insertions(+), 42 deletions(-)
15
2 files changed, 35 insertions(+), 1 deletion(-)
31
16
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
20
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
22
/* Caller must pass aligned values, except at image end */
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
27
28
/* The zero flag is only supported by version 3 and newer */
29
if (s->qcow_version < 3) {
30
diff --git a/block/qcow2.c b/block/qcow2.c
32
diff --git a/block/qcow2.c b/block/qcow2.c
31
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2.c
34
--- a/block/qcow2.c
33
+++ b/block/qcow2.c
35
+++ b/block/qcow2.c
36
@@ -XXX,XX +XXX,XX @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp)
37
38
/* Called with s->lock held. */
39
static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
40
- int flags, Error **errp)
41
+ int flags, bool open_data_file,
42
+ Error **errp)
43
{
44
ERRP_GUARD();
45
BDRVQcow2State *s = bs->opaque;
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
46
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
35
47
goto fail;
36
bs->supported_zero_flags = header.version >= 3 ?
48
}
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
49
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
50
- /* Open external data file */
39
51
- s->data_file = bdrv_open_child(NULL, options, "data-file", bs,
40
/* Repair image if dirty */
52
- &child_of_bds, BDRV_CHILD_DATA,
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
53
- true, errp);
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
54
- if (*errp) {
43
g_assert_not_reached();
55
- ret = -EINVAL;
44
}
56
- goto fail;
45
57
- }
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
58
+ if (open_data_file) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
59
+ /* Open external data file */
48
+
60
+ s->data_file = bdrv_open_child(NULL, options, "data-file", bs,
49
+ /*
61
+ &child_of_bds, BDRV_CHILD_DATA,
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
62
+ true, errp);
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
63
+ if (*errp) {
52
+ * at the end of the image (which it is here).
64
+ ret = -EINVAL;
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;
65
+ goto fail;
58
+ }
66
+ }
59
+
67
60
+ /* Write explicit zeros for the unaligned head */
68
- if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
61
+ if (zero_start > old_length) {
69
- if (!s->data_file && s->image_data_file) {
62
+ uint64_t len = zero_start - old_length;
70
- s->data_file = bdrv_open_child(s->image_data_file, options,
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
71
- "data-file", bs, &child_of_bds,
64
+ QEMUIOVector qiov;
72
- BDRV_CHILD_DATA, false, errp);
65
+ qemu_iovec_init_buf(&qiov, buf, len);
73
+ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
66
+
74
+ if (!s->data_file && s->image_data_file) {
67
+ qemu_co_mutex_unlock(&s->lock);
75
+ s->data_file = bdrv_open_child(s->image_data_file, options,
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
76
+ "data-file", bs, &child_of_bds,
69
+ qemu_co_mutex_lock(&s->lock);
77
+ BDRV_CHILD_DATA, false, errp);
70
+
78
+ if (!s->data_file) {
71
+ qemu_vfree(buf);
79
+ ret = -EINVAL;
72
+ if (ret < 0) {
80
+ goto fail;
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
81
+ }
82
+ }
83
if (!s->data_file) {
84
+ error_setg(errp, "'data-file' is required for this image");
85
ret = -EINVAL;
86
goto fail;
87
}
88
- }
89
- if (!s->data_file) {
90
- error_setg(errp, "'data-file' is required for this image");
91
- ret = -EINVAL;
92
- goto fail;
93
- }
94
95
- /* No data here */
96
- bs->file->role &= ~BDRV_CHILD_DATA;
97
+ /* No data here */
98
+ bs->file->role &= ~BDRV_CHILD_DATA;
99
100
- /* Must succeed because we have given up permissions if anything */
101
- bdrv_child_refresh_perms(bs, bs->file, &error_abort);
102
- } else {
103
- if (s->data_file) {
104
- error_setg(errp, "'data-file' can only be set for images with an "
105
- "external data file");
106
- ret = -EINVAL;
107
- goto fail;
108
- }
109
+ /* Must succeed because we have given up permissions if anything */
110
+ bdrv_child_refresh_perms(bs, bs->file, &error_abort);
111
+ } else {
112
+ if (s->data_file) {
113
+ error_setg(errp, "'data-file' can only be set for images with "
114
+ "an external data file");
115
+ ret = -EINVAL;
74
+ goto fail;
116
+ goto fail;
75
+ }
117
+ }
76
+ }
118
77
+ }
119
- s->data_file = bs->file;
120
+ s->data_file = bs->file;
121
122
- if (data_file_is_raw(bs)) {
123
- error_setg(errp, "data-file-raw requires a data file");
124
- ret = -EINVAL;
125
- goto fail;
126
+ if (data_file_is_raw(bs)) {
127
+ error_setg(errp, "data-file-raw requires a data file");
128
+ ret = -EINVAL;
129
+ goto fail;
130
+ }
131
}
132
}
133
134
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
135
136
fail:
137
g_free(s->image_data_file);
138
- if (has_data_file(bs)) {
139
+ if (open_data_file && has_data_file(bs)) {
140
bdrv_unref_child(bs, s->data_file);
141
s->data_file = NULL;
142
}
143
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qcow2_open_entry(void *opaque)
144
BDRVQcow2State *s = qoc->bs->opaque;
145
146
qemu_co_mutex_lock(&s->lock);
147
- qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, qoc->errp);
148
+ qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
149
+ qoc->errp);
150
qemu_co_mutex_unlock(&s->lock);
151
}
152
153
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
154
return result;
155
}
156
157
-static void qcow2_close(BlockDriverState *bs)
158
+static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
159
{
160
BDRVQcow2State *s = bs->opaque;
161
qemu_vfree(s->l1_table);
162
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
163
g_free(s->image_backing_file);
164
g_free(s->image_backing_format);
165
166
- if (has_data_file(bs)) {
167
+ if (close_data_file && has_data_file(bs)) {
168
bdrv_unref_child(bs, s->data_file);
169
s->data_file = NULL;
170
}
171
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
172
qcow2_free_snapshots(bs);
173
}
174
175
+static void qcow2_close(BlockDriverState *bs)
176
+{
177
+ qcow2_do_close(bs, true);
178
+}
78
+
179
+
79
if (prealloc != PREALLOC_MODE_OFF) {
180
static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
80
/* Flush metadata before actually changing the image size */
181
Error **errp)
81
ret = qcow2_write_caches(bs);
182
{
183
ERRP_GUARD();
184
BDRVQcow2State *s = bs->opaque;
185
+ BdrvChild *data_file;
186
int flags = s->flags;
187
QCryptoBlock *crypto = NULL;
188
QDict *options;
189
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
190
crypto = s->crypto;
191
s->crypto = NULL;
192
193
- qcow2_close(bs);
194
+ /*
195
+ * Do not reopen s->data_file (i.e., have qcow2_do_close() not close it,
196
+ * and then prevent qcow2_do_open() from opening it), because this function
197
+ * runs in the I/O path and as such we must not invoke global-state
198
+ * functions like bdrv_unref_child() and bdrv_open_child().
199
+ */
200
201
+ qcow2_do_close(bs, false);
202
+
203
+ data_file = s->data_file;
204
memset(s, 0, sizeof(BDRVQcow2State));
205
+ s->data_file = data_file;
206
+
207
options = qdict_clone_shallow(bs->options);
208
209
flags &= ~BDRV_O_INACTIVE;
210
qemu_co_mutex_lock(&s->lock);
211
- ret = qcow2_do_open(bs, options, flags, errp);
212
+ ret = qcow2_do_open(bs, options, flags, false, errp);
213
qemu_co_mutex_unlock(&s->lock);
214
qobject_unref(options);
215
if (ret < 0) {
82
--
216
--
83
2.25.3
217
2.35.1
84
85
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
2
3
Backing files and raw external data files are mutually exclusive.
3
This reverts commit b1c073490553f80594b903ceedfc7c1aef6b1b19. (We
4
The documentation of the raw external data bit (in autoclear_features)
4
wanted to do so once the 7.1 tree opens, which has happened. The issue
5
already indicates that, but we should also mention it on the other
5
reported in https://gitlab.com/qemu-project/qemu/-/issues/945 should be
6
side.
6
fixed by the preceding patches.)
7
7
8
Suggested-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Message-Id: <20220427114057.36651-4-hreitz@redhat.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
12
---
14
docs/interop/qcow2.txt | 3 +++
13
include/qemu/main-loop.h | 3 +--
15
1 file changed, 3 insertions(+)
14
1 file changed, 1 insertion(+), 2 deletions(-)
16
15
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
16
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/interop/qcow2.txt
18
--- a/include/qemu/main-loop.h
20
+++ b/docs/interop/qcow2.txt
19
+++ b/include/qemu/main-loop.h
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
20
@@ -XXX,XX +XXX,XX @@ bool qemu_in_main_thread(void);
22
is stored (NB: The string is not null terminated). 0 if the
21
#else
23
image doesn't have a backing file.
22
#define GLOBAL_STATE_CODE() \
24
23
do { \
25
+ Note: backing files are incompatible with raw external data
24
- /* FIXME: Re-enable after 7.0 release */ \
26
+ files (auto-clear feature bit 1).
25
- /* assert(qemu_in_main_thread()); */ \
27
+
26
+ assert(qemu_in_main_thread()); \
28
16 - 19: backing_file_size
27
} while (0)
29
Length of the backing file name in bytes. Must not be
28
#endif /* CONFIG_COCOA */
30
longer than 1023 bytes. Undefined if the image doesn't have
29
31
--
30
--
32
2.25.3
31
2.35.1
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
We want to keep TEST_IMG for the full path of the main test image, but
1
From: Hanna Reitz <hreitz@redhat.com>
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
2
6
Insert a filter_testfiles() call between both.
3
Create a VM with a BDS in an iothread, add -incoming defer to the
4
command line, and then export this BDS via NBD. Doing so should not
5
fail an assertion.
7
6
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20220427114057.36651-5-hreitz@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
10
Tested-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
12
---
14
tests/qemu-iotests/iotests.py | 5 +++--
13
.../tests/export-incoming-iothread | 81 +++++++++++++++++++
15
1 file changed, 3 insertions(+), 2 deletions(-)
14
.../tests/export-incoming-iothread.out | 5 ++
15
2 files changed, 86 insertions(+)
16
create mode 100755 tests/qemu-iotests/tests/export-incoming-iothread
17
create mode 100644 tests/qemu-iotests/tests/export-incoming-iothread.out
16
18
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
19
diff --git a/tests/qemu-iotests/tests/export-incoming-iothread b/tests/qemu-iotests/tests/export-incoming-iothread
18
index XXXXXXX..XXXXXXX 100644
20
new file mode 100755
19
--- a/tests/qemu-iotests/iotests.py
21
index XXXXXXX..XXXXXXX
20
+++ b/tests/qemu-iotests/iotests.py
22
--- /dev/null
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
23
+++ b/tests/qemu-iotests/tests/export-incoming-iothread
22
for line in output.split('\n'):
24
@@ -XXX,XX +XXX,XX @@
23
if 'disk size' in line or 'actual-size' in line:
25
+#!/usr/bin/env python3
24
continue
26
+# group: rw quick migration
25
- line = line.replace(filename, 'TEST_IMG') \
27
+#
26
- .replace(imgfmt, 'IMGFMT')
28
+# Regression test for issue 945:
27
+ line = line.replace(filename, 'TEST_IMG')
29
+# https://gitlab.com/qemu-project/qemu/-/issues/945
28
+ line = filter_testfiles(line)
30
+# Test adding an export on top of an iothread-ed block device while in
29
+ line = line.replace(imgfmt, 'IMGFMT')
31
+# -incoming defer.
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
32
+#
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
33
+# Copyright (C) 2022 Red Hat, Inc.
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
34
+#
35
+# This program is free software; you can redistribute it and/or modify
36
+# it under the terms of the GNU General Public License as published by
37
+# the Free Software Foundation; either version 2 of the License, or
38
+# (at your option) any later version.
39
+#
40
+# This program is distributed in the hope that it will be useful,
41
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
42
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43
+# GNU General Public License for more details.
44
+#
45
+# You should have received a copy of the GNU General Public License
46
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
47
+#
48
+
49
+import os
50
+import iotests
51
+from iotests import qemu_img_create
52
+
53
+
54
+image_size = 1 * 1024 * 1024
55
+test_img = os.path.join(iotests.test_dir, 'test.img')
56
+node_name = 'node0'
57
+iothread_id = 'iothr0'
58
+
59
+nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock')
60
+
61
+
62
+class TestExportIncomingIothread(iotests.QMPTestCase):
63
+ def setUp(self) -> None:
64
+ qemu_img_create('-f', iotests.imgfmt, test_img, str(image_size))
65
+
66
+ self.vm = iotests.VM()
67
+ self.vm.add_object(f'iothread,id={iothread_id}')
68
+ self.vm.add_blockdev((
69
+ f'driver={iotests.imgfmt}',
70
+ f'node-name={node_name}',
71
+ 'file.driver=file',
72
+ f'file.filename={test_img}'
73
+ ))
74
+ self.vm.add_incoming('defer')
75
+ self.vm.launch()
76
+
77
+ def tearDown(self):
78
+ self.vm.shutdown()
79
+ os.remove(test_img)
80
+
81
+ def test_export_add(self):
82
+ result = self.vm.qmp('nbd-server-start', {
83
+ 'addr': {
84
+ 'type': 'unix',
85
+ 'data': {
86
+ 'path': nbd_sock
87
+ }
88
+ }
89
+ })
90
+ self.assert_qmp(result, 'return', {})
91
+
92
+ # Regression test for issue 945: This should not fail an assertion
93
+ result = self.vm.qmp('block-export-add', {
94
+ 'type': 'nbd',
95
+ 'id': 'exp0',
96
+ 'node-name': node_name,
97
+ 'iothread': iothread_id
98
+ })
99
+ self.assert_qmp(result, 'return', {})
100
+
101
+
102
+if __name__ == '__main__':
103
+ iotests.main(supported_fmts=['generic'],
104
+ unsupported_fmts=['luks'], # Would need a secret
105
+ supported_protocols=['file'])
106
diff --git a/tests/qemu-iotests/tests/export-incoming-iothread.out b/tests/qemu-iotests/tests/export-incoming-iothread.out
107
new file mode 100644
108
index XXXXXXX..XXXXXXX
109
--- /dev/null
110
+++ b/tests/qemu-iotests/tests/export-incoming-iothread.out
111
@@ -XXX,XX +XXX,XX @@
112
+.
113
+----------------------------------------------------------------------
114
+Ran 1 tests
115
+
116
+OK
33
--
117
--
34
2.25.3
118
2.35.1
35
36
diff view generated by jsdifflib
1
When extending the size of an image that has a backing file larger than
1
From: Hanna Reitz <hreitz@redhat.com>
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
4
2
5
Consider the following scenario where the overlay is shorter than its
3
VMDK disk data is stored in extents, which may or may not be separate
6
backing file:
4
from bs->file. VmdkExtent.file points to where they are stored. Each
5
that is stored in bs->file will simply reuse the exact pointer value of
6
bs->file.
7
7
8
base.qcow2: AAAAAAAA
8
(That is why vmdk_free_extents() will unref VmdkExtent.file (e->file)
9
overlay.qcow2: BBBB
9
only if e->file != bs->file.)
10
10
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
11
Reopen operations can change bs->file (they will replace the whole
12
unallocated and make the additional As from base.qcow2 visible like
12
BdrvChild object, not just the BDS stored in that BdrvChild), and then
13
before this patch, but zeros should be read.
13
we will need to change all .file pointers of all such VmdkExtents to
14
point to the new BdrvChild.
14
15
15
A similar case happens with the various variants of a commit job when an
16
In vmdk_reopen_prepare(), we have to check which VmdkExtents are
16
intermediate file is short (- for unallocated):
17
affected, and in vmdk_reopen_commit(), we can modify them. We have to
18
split this because:
19
- The new BdrvChild is created only after prepare, so we can change
20
VmdkExtent.file only in commit
21
- In commit, there no longer is any (valid) reference to the old
22
BdrvChild object, so there would be nothing to compare VmdkExtent.file
23
against to see whether it was equal to bs->file before reopening
24
(There is BDRVReopenState.old_file_bs, but the old bs->file
25
BdrvChild's .bs pointer will be NULL-ed when the new BdrvChild is
26
created, and so we cannot compare VmdkExtent.file->bs against
27
BDRVReopenState.old_file_bs)
17
28
18
base.qcow2: A-A-AAAA
29
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
19
mid.qcow2: BB-B
30
Message-Id: <20220314162719.65384-2-hreitz@redhat.com>
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>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
32
---
36
block/io.c | 25 +++++++++++++++++++++++++
33
block/vmdk.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-
37
1 file changed, 25 insertions(+)
34
1 file changed, 55 insertions(+), 1 deletion(-)
38
35
39
diff --git a/block/io.c b/block/io.c
36
diff --git a/block/vmdk.c b/block/vmdk.c
40
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
41
--- a/block/io.c
38
--- a/block/vmdk.c
42
+++ b/block/io.c
39
+++ b/block/vmdk.c
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
40
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVVmdkState {
44
goto out;
41
char *create_type;
45
}
42
} BDRVVmdkState;
46
43
44
+typedef struct BDRVVmdkReopenState {
45
+ bool *extents_using_bs_file;
46
+} BDRVVmdkReopenState;
47
+
48
typedef struct VmdkMetaData {
49
unsigned int l1_index;
50
unsigned int l2_index;
51
@@ -XXX,XX +XXX,XX @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
52
return 1;
53
}
54
55
-/* We have nothing to do for VMDK reopen, stubs just return success */
56
static int vmdk_reopen_prepare(BDRVReopenState *state,
57
BlockReopenQueue *queue, Error **errp)
58
{
59
+ BDRVVmdkState *s;
60
+ BDRVVmdkReopenState *rs;
61
+ int i;
62
+
63
assert(state != NULL);
64
assert(state->bs != NULL);
65
+ assert(state->opaque == NULL);
66
+
67
+ s = state->bs->opaque;
68
+
69
+ rs = g_new0(BDRVVmdkReopenState, 1);
70
+ state->opaque = rs;
71
+
47
+ /*
72
+ /*
48
+ * If the image has a backing file that is large enough that it would
73
+ * Check whether there are any extents stored in bs->file; if bs->file
49
+ * provide data for the new area, we cannot leave it unallocated because
74
+ * changes, we will need to update their .file pointers to follow suit
50
+ * then the backing file content would become visible. Instead, zero-fill
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
+ */
75
+ */
57
+ if (new_bytes && bs->backing) {
76
+ rs->extents_using_bs_file = g_new(bool, s->num_extents);
58
+ int64_t backing_len;
77
+ for (i = 0; i < s->num_extents; i++) {
78
+ rs->extents_using_bs_file[i] = s->extents[i].file == state->bs->file;
79
+ }
59
+
80
+
60
+ backing_len = bdrv_getlength(backing_bs(bs));
81
return 0;
61
+ if (backing_len < 0) {
82
}
62
+ ret = backing_len;
83
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
84
+static void vmdk_reopen_clean(BDRVReopenState *state)
64
+ goto out;
85
+{
65
+ }
86
+ BDRVVmdkReopenState *rs = state->opaque;
66
+
87
+
67
+ if (backing_len > old_size) {
88
+ g_free(rs->extents_using_bs_file);
68
+ flags |= BDRV_REQ_ZERO_WRITE;
89
+ g_free(rs);
90
+ state->opaque = NULL;
91
+}
92
+
93
+static void vmdk_reopen_commit(BDRVReopenState *state)
94
+{
95
+ BDRVVmdkState *s = state->bs->opaque;
96
+ BDRVVmdkReopenState *rs = state->opaque;
97
+ int i;
98
+
99
+ for (i = 0; i < s->num_extents; i++) {
100
+ if (rs->extents_using_bs_file[i]) {
101
+ s->extents[i].file = state->bs->file;
69
+ }
102
+ }
70
+ }
103
+ }
71
+
104
+
72
if (drv->bdrv_co_truncate) {
105
+ vmdk_reopen_clean(state);
73
if (flags & ~bs->supported_truncate_flags) {
106
+}
74
error_setg(errp, "Block driver does not support requested flags");
107
+
108
+static void vmdk_reopen_abort(BDRVReopenState *state)
109
+{
110
+ vmdk_reopen_clean(state);
111
+}
112
+
113
static int vmdk_parent_open(BlockDriverState *bs)
114
{
115
char *p_name;
116
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = {
117
.bdrv_open = vmdk_open,
118
.bdrv_co_check = vmdk_co_check,
119
.bdrv_reopen_prepare = vmdk_reopen_prepare,
120
+ .bdrv_reopen_commit = vmdk_reopen_commit,
121
+ .bdrv_reopen_abort = vmdk_reopen_abort,
122
.bdrv_child_perm = bdrv_default_perms,
123
.bdrv_co_preadv = vmdk_co_preadv,
124
.bdrv_co_pwritev = vmdk_co_pwritev,
75
--
125
--
76
2.25.3
126
2.35.1
77
78
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
From: Hanna Reitz <hreitz@redhat.com>
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
2
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
This should work for all format drivers that support reopening, so test
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
it.
5
6
(This serves as a regression test for HEAD^: This test used to fail for
7
VMDK before HEAD^.)
8
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
Message-Id: <20220314162719.65384-3-hreitz@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
12
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
13
tests/qemu-iotests/tests/reopen-file | 89 ++++++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
14
tests/qemu-iotests/tests/reopen-file.out | 5 ++
9
tests/qemu-iotests/group | 1 +
15
2 files changed, 94 insertions(+)
10
3 files changed, 424 insertions(+)
16
create mode 100755 tests/qemu-iotests/tests/reopen-file
11
create mode 100755 tests/qemu-iotests/274
17
create mode 100644 tests/qemu-iotests/tests/reopen-file.out
12
create mode 100644 tests/qemu-iotests/274.out
13
18
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
19
diff --git a/tests/qemu-iotests/tests/reopen-file b/tests/qemu-iotests/tests/reopen-file
15
new file mode 100755
20
new file mode 100755
16
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
17
--- /dev/null
22
--- /dev/null
18
+++ b/tests/qemu-iotests/274
23
+++ b/tests/qemu-iotests/tests/reopen-file
19
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python3
25
+#!/usr/bin/env python3
26
+# group: rw quick
21
+#
27
+#
22
+# Copyright (C) 2019 Red Hat, Inc.
28
+# Test reopening a format driver's file child
29
+#
30
+# Copyright (C) 2022 Red Hat, Inc.
23
+#
31
+#
24
+# This program is free software; you can redistribute it and/or modify
32
+# This program is free software; you can redistribute it and/or modify
25
+# it under the terms of the GNU General Public License as published by
33
+# 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
34
+# the Free Software Foundation; either version 2 of the License, or
27
+# (at your option) any later version.
35
+# (at your option) any later version.
...
...
32
+# GNU General Public License for more details.
40
+# GNU General Public License for more details.
33
+#
41
+#
34
+# You should have received a copy of the GNU General Public License
42
+# You should have received a copy of the GNU General Public License
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
43
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
36
+#
44
+#
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
38
+#
39
+# Some tests for short backing files and short overlays
40
+
45
+
46
+import os
41
+import iotests
47
+import iotests
42
+
48
+from iotests import imgfmt, qemu_img_create, QMPTestCase
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
44
+iotests.verify_platform(['linux'])
45
+
46
+size_short = 1 * 1024 * 1024
47
+size_long = 2 * 1024 * 1024
48
+size_diff = size_long - size_short
49
+
50
+def create_chain() -> None:
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
52
+ str(size_long))
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
54
+ str(size_short))
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
56
+ str(size_long))
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
+
49
+
137
+
50
+
138
+ iotests.log('== Resize tests ==')
51
+image_size = 1 * 1024 * 1024
52
+test_img = os.path.join(iotests.test_dir, 'test.img')
139
+
53
+
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
+
54
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
55
+class TestReopenFile(QMPTestCase):
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
56
+ def setUp(self) -> None:
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
57
+ res = qemu_img_create('-f', imgfmt, test_img, str(image_size))
162
+ top_size_old)
58
+ assert res.returncode == 0
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
164
+
59
+
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
60
+ # Add format driver node ('format') on top of the file ('file'), then
166
+ #
61
+ # add another raw node ('raw') on top of 'file' so for the reopen we
167
+ # In theory, leaving base_size to top_size_new unallocated would be
62
+ # can just switch from 'file' to 'raw'
168
+ # correct, but in practice, if we zero out anything, we zero out
63
+ self.vm = iotests.VM()
169
+ # everything up to top_size_new.
64
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
65
+ 'driver': imgfmt,
171
+ '--preallocation', prealloc, top, top_size_new)
66
+ 'node-name': 'format',
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
67
+ 'file': {
173
+ iotests.qemu_io_log('-c', 'map', top)
68
+ 'driver': 'file',
174
+ iotests.qemu_img_log('map', '--output=json', top)
69
+ 'node-name': 'file',
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
70
+ 'filename': test_img
71
+ }
72
+ }))
73
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
74
+ 'driver': 'raw',
75
+ 'node-name': 'raw',
76
+ 'file': 'file'
77
+ }))
78
+ self.vm.launch()
79
+
80
+ def tearDown(self) -> None:
81
+ self.vm.shutdown()
82
+ os.remove(test_img)
83
+
84
+ # Check if there was any qemu-io run that failed
85
+ if 'Pattern verification failed' in self.vm.get_log():
86
+ print('ERROR: Pattern verification failed:')
87
+ print(self.vm.get_log())
88
+ self.fail('qemu-io pattern verification failed')
89
+
90
+ def test_reopen_file(self) -> None:
91
+ result = self.vm.qmp('blockdev-reopen', options=[{
92
+ 'driver': imgfmt,
93
+ 'node-name': 'format',
94
+ 'file': 'raw'
95
+ }])
96
+ self.assert_qmp(result, 'return', {})
97
+
98
+ # Do some I/O to the image to see whether it still works
99
+ # (Pattern verification will be checked by tearDown())
100
+ result = self.vm.qmp('human-monitor-command',
101
+ command_line='qemu-io format "write -P 42 0 64k"')
102
+ self.assert_qmp(result, 'return', '')
103
+
104
+ result = self.vm.qmp('human-monitor-command',
105
+ command_line='qemu-io format "read -P 42 0 64k"')
106
+ self.assert_qmp(result, 'return', '')
107
+
108
+
109
+if __name__ == '__main__':
110
+ # Must support creating images and reopen
111
+ iotests.main(supported_fmts=['qcow', 'qcow2', 'qed', 'raw', 'vdi', 'vhdx',
112
+ 'vmdk', 'vpc'],
113
+ supported_protocols=['file'])
114
diff --git a/tests/qemu-iotests/tests/reopen-file.out b/tests/qemu-iotests/tests/reopen-file.out
176
new file mode 100644
115
new file mode 100644
177
index XXXXXXX..XXXXXXX
116
index XXXXXXX..XXXXXXX
178
--- /dev/null
117
--- /dev/null
179
+++ b/tests/qemu-iotests/274.out
118
+++ b/tests/qemu-iotests/tests/reopen-file.out
180
@@ -XXX,XX +XXX,XX @@
119
@@ -XXX,XX +XXX,XX @@
181
+== Commit tests ==
120
+.
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
121
+----------------------------------------------------------------------
122
+Ran 1 tests
183
+
123
+
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
124
+OK
185
+
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
187
+
188
+wrote 2097152/2097152 bytes at offset 0
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
190
+
191
+=== Check visible data ===
192
+read 1048576/1048576 bytes at offset 0
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+
195
+read 1048576/1048576 bytes at offset 1048576
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
197
+
198
+=== Checking allocation status ===
199
+1048576/1048576 bytes allocated at offset 0 bytes
200
+1048576/1048576 bytes allocated at offset 1 MiB
201
+
202
+0/1048576 bytes allocated at offset 0 bytes
203
+0/0 bytes allocated at offset 1 MiB
204
+
205
+0/1048576 bytes allocated at offset 0 bytes
206
+0/1048576 bytes allocated at offset 1 MiB
207
+
208
+=== Checking map ===
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
211
+Offset Length Mapped to File
212
+0 0x200000 0x50000 TEST_DIR/PID-base
213
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
215
+
216
+Offset Length Mapped to File
217
+0 0x100000 0x50000 TEST_DIR/PID-base
218
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
222
+Offset Length Mapped to File
223
+0 0x100000 0x50000 TEST_DIR/PID-base
224
+
225
+=== Testing qemu-img commit (top -> mid) ===
226
+Image committed.
227
+
228
+image: TEST_IMG
229
+file format: IMGFMT
230
+virtual size: 2 MiB (2097152 bytes)
231
+cluster_size: 65536
232
+backing file: TEST_DIR/PID-base
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
239
+read 1048576/1048576 bytes at offset 0
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
242
+read 1048576/1048576 bytes at offset 1048576
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
244
+
245
+=== Testing HMP commit (top -> mid) ===
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
247
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
249
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
251
+
252
+wrote 2097152/2097152 bytes at offset 0
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
256
+{"return": ""}
257
+image: TEST_IMG
258
+file format: IMGFMT
259
+virtual size: 2 MiB (2097152 bytes)
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
268
+read 1048576/1048576 bytes at offset 0
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
+
271
+read 1048576/1048576 bytes at offset 1048576
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+
274
+=== Testing QMP active commit (top -> mid) ===
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
280
+
281
+wrote 2097152/2097152 bytes at offset 0
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
283
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
285
+{"return": {}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
287
+{"return": {}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
333
+
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
448
+
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
450
index XXXXXXX..XXXXXXX 100644
451
--- a/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
453
@@ -XXX,XX +XXX,XX @@
454
270 rw backing quick
455
272 rw
456
273 backing quick
457
+274 rw backing
458
277 rw quick
459
279 rw backing quick
460
280 rw migration quick
461
--
125
--
462
2.25.3
126
2.35.1
463
464
diff view generated by jsdifflib
1
The QMP handler qmp_object_add() and the implementation of --object in
1
From: Stefan Hajnoczi <stefanha@redhat.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
Thread-Local Storage variables cannot be used directly from coroutine
7
new function user_creatable_add_dict() that can get an additional
4
code because the compiler may optimize TLS variable accesses across
8
parameter. The handling of "props" is only required for compatibility
5
qemu_coroutine_yield() calls. When the coroutine is re-entered from
9
and not required for the qemu-storage-daemon command line, so it stays
6
another thread the TLS variables from the old thread must no longer be
10
in qmp_object_add().
7
used.
11
8
9
Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables.
10
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20220307153853.602859-2-stefanha@redhat.com>
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
15
---
14
include/qom/object_interfaces.h | 12 ++++++++++++
16
util/coroutine-ucontext.c | 38 ++++++++++++++++++++++++--------------
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
17
1 file changed, 24 insertions(+), 14 deletions(-)
16
qom/qom-qmp-cmds.c | 24 +-----------------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
18
18
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
19
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
20
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/qom/object_interfaces.h
21
--- a/util/coroutine-ucontext.c
22
+++ b/include/qom/object_interfaces.h
22
+++ b/util/coroutine-ucontext.c
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
23
@@ -XXX,XX +XXX,XX @@
24
const QDict *qdict,
24
#include "qemu/osdep.h"
25
Visitor *v, Error **errp);
25
#include <ucontext.h>
26
26
#include "qemu/coroutine_int.h"
27
+/**
27
+#include "qemu/coroutine-tls.h"
28
+ * user_creatable_add_dict:
28
29
+ * @qdict: the object definition
29
#ifdef CONFIG_VALGRIND_H
30
+ * @errp: if an error occurs, a pointer to an area to store the error
30
#include <valgrind/valgrind.h>
31
+ *
31
@@ -XXX,XX +XXX,XX @@ typedef struct {
32
+ * Create an instance of the user creatable object that is defined by
32
/**
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
33
* Per-thread coroutine bookkeeping
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
34
*/
35
+ * initialize the object properties.
35
-static __thread CoroutineUContext leader;
36
+ */
36
-static __thread Coroutine *current;
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
37
+QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
38
+QEMU_DEFINE_STATIC_CO_TLS(CoroutineUContext, leader);
39
40
/*
41
* va_args to makecontext() must be type 'int', so passing
42
@@ -XXX,XX +XXX,XX @@ static inline __attribute__((always_inline))
43
void finish_switch_fiber(void *fake_stack_save)
44
{
45
#ifdef CONFIG_ASAN
46
+ CoroutineUContext *leaderp = get_ptr_leader();
47
const void *bottom_old;
48
size_t size_old;
49
50
__sanitizer_finish_switch_fiber(fake_stack_save, &bottom_old, &size_old);
51
52
- if (!leader.stack) {
53
- leader.stack = (void *)bottom_old;
54
- leader.stack_size = size_old;
55
+ if (!leaderp->stack) {
56
+ leaderp->stack = (void *)bottom_old;
57
+ leaderp->stack_size = size_old;
58
}
59
#endif
60
#ifdef CONFIG_TSAN
61
@@ -XXX,XX +XXX,XX @@ static void coroutine_trampoline(int i0, int i1)
62
63
/* Initialize longjmp environment and switch back the caller */
64
if (!sigsetjmp(self->env, 0)) {
65
- start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save, leader.stack,
66
- leader.stack_size);
67
+ CoroutineUContext *leaderp = get_ptr_leader();
38
+
68
+
39
/**
69
+ start_switch_fiber_asan(COROUTINE_YIELD, &fake_stack_save,
40
* user_creatable_add_opts:
70
+ leaderp->stack, leaderp->stack_size);
41
* @opts: the object definition
71
start_switch_fiber_tsan(&fake_stack_save, self, true); /* true=caller */
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
72
siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
43
index XXXXXXX..XXXXXXX 100644
73
}
44
--- a/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
45
+++ b/qom/object_interfaces.c
75
int ret;
46
@@ -XXX,XX +XXX,XX @@
76
void *fake_stack_save = NULL;
47
#include "qapi/qmp/qerror.h"
77
48
#include "qapi/qmp/qjson.h"
78
- current = to_;
49
#include "qapi/qmp/qstring.h"
79
+ set_current(to_);
50
+#include "qapi/qobject-input-visitor.h"
80
51
#include "qom/object_interfaces.h"
81
ret = sigsetjmp(from->env, 0);
52
#include "qemu/help_option.h"
82
if (ret == 0) {
53
#include "qemu/module.h"
83
@@ -XXX,XX +XXX,XX @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
54
@@ -XXX,XX +XXX,XX @@ out:
84
55
return obj;
85
Coroutine *qemu_coroutine_self(void)
86
{
87
- if (!current) {
88
- current = &leader.base;
89
+ Coroutine *self = get_current();
90
+ CoroutineUContext *leaderp = get_ptr_leader();
91
+
92
+ if (!self) {
93
+ self = &leaderp->base;
94
+ set_current(self);
95
}
96
#ifdef CONFIG_TSAN
97
- if (!leader.tsan_co_fiber) {
98
- leader.tsan_co_fiber = __tsan_get_current_fiber();
99
+ if (!leaderp->tsan_co_fiber) {
100
+ leaderp->tsan_co_fiber = __tsan_get_current_fiber();
101
}
102
#endif
103
- return current;
104
+ return self;
56
}
105
}
57
106
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
107
bool qemu_in_coroutine(void)
59
+{
108
{
60
+ Visitor *v;
109
- return current && current->caller;
61
+ Object *obj;
110
+ Coroutine *self = get_current();
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
64
+
111
+
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
112
+ return self && self->caller;
66
+ if (!type) {
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
86
{
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
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
}
127
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
130
- visit_free(v);
131
- object_unref(obj);
132
+ user_creatable_add_dict(qdict, errp);
133
}
113
}
134
135
void qmp_object_del(const char *id, Error **errp)
136
--
114
--
137
2.25.3
115
2.35.1
138
116
139
117
diff view generated by jsdifflib
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
1
From: Stefan Hajnoczi <stefanha@redhat.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
Thread-Local Storage variables cannot be used directly from coroutine
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
code because the compiler may optimize TLS variable accesses across
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
qemu_coroutine_yield() calls. When the coroutine is re-entered from
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
another thread the TLS variables from the old thread must no longer be
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
7
used.
8
9
Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables.
10
The alloc_pool QSLIST needs a typedef so the return value of
11
get_ptr_alloc_pool() can be stored in a local variable.
12
13
One example of why this code is necessary: a coroutine that yields
14
before calling qemu_coroutine_create() to create another coroutine is
15
affected by the TLS issue.
16
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Message-Id: <20220307153853.602859-3-stefanha@redhat.com>
19
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
21
---
12
include/block/block.h | 5 +++--
22
util/qemu-coroutine.c | 41 ++++++++++++++++++++++++-----------------
13
block/block-backend.c | 2 +-
23
1 file changed, 24 insertions(+), 17 deletions(-)
14
block/crypto.c | 2 +-
15
block/io.c | 12 +++++++-----
16
block/parallels.c | 6 +++---
17
block/qcow.c | 4 ++--
18
block/qcow2-refcount.c | 2 +-
19
block/qcow2.c | 15 +++++++++------
20
block/raw-format.c | 2 +-
21
block/vhdx-log.c | 2 +-
22
block/vhdx.c | 2 +-
23
block/vmdk.c | 2 +-
24
tests/test-block-iothread.c | 6 +++---
25
13 files changed, 34 insertions(+), 28 deletions(-)
26
24
27
diff --git a/include/block/block.h b/include/block/block.h
25
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
28
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block.h
27
--- a/util/qemu-coroutine.c
30
+++ b/include/block/block.h
28
+++ b/util/qemu-coroutine.c
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
29
@@ -XXX,XX +XXX,XX @@
32
void bdrv_refresh_filename(BlockDriverState *bs);
30
#include "qemu/atomic.h"
33
31
#include "qemu/coroutine.h"
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
32
#include "qemu/coroutine_int.h"
35
- PreallocMode prealloc, Error **errp);
33
+#include "qemu/coroutine-tls.h"
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
34
#include "block/aio.h"
37
+ Error **errp);
35
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
36
/** Initial batch size is 64, and is increased on demand */
39
- PreallocMode prealloc, Error **errp);
37
@@ -XXX,XX +XXX,XX @@ enum {
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
38
static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool);
41
39
static unsigned int pool_batch_size = POOL_INITIAL_BATCH_SIZE;
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
40
static unsigned int release_pool_size;
43
int64_t bdrv_getlength(BlockDriverState *bs);
41
-static __thread QSLIST_HEAD(, Coroutine) alloc_pool = QSLIST_HEAD_INITIALIZER(pool);
44
diff --git a/block/block-backend.c b/block/block-backend.c
42
-static __thread unsigned int alloc_pool_size;
45
index XXXXXXX..XXXXXXX 100644
43
-static __thread Notifier coroutine_pool_cleanup_notifier;
46
--- a/block/block-backend.c
44
+
47
+++ b/block/block-backend.c
45
+typedef QSLIST_HEAD(, Coroutine) CoroutineQSList;
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
46
+QEMU_DEFINE_STATIC_CO_TLS(CoroutineQSList, alloc_pool);
49
return -ENOMEDIUM;
47
+QEMU_DEFINE_STATIC_CO_TLS(unsigned int, alloc_pool_size);
50
}
48
+QEMU_DEFINE_STATIC_CO_TLS(Notifier, coroutine_pool_cleanup_notifier);
51
49
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
50
static void coroutine_pool_cleanup(Notifier *n, void *value)
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
54
}
55
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
60
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
62
63
offset += payload_offset;
64
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
}
68
69
static void block_crypto_close(BlockDriverState *bs)
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
{
51
{
119
Coroutine *co;
52
Coroutine *co;
120
TruncateCo tco = {
53
Coroutine *tmp;
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
54
+ CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
122
.offset = offset,
55
123
.exact = exact,
56
- QSLIST_FOREACH_SAFE(co, &alloc_pool, pool_next, tmp) {
124
.prealloc = prealloc,
57
- QSLIST_REMOVE_HEAD(&alloc_pool, pool_next);
125
+ .flags = flags,
58
+ QSLIST_FOREACH_SAFE(co, alloc_pool, pool_next, tmp) {
126
.errp = errp,
59
+ QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
127
.ret = NOT_DONE,
60
qemu_coroutine_delete(co);
128
};
61
}
129
diff --git a/block/parallels.c b/block/parallels.c
62
}
130
index XXXXXXX..XXXXXXX 100644
63
@@ -XXX,XX +XXX,XX @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque)
131
--- a/block/parallels.c
64
Coroutine *co = NULL;
132
+++ b/block/parallels.c
65
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
66
if (CONFIG_COROUTINE_POOL) {
134
} else {
67
- co = QSLIST_FIRST(&alloc_pool);
135
ret = bdrv_truncate(bs->file,
68
+ CoroutineQSList *alloc_pool = get_ptr_alloc_pool();
136
(s->data_end + space) << BDRV_SECTOR_BITS,
69
+
137
- false, PREALLOC_MODE_OFF, NULL);
70
+ co = QSLIST_FIRST(alloc_pool);
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
71
if (!co) {
72
if (release_pool_size > qatomic_read(&pool_batch_size)) {
73
/* Slow path; a good place to register the destructor, too. */
74
- if (!coroutine_pool_cleanup_notifier.notify) {
75
- coroutine_pool_cleanup_notifier.notify = coroutine_pool_cleanup;
76
- qemu_thread_atexit_add(&coroutine_pool_cleanup_notifier);
77
+ Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier();
78
+ if (!notifier->notify) {
79
+ notifier->notify = coroutine_pool_cleanup;
80
+ qemu_thread_atexit_add(notifier);
81
}
82
83
/* This is not exact; there could be a little skew between
84
* release_pool_size and the actual size of release_pool. But
85
* it is just a heuristic, it does not need to be perfect.
86
*/
87
- alloc_pool_size = qatomic_xchg(&release_pool_size, 0);
88
- QSLIST_MOVE_ATOMIC(&alloc_pool, &release_pool);
89
- co = QSLIST_FIRST(&alloc_pool);
90
+ set_alloc_pool_size(qatomic_xchg(&release_pool_size, 0));
91
+ QSLIST_MOVE_ATOMIC(alloc_pool, &release_pool);
92
+ co = QSLIST_FIRST(alloc_pool);
93
}
139
}
94
}
140
if (ret < 0) {
95
if (co) {
141
return ret;
96
- QSLIST_REMOVE_HEAD(&alloc_pool, pool_next);
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
97
- alloc_pool_size--;
143
* That means we have to pass exact=true.
98
+ QSLIST_REMOVE_HEAD(alloc_pool, pool_next);
144
*/
99
+ set_alloc_pool_size(get_alloc_pool_size() - 1);
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
100
}
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
}
101
}
158
102
159
g_free(s->bat_dirty_bmap);
103
@@ -XXX,XX +XXX,XX @@ static void coroutine_delete(Coroutine *co)
160
diff --git a/block/qcow.c b/block/qcow.c
104
qatomic_inc(&release_pool_size);
161
index XXXXXXX..XXXXXXX 100644
105
return;
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
}
106
}
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
107
- if (alloc_pool_size < qatomic_read(&pool_batch_size)) {
203
- mode, errp);
108
- QSLIST_INSERT_HEAD(&alloc_pool, co, pool_next);
204
+ mode, 0, errp);
109
- alloc_pool_size++;
205
if (ret < 0) {
110
+ if (get_alloc_pool_size() < qatomic_read(&pool_batch_size)) {
206
return ret;
111
+ QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next);
112
+ set_alloc_pool_size(get_alloc_pool_size() + 1);
113
return;
207
}
114
}
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
}
115
}
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
--
116
--
335
2.25.3
117
2.35.1
336
118
337
119
diff view generated by jsdifflib
1
The raw format driver can simply forward the flag and let its bs->file
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
child take care of actually providing the zeros.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
Thread-Local Storage variables cannot be used directly from coroutine
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
code because the compiler may optimize TLS variable accesses across
6
Reviewed-by: Eric Blake <eblake@redhat.com>
5
qemu_coroutine_yield() calls. When the coroutine is re-entered from
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
another thread the TLS variables from the old thread must no longer be
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
7
used.
8
9
Use QEMU_DEFINE_STATIC_CO_TLS() for the current and leader variables.
10
11
I think coroutine-win32.c could get away with __thread because the
12
variables are only used in situations where either the stale value is
13
correct (current) or outside coroutine context (loading leader when
14
current is NULL). Due to the difficulty of being sure that this is
15
really safe in all scenarios it seems worth converting it anyway.
16
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Message-Id: <20220307153853.602859-4-stefanha@redhat.com>
19
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
21
---
11
block/raw-format.c | 4 +++-
22
util/coroutine-win32.c | 18 +++++++++++++-----
12
1 file changed, 3 insertions(+), 1 deletion(-)
23
1 file changed, 13 insertions(+), 5 deletions(-)
13
24
14
diff --git a/block/raw-format.c b/block/raw-format.c
25
diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c
15
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
16
--- a/block/raw-format.c
27
--- a/util/coroutine-win32.c
17
+++ b/block/raw-format.c
28
+++ b/util/coroutine-win32.c
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
29
@@ -XXX,XX +XXX,XX @@
19
30
20
s->size = offset;
31
#include "qemu/osdep.h"
21
offset += s->offset;
32
#include "qemu/coroutine_int.h"
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
33
+#include "qemu/coroutine-tls.h"
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
34
35
typedef struct
36
{
37
@@ -XXX,XX +XXX,XX @@ typedef struct
38
CoroutineAction action;
39
} CoroutineWin32;
40
41
-static __thread CoroutineWin32 leader;
42
-static __thread Coroutine *current;
43
+QEMU_DEFINE_STATIC_CO_TLS(CoroutineWin32, leader);
44
+QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
45
46
/* This function is marked noinline to prevent GCC from inlining it
47
* into coroutine_trampoline(). If we allow it to do that then it
48
@@ -XXX,XX +XXX,XX @@ qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
49
CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
50
CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
51
52
- current = to_;
53
+ set_current(to_);
54
55
to->action = action;
56
SwitchToFiber(to->fiber);
57
@@ -XXX,XX +XXX,XX @@ void qemu_coroutine_delete(Coroutine *co_)
58
59
Coroutine *qemu_coroutine_self(void)
60
{
61
+ Coroutine *current = get_current();
62
+
63
if (!current) {
64
- current = &leader.base;
65
- leader.fiber = ConvertThreadToFiber(NULL);
66
+ CoroutineWin32 *leader = get_ptr_leader();
67
+
68
+ current = &leader->base;
69
+ set_current(current);
70
+ leader->fiber = ConvertThreadToFiber(NULL);
71
}
72
return current;
24
}
73
}
25
74
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
75
bool qemu_in_coroutine(void)
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
76
{
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
77
+ Coroutine *current = get_current();
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
78
+
30
bs->file->bs->supported_zero_flags);
79
return current && current->caller;
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
80
}
32
+ BDRV_REQ_ZERO_WRITE;
33
34
if (bs->probed && !bdrv_is_read_only(bs)) {
35
bdrv_refresh_filename(bs->file->bs);
36
--
81
--
37
2.25.3
82
2.35.1
38
83
39
84
diff view generated by jsdifflib
Deleted patch
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
OS, so we can advertise the flag and just ignore it.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/file-posix.c | 4 ++++
12
1 file changed, 4 insertions(+)
13
14
diff --git a/block/file-posix.c b/block/file-posix.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/file-posix.c
17
+++ b/block/file-posix.c
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
19
#endif
20
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
22
+ if (S_ISREG(st.st_mode)) {
23
+ /* When extending regular files, we get zeros from the OS */
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
25
+ }
26
ret = 0;
27
fail:
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
29
--
30
2.25.3
31
32
diff view generated by jsdifflib