1
The following changes since commit a26a98dfb9d448d7234d931ae3720feddf6f0651:
1
The following changes since commit 9a7beaad3dbba982f7a461d676b55a5c3851d312:
2
2
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20171006' into staging (2017-10-06 13:19:03 +0100)
3
Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20210304' into staging (2021-03-05 10:47:46 +0000)
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 fc3fd63fc0573ffd2ee569591a2e7f6c7310fd18:
9
for you to fetch changes up to 67bedc3aed5c455b629c2cb5f523b536c46adff9:
10
10
11
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-06' into queue-block (2017-10-06 16:32:08 +0200)
11
docs: qsd: Explain --export nbd,name=... default (2021-03-05 17:09:46 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches:
15
16
- qemu-storage-daemon: add --pidfile option
17
- qemu-storage-daemon: CLI error messages include the option name now
18
- vhost-user-blk export: Misc fixes, added test cases
19
- docs: Improvements for qemu-storage-daemon documentation
20
- parallels: load bitmap extension
21
- backup-top: Don't crash on post-finalize accesses
22
- iotests improvements
15
23
16
----------------------------------------------------------------
24
----------------------------------------------------------------
17
Daniel P. Berrange (6):
25
Alberto Garcia (1):
18
block: use 1 MB bounce buffers for crypto instead of 16KB
26
iotests: Drop deprecated 'props' from object-add
19
crypto: expose encryption sector size in APIs
20
block: fix data type casting for crypto payload offset
21
block: convert crypto driver to bdrv_co_preadv|pwritev
22
block: convert qcrypto_block_encrypt|decrypt to take bytes offset
23
block: support passthrough of BDRV_REQ_FUA in crypto driver
24
27
25
Eric Blake (27):
28
Coiby Xu (1):
26
block: Typo fix in copy_on_readv()
29
test: new qTest case to test the vhost-user-blk-server
27
block: Make bdrv_img_create() size selection easier to read
28
hbitmap: Rename serialization_granularity to serialization_align
29
qcow2: Ensure bitmap serialization is aligned
30
dirty-bitmap: Drop unused functions
31
dirty-bitmap: Avoid size query failure during truncate
32
dirty-bitmap: Change bdrv_dirty_bitmap_size() to report bytes
33
dirty-bitmap: Track bitmap size by bytes
34
dirty-bitmap: Change bdrv_dirty_bitmap_*serialize*() to take bytes
35
qcow2: Switch sectors_covered_by_bitmap_cluster() to byte-based
36
dirty-bitmap: Set iterator start by offset, not sector
37
dirty-bitmap: Change bdrv_dirty_iter_next() to report byte offset
38
dirty-bitmap: Change bdrv_get_dirty_count() to report bytes
39
dirty-bitmap: Change bdrv_get_dirty_locked() to take bytes
40
dirty-bitmap: Change bdrv_[re]set_dirty_bitmap() to use bytes
41
mirror: Switch mirror_dirty_init() to byte-based iteration
42
qcow2: Switch qcow2_measure() to byte-based iteration
43
qcow2: Switch load_bitmap_data() to byte-based iteration
44
qcow2: Switch store_bitmap_data() to byte-based iteration
45
dirty-bitmap: Switch bdrv_set_dirty() to bytes
46
dirty-bitmap: Convert internal hbitmap size/granularity
47
qemu-io: Add -C for opening with copy-on-read
48
block: Uniform handling of 0-length bdrv_get_block_status()
49
iotests: Restore stty settings on completion
50
block: Add blkdebug hook for copy-on-read
51
block: Perform copy-on-read in loop
52
iotests: Add test 197 for covering copy-on-read
53
30
54
Kevin Wolf (6):
31
Eric Blake (1):
55
block: Introduce BdrvChildRole.update_filename
32
iotests: Fix up python style in 300
56
commit: Support multiple roots above top node
57
qemu-iotests: Allow QMP pretty printing in common.qemu
58
qemu-iotests: Test commit block job where top has two parents
59
commit: Remove overlay_bs
60
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-06' into queue-block
61
33
62
Max Reitz (1):
34
Kevin Wolf (1):
63
iotests: Fix 195 if IMGFMT is part of TEST_DIR
35
docs: qsd: Explain --export nbd,name=... default
64
36
65
Paolo Bonzini (10):
37
Max Reitz (3):
66
qemu-iotests: remove dead code
38
backup: Remove nodes from job in .clean()
67
qemu-iotests: get rid of AWK_PROG
39
backup-top: Refuse I/O in inactive state
68
qemu-iotests: move "check" code out of common.rc
40
iotests/283: Check that finalize drops backup-top
69
qemu-iotests: cleanup and fix search for programs
70
qemu-iotests: limit non-_PROG-suffixed variables to common.rc
71
qemu-iotests: do not include common.rc in "check"
72
qemu-iotests: disintegrate more parts of common.config
73
qemu-iotests: fix uninitialized variable
74
qemu-iotests: get rid of $iam
75
qemu-iotests: merge "check" and "common"
76
41
77
Pavel Butsykin (2):
42
Paolo Bonzini (2):
78
qcow2: fix return error code in qcow2_truncate()
43
storage-daemon: report unexpected arguments on the fly
79
qcow2: truncate the tail of the image file after shrinking the image
44
storage-daemon: include current command line option in the errors
80
45
81
Thomas Huth (1):
46
Stefan Hajnoczi (14):
82
hw/block/onenand: Remove dead code block
47
qemu-storage-daemon: add --pidfile option
48
docs: show how to spawn qemu-storage-daemon with fd passing
49
docs: replace insecure /tmp examples in qsd docs
50
vhost-user-blk: fix blkcfg->num_queues endianness
51
libqtest: add qtest_socket_server()
52
libqtest: add qtest_kill_qemu()
53
libqtest: add qtest_remove_abrt_handler()
54
tests/qtest: add multi-queue test case to vhost-user-blk-test
55
block/export: fix blk_size double byteswap
56
block/export: use VIRTIO_BLK_SECTOR_BITS
57
block/export: fix vhost-user-blk export sector number calculation
58
block/export: port virtio-blk discard/write zeroes input validation
59
vhost-user-blk-test: test discard/write zeroes invalid inputs
60
block/export: port virtio-blk read/write range check
83
61
84
Vladimir Sementsov-Ogievskiy (2):
62
Stefano Garzarella (1):
85
block/mirror: check backing in bdrv_mirror_top_refresh_filename
63
blockjob: report a better error message
86
block/mirror: check backing in bdrv_mirror_top_flush
87
64
88
qapi/block-core.json | 5 +-
65
Vladimir Sementsov-Ogievskiy (7):
89
block/qcow2.h | 1 +
66
qcow2-bitmap: make bytes_covered_by_bitmap_cluster() public
90
crypto/blockpriv.h | 5 +-
67
parallels.txt: fix bitmap L1 table description
91
include/block/block.h | 3 +-
68
block/parallels: BDRVParallelsState: add cluster_size field
92
include/block/block_int.h | 8 +-
69
parallels: support bitmap extension for read-only mode
93
include/block/dirty-bitmap.h | 43 +-
70
iotests.py: add unarchive_sample_image() helper
94
include/crypto/block.h | 29 +-
71
iotests: add parallels-read-bitmap test
95
include/qemu/hbitmap.h | 8 +-
72
MAINTAINERS: update parallels block driver
96
block.c | 109 ++++--
97
block/backup.c | 7 +-
98
block/commit.c | 64 +--
99
block/crypto.c | 130 +++---
100
block/dirty-bitmap.c | 134 ++-----
101
block/io.c | 131 +++++--
102
block/mirror.c | 88 ++---
103
block/qcow.c | 11 +-
104
block/qcow2-bitmap.c | 62 +--
105
block/qcow2-cluster.c | 8 +-
106
block/qcow2-refcount.c | 22 ++
107
block/qcow2.c | 53 ++-
108
crypto/block-luks.c | 18 +-
109
crypto/block-qcow.c | 13 +-
110
crypto/block.c | 26 +-
111
hw/block/onenand.c | 4 -
112
migration/block.c | 12 +-
113
qemu-io.c | 15 +-
114
tests/test-hbitmap.c | 10 +-
115
util/hbitmap.c | 8 +-
116
tests/qemu-iotests/030 | 4 -
117
tests/qemu-iotests/039.out | 10 +-
118
tests/qemu-iotests/061.out | 4 +-
119
tests/qemu-iotests/137.out | 2 +-
120
tests/qemu-iotests/165 | 2 +-
121
tests/qemu-iotests/191 | 153 ++++++++
122
tests/qemu-iotests/191.out | 827 +++++++++++++++++++++++++++++++++++++++
123
tests/qemu-iotests/195 | 7 +-
124
tests/qemu-iotests/197 | 109 ++++++
125
tests/qemu-iotests/197.out | 26 ++
126
tests/qemu-iotests/check | 585 ++++++++++++++++++++++++---
127
tests/qemu-iotests/common | 459 ----------------------
128
tests/qemu-iotests/common.config | 206 +---------
129
tests/qemu-iotests/common.filter | 1 +
130
tests/qemu-iotests/common.qemu | 15 +-
131
tests/qemu-iotests/common.rc | 205 +++++-----
132
tests/qemu-iotests/group | 2 +
133
45 files changed, 2333 insertions(+), 1311 deletions(-)
134
create mode 100755 tests/qemu-iotests/191
135
create mode 100644 tests/qemu-iotests/191.out
136
create mode 100755 tests/qemu-iotests/197
137
create mode 100644 tests/qemu-iotests/197.out
138
delete mode 100644 tests/qemu-iotests/common
139
73
74
docs/interop/parallels.txt | 28 +-
75
docs/tools/qemu-storage-daemon.rst | 68 +-
76
block/parallels.h | 7 +-
77
include/block/dirty-bitmap.h | 2 +
78
tests/qtest/libqos/libqtest.h | 37 +
79
tests/qtest/libqos/vhost-user-blk.h | 48 +
80
block/backup-top.c | 10 +
81
block/backup.c | 1 +
82
block/dirty-bitmap.c | 13 +
83
block/export/vhost-user-blk-server.c | 150 +++-
84
block/parallels-ext.c | 300 +++++++
85
block/parallels.c | 26 +-
86
block/qcow2-bitmap.c | 16 +-
87
blockjob.c | 10 +-
88
hw/block/vhost-user-blk.c | 7 +-
89
storage-daemon/qemu-storage-daemon.c | 56 +-
90
tests/qtest/libqos/vhost-user-blk.c | 130 +++
91
tests/qtest/libqtest.c | 82 +-
92
tests/qtest/vhost-user-blk-test.c | 983 +++++++++++++++++++++
93
tests/qemu-iotests/iotests.py | 10 +
94
MAINTAINERS | 5 +
95
block/meson.build | 3 +-
96
tests/qemu-iotests/087 | 8 +-
97
tests/qemu-iotests/184 | 18 +-
98
tests/qemu-iotests/218 | 2 +-
99
tests/qemu-iotests/235 | 2 +-
100
tests/qemu-iotests/245 | 4 +-
101
tests/qemu-iotests/258 | 6 +-
102
tests/qemu-iotests/258.out | 4 +-
103
tests/qemu-iotests/283 | 53 ++
104
tests/qemu-iotests/283.out | 15 +
105
tests/qemu-iotests/295 | 2 +-
106
tests/qemu-iotests/296 | 2 +-
107
tests/qemu-iotests/300 | 10 +-
108
.../sample_images/parallels-with-bitmap.bz2 | Bin 0 -> 203 bytes
109
.../sample_images/parallels-with-bitmap.sh | 51 ++
110
tests/qemu-iotests/tests/parallels-read-bitmap | 55 ++
111
tests/qemu-iotests/tests/parallels-read-bitmap.out | 6 +
112
tests/qtest/libqos/meson.build | 1 +
113
tests/qtest/meson.build | 4 +
114
40 files changed, 2098 insertions(+), 137 deletions(-)
115
create mode 100644 tests/qtest/libqos/vhost-user-blk.h
116
create mode 100644 block/parallels-ext.c
117
create mode 100644 tests/qtest/libqos/vhost-user-blk.c
118
create mode 100644 tests/qtest/vhost-user-blk-test.c
119
create mode 100644 tests/qemu-iotests/sample_images/parallels-with-bitmap.bz2
120
create mode 100755 tests/qemu-iotests/sample_images/parallels-with-bitmap.sh
121
create mode 100755 tests/qemu-iotests/tests/parallels-read-bitmap
122
create mode 100644 tests/qemu-iotests/tests/parallels-read-bitmap.out
123
124
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Signed-off-by: Eric Blake <eblake@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
block/io.c | 2 +-
7
1 file changed, 1 insertion(+), 1 deletion(-)
8
9
diff --git a/block/io.c b/block/io.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/io.c
12
+++ b/block/io.c
13
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
14
/* FIXME We cannot require callers to have write permissions when all they
15
* are doing is a read request. If we did things right, write permissions
16
* would be obtained anyway, but internally by the copy-on-read code. As
17
- * long as it is implemented here rather than in a separat filter driver,
18
+ * long as it is implemented here rather than in a separate filter driver,
19
* the copy-on-read code doesn't have its own BdrvChild, however, for which
20
* it could request permissions. Therefore we have to bypass the permission
21
* system for the moment. */
22
--
23
2.13.6
24
25
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
All callers of bdrv_img_create() pass in a size, or -1 to read the
4
size from the backing file. We then set that size as the QemuOpt
5
default, which means we will reuse that default rather than the
6
final parameter to qemu_opt_get_size() several lines later. But
7
it is rather confusing to read subsequent checks of 'size == -1'
8
when it looks (without seeing the full context) like size defaults
9
to 0; it also doesn't help that a size of 0 is valid (for some
10
formats).
11
12
Rework the logic to make things more legible.
13
14
Signed-off-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: John Snow <jsnow@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Fam Zheng <famz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
block.c | 2 +-
21
1 file changed, 1 insertion(+), 1 deletion(-)
22
23
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
26
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
28
29
/* The size for the image must always be specified, unless we have a backing
30
* file and we have not been forbidden from opening it. */
31
- size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
32
+ size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size);
33
if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
34
BlockDriverState *bs;
35
char *full_backing = g_new0(char, PATH_MAX);
36
--
37
2.13.6
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
The only client of hbitmap_serialization_granularity() is dirty-bitmap's
4
bdrv_dirty_bitmap_serialization_align(). Keeping the two names consistent
5
is worthwhile, and the shorter name is more representative of what the
6
function returns (the required alignment to be used for start/count of
7
other serialization functions, where violating the alignment causes
8
assertion failures).
9
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
include/qemu/hbitmap.h | 8 ++++----
17
block/dirty-bitmap.c | 2 +-
18
tests/test-hbitmap.c | 10 +++++-----
19
util/hbitmap.c | 8 ++++----
20
4 files changed, 14 insertions(+), 14 deletions(-)
21
22
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/qemu/hbitmap.h
25
+++ b/include/qemu/hbitmap.h
26
@@ -XXX,XX +XXX,XX @@ bool hbitmap_get(const HBitmap *hb, uint64_t item);
27
bool hbitmap_is_serializable(const HBitmap *hb);
28
29
/**
30
- * hbitmap_serialization_granularity:
31
+ * hbitmap_serialization_align:
32
* @hb: HBitmap to operate on.
33
*
34
- * Granularity of serialization chunks, used by other serialization functions.
35
- * For every chunk:
36
+ * Required alignment of serialization chunks, used by other serialization
37
+ * functions. For every chunk:
38
* 1. Chunk start should be aligned to this granularity.
39
* 2. Chunk size should be aligned too, except for last chunk (for which
40
* start + count == hb->size)
41
*/
42
-uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
43
+uint64_t hbitmap_serialization_align(const HBitmap *hb);
44
45
/**
46
* hbitmap_serialization_size:
47
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/dirty-bitmap.c
50
+++ b/block/dirty-bitmap.c
51
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
52
53
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
54
{
55
- return hbitmap_serialization_granularity(bitmap->bitmap);
56
+ return hbitmap_serialization_align(bitmap->bitmap);
57
}
58
59
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
60
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/test-hbitmap.c
63
+++ b/tests/test-hbitmap.c
64
@@ -XXX,XX +XXX,XX @@ static void test_hbitmap_meta_one(TestHBitmapData *data, const void *unused)
65
}
66
}
67
68
-static void test_hbitmap_serialize_granularity(TestHBitmapData *data,
69
- const void *unused)
70
+static void test_hbitmap_serialize_align(TestHBitmapData *data,
71
+ const void *unused)
72
{
73
int r;
74
75
hbitmap_test_init(data, L3 * 2, 3);
76
g_assert(hbitmap_is_serializable(data->hb));
77
78
- r = hbitmap_serialization_granularity(data->hb);
79
+ r = hbitmap_serialization_align(data->hb);
80
g_assert_cmpint(r, ==, 64 << 3);
81
}
82
83
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
84
hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
85
hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
86
87
- hbitmap_test_add("/hbitmap/serialize/granularity",
88
- test_hbitmap_serialize_granularity);
89
+ hbitmap_test_add("/hbitmap/serialize/align",
90
+ test_hbitmap_serialize_align);
91
hbitmap_test_add("/hbitmap/serialize/basic",
92
test_hbitmap_serialize_basic);
93
hbitmap_test_add("/hbitmap/serialize/part",
94
diff --git a/util/hbitmap.c b/util/hbitmap.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/util/hbitmap.c
97
+++ b/util/hbitmap.c
98
@@ -XXX,XX +XXX,XX @@ bool hbitmap_is_serializable(const HBitmap *hb)
99
{
100
/* Every serialized chunk must be aligned to 64 bits so that endianness
101
* requirements can be fulfilled on both 64 bit and 32 bit hosts.
102
- * We have hbitmap_serialization_granularity() which converts this
103
+ * We have hbitmap_serialization_align() which converts this
104
* alignment requirement from bitmap bits to items covered (e.g. sectors).
105
* That value is:
106
* 64 << hb->granularity
107
* Since this value must not exceed UINT64_MAX, hb->granularity must be
108
* less than 58 (== 64 - 6, where 6 is ld(64), i.e. 1 << 6 == 64).
109
*
110
- * In order for hbitmap_serialization_granularity() to always return a
111
+ * In order for hbitmap_serialization_align() to always return a
112
* meaningful value, bitmaps that are to be serialized must have a
113
* granularity of less than 58. */
114
115
@@ -XXX,XX +XXX,XX @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
116
return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
117
}
118
119
-uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
120
+uint64_t hbitmap_serialization_align(const HBitmap *hb)
121
{
122
assert(hbitmap_is_serializable(hb));
123
124
@@ -XXX,XX +XXX,XX @@ static void serialization_chunk(const HBitmap *hb,
125
unsigned long **first_el, uint64_t *el_count)
126
{
127
uint64_t last = start + count - 1;
128
- uint64_t gran = hbitmap_serialization_granularity(hb);
129
+ uint64_t gran = hbitmap_serialization_align(hb);
130
131
assert((start & (gran - 1)) == 0);
132
assert((last >> hb->granularity) < hb->size);
133
--
134
2.13.6
135
136
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
When subdividing a bitmap serialization, the code in hbitmap.c
4
enforces that start/count parameters are aligned (except that
5
count can end early at end-of-bitmap). We exposed this required
6
alignment through bdrv_dirty_bitmap_serialization_align(), but
7
forgot to actually check that we comply with it.
8
9
Fortunately, qcow2 is never dividing bitmap serialization smaller
10
than one cluster (which is a minimum of 512 bytes); so we are
11
always compliant with the serialization alignment (which insists
12
that we partition at least 64 bits per chunk) because we are doing
13
at least 4k bits per chunk.
14
15
Still, it's safer to add an assertion (for the unlikely case that
16
we'd ever support a cluster smaller than 512 bytes, or if the
17
hbitmap implementation changes what it considers to be aligned),
18
rather than leaving bdrv_dirty_bitmap_serialization_align()
19
without a caller.
20
21
Signed-off-by: Eric Blake <eblake@redhat.com>
22
Reviewed-by: John Snow <jsnow@redhat.com>
23
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
24
Reviewed-by: Fam Zheng <famz@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
27
block/qcow2-bitmap.c | 7 +++++--
28
1 file changed, 5 insertions(+), 2 deletions(-)
29
30
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2-bitmap.c
33
+++ b/block/qcow2-bitmap.c
34
@@ -XXX,XX +XXX,XX @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
35
static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
36
const BdrvDirtyBitmap *bitmap)
37
{
38
- uint32_t sector_granularity =
39
+ uint64_t sector_granularity =
40
bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
41
+ uint64_t sbc = sector_granularity * (s->cluster_size << 3);
42
43
- return (uint64_t)sector_granularity * (s->cluster_size << 3);
44
+ assert(QEMU_IS_ALIGNED(sbc,
45
+ bdrv_dirty_bitmap_serialization_align(bitmap)));
46
+ return sbc;
47
}
48
49
/* load_bitmap_data
50
--
51
2.13.6
52
53
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
We had several functions that no one is currently using, and which
4
use sector-based interfaces. I'm trying to convert towards byte-based
5
interfaces, so it's easier to just drop the unused functions:
6
7
bdrv_dirty_bitmap_get_meta
8
bdrv_dirty_bitmap_get_meta_locked
9
bdrv_dirty_bitmap_reset_meta
10
bdrv_dirty_bitmap_meta_granularity
11
12
Signed-off-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: John Snow <jsnow@redhat.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Fam Zheng <famz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
18
include/block/dirty-bitmap.h | 10 ----------
19
block/dirty-bitmap.c | 44 --------------------------------------------
20
2 files changed, 54 deletions(-)
21
22
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/dirty-bitmap.h
25
+++ b/include/block/dirty-bitmap.h
26
@@ -XXX,XX +XXX,XX @@ void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
27
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
28
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
29
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
30
-uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
31
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
32
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
33
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
34
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
35
int64_t cur_sector, int64_t nr_sectors);
36
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
37
int64_t cur_sector, int64_t nr_sectors);
38
-int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
39
- BdrvDirtyBitmap *bitmap, int64_t sector,
40
- int nb_sectors);
41
-int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
42
- BdrvDirtyBitmap *bitmap, int64_t sector,
43
- int nb_sectors);
44
-void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
45
- BdrvDirtyBitmap *bitmap, int64_t sector,
46
- int nb_sectors);
47
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
48
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
49
uint64_t first_sector);
50
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/dirty-bitmap.c
53
+++ b/block/dirty-bitmap.c
54
@@ -XXX,XX +XXX,XX @@ void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
55
qemu_mutex_unlock(bitmap->mutex);
56
}
57
58
-int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
59
- BdrvDirtyBitmap *bitmap, int64_t sector,
60
- int nb_sectors)
61
-{
62
- uint64_t i;
63
- int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta);
64
-
65
- /* To optimize: we can make hbitmap to internally check the range in a
66
- * coarse level, or at least do it word by word. */
67
- for (i = sector; i < sector + nb_sectors; i += sectors_per_bit) {
68
- if (hbitmap_get(bitmap->meta, i)) {
69
- return true;
70
- }
71
- }
72
- return false;
73
-}
74
-
75
-int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
76
- BdrvDirtyBitmap *bitmap, int64_t sector,
77
- int nb_sectors)
78
-{
79
- bool dirty;
80
-
81
- qemu_mutex_lock(bitmap->mutex);
82
- dirty = bdrv_dirty_bitmap_get_meta_locked(bs, bitmap, sector, nb_sectors);
83
- qemu_mutex_unlock(bitmap->mutex);
84
-
85
- return dirty;
86
-}
87
-
88
-void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
89
- BdrvDirtyBitmap *bitmap, int64_t sector,
90
- int nb_sectors)
91
-{
92
- qemu_mutex_lock(bitmap->mutex);
93
- hbitmap_reset(bitmap->meta, sector, nb_sectors);
94
- qemu_mutex_unlock(bitmap->mutex);
95
-}
96
-
97
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
98
{
99
return bitmap->size;
100
@@ -XXX,XX +XXX,XX @@ uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
101
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
102
}
103
104
-uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
105
-{
106
- return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->meta);
107
-}
108
-
109
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
110
uint64_t first_sector)
111
{
112
--
113
2.13.6
114
115
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
We've previously fixed several places where we failed to account
4
for possible errors from bdrv_nb_sectors(). Fix another one by
5
making bdrv_dirty_bitmap_truncate() take the new size from the
6
caller instead of querying itself; then adjust the sole caller
7
bdrv_truncate() to pass the size just determined by a successful
8
resize, or to reuse the size given to the original truncate
9
operation when refresh_total_sectors() was not able to confirm the
10
actual size (the two sizes can potentially differ according to
11
rounding constraints), thus avoiding sizing the bitmaps to -1.
12
This also fixes a bug where not all failure paths in
13
bdrv_truncate() would set errp.
14
15
Note that bdrv_truncate() is still a bit awkward. We may want
16
to revisit it later and clean up things to better guarantee that
17
a resize attempt either fails cleanly up front, or cannot fail
18
after guest-visible changes have been made (if temporary changes
19
are made, then they need to be cleanly rolled back). But that
20
is a task for another day; for now, the goal is the bare minimum
21
fix to ensure that just bdrv_dirty_bitmap_truncate() cannot fail.
22
23
Signed-off-by: Eric Blake <eblake@redhat.com>
24
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
25
Reviewed-by: John Snow <jsnow@redhat.com>
26
Reviewed-by: Fam Zheng <famz@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
---
29
include/block/dirty-bitmap.h | 2 +-
30
block.c | 16 +++++++++++-----
31
block/dirty-bitmap.c | 6 +++---
32
3 files changed, 15 insertions(+), 9 deletions(-)
33
34
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
35
index XXXXXXX..XXXXXXX 100644
36
--- a/include/block/dirty-bitmap.h
37
+++ b/include/block/dirty-bitmap.h
38
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
39
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
40
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
41
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
42
-void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
43
+void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
44
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
45
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
46
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
47
diff --git a/block.c b/block.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block.c
50
+++ b/block.c
51
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
52
assert(!(bs->open_flags & BDRV_O_INACTIVE));
53
54
ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
55
- if (ret == 0) {
56
- ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
57
- bdrv_dirty_bitmap_truncate(bs);
58
- bdrv_parent_cb_resize(bs);
59
- atomic_inc(&bs->write_gen);
60
+ if (ret < 0) {
61
+ return ret;
62
+ }
63
+ ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
64
+ if (ret < 0) {
65
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
66
+ } else {
67
+ offset = bs->total_sectors * BDRV_SECTOR_SIZE;
68
}
69
+ bdrv_dirty_bitmap_truncate(bs, offset);
70
+ bdrv_parent_cb_resize(bs);
71
+ atomic_inc(&bs->write_gen);
72
return ret;
73
}
74
75
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/dirty-bitmap.c
78
+++ b/block/dirty-bitmap.c
79
@@ -XXX,XX +XXX,XX @@
80
/*
81
* Block Dirty Bitmap
82
*
83
- * Copyright (c) 2016 Red Hat. Inc
84
+ * Copyright (c) 2016-2017 Red Hat. Inc
85
*
86
* Permission is hereby granted, free of charge, to any person obtaining a copy
87
* of this software and associated documentation files (the "Software"), to deal
88
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
89
* Truncates _all_ bitmaps attached to a BDS.
90
* Called with BQL taken.
91
*/
92
-void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
93
+void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
94
{
95
BdrvDirtyBitmap *bitmap;
96
- uint64_t size = bdrv_nb_sectors(bs);
97
+ int64_t size = DIV_ROUND_UP(bytes, BDRV_SECTOR_SIZE);
98
99
bdrv_dirty_bitmaps_lock(bs);
100
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
101
--
102
2.13.6
103
104
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
The condition of the for-loop makes sure that b is always smaller
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
than s->blocks, so the "if (b >= s->blocks)" statement is completely
4
Message-Id: <20210222115737.2993-1-berto@igalia.com>
5
superfluous here.
6
7
Buglink: https://bugs.launchpad.net/qemu/+bug/1715007
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
6
---
12
hw/block/onenand.c | 4 ----
7
tests/qemu-iotests/087 | 8 ++------
13
1 file changed, 4 deletions(-)
8
tests/qemu-iotests/184 | 18 ++++++------------
14
9
tests/qemu-iotests/218 | 2 +-
15
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
10
tests/qemu-iotests/235 | 2 +-
11
tests/qemu-iotests/245 | 4 ++--
12
tests/qemu-iotests/258 | 6 +++---
13
tests/qemu-iotests/258.out | 4 ++--
14
tests/qemu-iotests/295 | 2 +-
15
tests/qemu-iotests/296 | 2 +-
16
9 files changed, 19 insertions(+), 29 deletions(-)
17
18
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/087
21
+++ b/tests/qemu-iotests/087
22
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
23
"arguments": {
24
"qom-type": "secret",
25
"id": "sec0",
26
- "props": {
27
- "data": "123456"
28
- }
29
+ "data": "123456"
30
}
31
}
32
{ "execute": "blockdev-add",
33
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
34
"arguments": {
35
"qom-type": "secret",
36
"id": "sec0",
37
- "props": {
38
- "data": "123456"
39
- }
40
+ "data": "123456"
41
}
42
}
43
{ "execute": "blockdev-add",
44
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
45
index XXXXXXX..XXXXXXX 100755
46
--- a/tests/qemu-iotests/184
47
+++ b/tests/qemu-iotests/184
48
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
49
"arguments": {
50
"qom-type": "throttle-group",
51
"id": "group0",
52
- "props": {
53
- "limits" : {
54
- "iops-total": 1000
55
- }
56
+ "limits" : {
57
+ "iops-total": 1000
58
}
59
}
60
}
61
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
62
"arguments": {
63
"qom-type": "throttle-group",
64
"id": "group0",
65
- "props" : {
66
- "limits": {
67
- "iops-total": 1000
68
- }
69
+ "limits": {
70
+ "iops-total": 1000
71
}
72
}
73
}
74
@@ -XXX,XX +XXX,XX @@ run_qemu <<EOF
75
"arguments": {
76
"qom-type": "throttle-group",
77
"id": "group0",
78
- "props" : {
79
- "limits": {
80
- "iops-total": 1000
81
- }
82
+ "limits": {
83
+ "iops-total": 1000
84
}
85
}
86
}
87
diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218
88
index XXXXXXX..XXXXXXX 100755
89
--- a/tests/qemu-iotests/218
90
+++ b/tests/qemu-iotests/218
91
@@ -XXX,XX +XXX,XX @@ with iotests.VM() as vm, \
92
vm.launch()
93
94
ret = vm.qmp('object-add', qom_type='throttle-group', id='tg',
95
- props={'x-bps-read': 4096})
96
+ limits={'bps-read': 4096})
97
assert ret['return'] == {}
98
99
ret = vm.qmp('blockdev-add',
100
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
101
index XXXXXXX..XXXXXXX 100755
102
--- a/tests/qemu-iotests/235
103
+++ b/tests/qemu-iotests/235
104
@@ -XXX,XX +XXX,XX @@ vm.add_args('-drive', 'id=src,file=' + disk)
105
vm.launch()
106
107
log(vm.qmp('object-add', qom_type='throttle-group', id='tg0',
108
- props={ 'x-bps-total': size }))
109
+ limits={'bps-total': size}))
110
111
log(vm.qmp('blockdev-add',
112
**{ 'node-name': 'target',
113
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
114
index XXXXXXX..XXXXXXX 100755
115
--- a/tests/qemu-iotests/245
116
+++ b/tests/qemu-iotests/245
117
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
118
###### throttle ######
119
######################
120
opts = { 'qom-type': 'throttle-group', 'id': 'group0',
121
- 'props': { 'limits': { 'iops-total': 1000 } } }
122
+ 'limits': { 'iops-total': 1000 } }
123
result = self.vm.qmp('object-add', conv_keys = False, **opts)
124
self.assert_qmp(result, 'return', {})
125
126
opts = { 'qom-type': 'throttle-group', 'id': 'group1',
127
- 'props': { 'limits': { 'iops-total': 2000 } } }
128
+ 'limits': { 'iops-total': 2000 } }
129
result = self.vm.qmp('object-add', conv_keys = False, **opts)
130
self.assert_qmp(result, 'return', {})
131
132
diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258
133
index XXXXXXX..XXXXXXX 100755
134
--- a/tests/qemu-iotests/258
135
+++ b/tests/qemu-iotests/258
136
@@ -XXX,XX +XXX,XX @@ def test_concurrent_finish(write_to_stream_node):
137
vm.qmp_log('object-add',
138
qom_type='throttle-group',
139
id='tg',
140
- props={
141
- 'x-iops-write': 1,
142
- 'x-iops-write-max': 1
143
+ limits={
144
+ 'iops-write': 1,
145
+ 'iops-write-max': 1
146
})
147
148
vm.qmp_log('blockdev-add',
149
diff --git a/tests/qemu-iotests/258.out b/tests/qemu-iotests/258.out
16
index XXXXXXX..XXXXXXX 100644
150
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/block/onenand.c
151
--- a/tests/qemu-iotests/258.out
18
+++ b/hw/block/onenand.c
152
+++ b/tests/qemu-iotests/258.out
19
@@ -XXX,XX +XXX,XX @@ static void onenand_command(OneNANDState *s)
153
@@ -XXX,XX +XXX,XX @@ Running tests:
20
s->intstatus |= ONEN_INT;
154
21
155
=== Commit and stream finish concurrently (letting stream write) ===
22
for (b = 0; b < s->blocks; b ++) {
156
23
- if (b >= s->blocks) {
157
-{"execute": "object-add", "arguments": {"id": "tg", "props": {"x-iops-write": 1, "x-iops-write-max": 1}, "qom-type": "throttle-group"}}
24
- s->status |= ONEN_ERR_CMD;
158
+{"execute": "object-add", "arguments": {"id": "tg", "limits": {"iops-write": 1, "iops-write-max": 1}, "qom-type": "throttle-group"}}
25
- break;
159
{"return": {}}
26
- }
160
{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"backing": {"driver": "raw", "file": {"driver": "file", "filename": "TEST_DIR/PID-node0.img"}, "node-name": "node0"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node1.img"}, "node-name": "node1"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node2.img"}, "node-name": "node2"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node3.img"}, "node-name": "node3"}, "driver": "IMGFMT", "file": {"driver": "throttle", "file": {"driver": "file", "filename": "TEST_DIR/PID-node4.img"}, "throttle-group": "tg"}, "node-name": "node4"}}
27
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
161
{"return": {}}
28
break;
162
@@ -XXX,XX +XXX,XX @@ Running tests:
163
164
=== Commit and stream finish concurrently (letting commit write) ===
165
166
-{"execute": "object-add", "arguments": {"id": "tg", "props": {"x-iops-write": 1, "x-iops-write-max": 1}, "qom-type": "throttle-group"}}
167
+{"execute": "object-add", "arguments": {"id": "tg", "limits": {"iops-write": 1, "iops-write-max": 1}, "qom-type": "throttle-group"}}
168
{"return": {}}
169
{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"backing": {"driver": "raw", "file": {"driver": "throttle", "file": {"driver": "file", "filename": "TEST_DIR/PID-node0.img"}, "throttle-group": "tg"}, "node-name": "node0"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node1.img"}, "node-name": "node1"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node2.img"}, "node-name": "node2"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node3.img"}, "node-name": "node3"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-node4.img"}, "node-name": "node4"}}
170
{"return": {}}
171
diff --git a/tests/qemu-iotests/295 b/tests/qemu-iotests/295
172
index XXXXXXX..XXXXXXX 100755
173
--- a/tests/qemu-iotests/295
174
+++ b/tests/qemu-iotests/295
175
@@ -XXX,XX +XXX,XX @@ class Secret:
176
177
def to_qmp_object(self):
178
return { "qom_type" : "secret", "id": self.id(),
179
- "props": { "data": self.secret() } }
180
+ "data": self.secret() }
181
182
################################################################################
183
class EncryptionSetupTestCase(iotests.QMPTestCase):
184
diff --git a/tests/qemu-iotests/296 b/tests/qemu-iotests/296
185
index XXXXXXX..XXXXXXX 100755
186
--- a/tests/qemu-iotests/296
187
+++ b/tests/qemu-iotests/296
188
@@ -XXX,XX +XXX,XX @@ class Secret:
189
190
def to_qmp_object(self):
191
return { "qom_type" : "secret", "id": self.id(),
192
- "props": { "data": self.secret() } }
193
+ "data": self.secret() }
194
195
################################################################################
29
196
30
--
197
--
31
2.13.6
198
2.29.2
32
199
33
200
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
Thanks to recent cleanups, most callers were scaling a return value
3
The block job holds a reference to the backup-top node (because it is
4
of sectors into bytes (the exception, in qcow2-bitmap, will be
4
passed as the main job BDS to block_job_create()). Therefore,
5
converted to byte-based iteration later). Update the interface to
5
bdrv_backup_top_drop() cannot delete the backup-top node (replacing it
6
do the scaling internally instead.
6
by its child does not affect the job parent, because that has
7
.stay_at_node set). That is a problem, because all of its I/O functions
8
assume the BlockCopyState (s->bcs) to be valid and that it has a
9
filtered child; but after bdrv_backup_top_drop(), neither of those
10
things are true.
7
11
8
In qcow2-bitmap, the code was specifically checking for an error
12
It does not make sense to add new parents to backup-top after
9
return of -1. To avoid a regression, we either have to make sure
13
backup_clean(), so we should detach it from the job before
10
we continue to return -1 (rather than a scaled -512) on error, or
14
bdrv_backup_top_drop(). Because there is no function to do that for a
11
we have to fix the caller to treat all negative values as error
15
single node, just detach all of the job's nodes -- the job does not do
12
rather than just one magic value. It's easy enough to make both
16
anything past backup_clean() anyway.
13
changes at the same time, even though either one in isolation
14
would work.
15
17
16
Signed-off-by: Eric Blake <eblake@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Reviewed-by: John Snow <jsnow@redhat.com>
19
Message-Id: <20210219153348.41861-2-mreitz@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
19
Reviewed-by: Fam Zheng <famz@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
21
---
22
block/backup.c | 2 +-
22
block/backup.c | 1 +
23
block/dirty-bitmap.c | 3 ++-
23
1 file changed, 1 insertion(+)
24
block/mirror.c | 8 ++++----
25
block/qcow2-bitmap.c | 2 +-
26
4 files changed, 8 insertions(+), 7 deletions(-)
27
24
28
diff --git a/block/backup.c b/block/backup.c
25
diff --git a/block/backup.c b/block/backup.c
29
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
30
--- a/block/backup.c
27
--- a/block/backup.c
31
+++ b/block/backup.c
28
+++ b/block/backup.c
32
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
29
@@ -XXX,XX +XXX,XX @@ static void backup_abort(Job *job)
33
dbi = bdrv_dirty_iter_new(job->sync_bitmap);
30
static void backup_clean(Job *job)
34
35
/* Find the next dirty sector(s) */
36
- while ((offset = bdrv_dirty_iter_next(dbi) * BDRV_SECTOR_SIZE) >= 0) {
37
+ while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
38
cluster = offset / job->cluster_size;
39
40
/* Fake progress updates for any clusters we skipped */
41
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/dirty-bitmap.c
44
+++ b/block/dirty-bitmap.c
45
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
46
47
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
48
{
31
{
49
- return hbitmap_iter_next(&iter->hbi);
32
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
50
+ int64_t ret = hbitmap_iter_next(&iter->hbi);
33
+ block_job_remove_all_bdrv(&s->common);
51
+ return ret < 0 ? -1 : ret * BDRV_SECTOR_SIZE;
34
bdrv_backup_top_drop(s->backup_top);
52
}
35
}
53
36
54
/* Called within bdrv_dirty_bitmap_lock..unlock */
55
diff --git a/block/mirror.c b/block/mirror.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/mirror.c
58
+++ b/block/mirror.c
59
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
60
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
61
62
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
63
- offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
64
+ offset = bdrv_dirty_iter_next(s->dbi);
65
if (offset < 0) {
66
bdrv_set_dirty_iter(s->dbi, 0);
67
- offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
68
+ offset = bdrv_dirty_iter_next(s->dbi);
69
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) *
70
BDRV_SECTOR_SIZE);
71
assert(offset >= 0);
72
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
73
break;
74
}
75
76
- next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
77
+ next_dirty = bdrv_dirty_iter_next(s->dbi);
78
if (next_dirty > next_offset || next_dirty < 0) {
79
/* The bitmap iterator's cache is stale, refresh it */
80
bdrv_set_dirty_iter(s->dbi, next_offset);
81
- next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
82
+ next_dirty = bdrv_dirty_iter_next(s->dbi);
83
}
84
assert(next_dirty == next_offset);
85
nb_chunks++;
86
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qcow2-bitmap.c
89
+++ b/block/qcow2-bitmap.c
90
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
91
sbc = limit >> BDRV_SECTOR_BITS;
92
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
93
94
- while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
95
+ while ((sector = bdrv_dirty_iter_next(dbi) >> BDRV_SECTOR_BITS) >= 0) {
96
uint64_t cluster = sector / sbc;
97
uint64_t end, write_size;
98
int64_t off;
99
--
37
--
100
2.13.6
38
2.29.2
101
39
102
40
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
We are still using an internal hbitmap that tracks a size in sectors,
3
When the backup-top node transitions from active to inactive in
4
with the granularity scaled down accordingly, because it lets us
4
bdrv_backup_top_drop(), the BlockCopyState is freed and the filtered
5
use a shortcut for our iterators which are currently sector-based.
5
child is removed, so the node effectively becomes unusable.
6
But there's no reason we can't track the dirty bitmap size in bytes,
7
since it is (mostly) an internal-only variable (remember, the size
8
is how many bytes are covered by the bitmap, not how many bytes the
9
bitmap occupies). A later cleanup will convert dirty bitmap
10
internals to be entirely byte-based, eliminating the intermediate
11
sector rounding added here; and technically, since bdrv_getlength()
12
already rounds up to sectors, our use of DIV_ROUND_UP is more for
13
theoretical completeness than for any actual rounding.
14
6
15
Use is_power_of_2() while at it, instead of open-coding that.
7
However, noone told its I/O functions this, so they will happily
8
continue accessing bs->backing and s->bcs. Prevent that by aborting
9
early when s->active is false.
16
10
17
Signed-off-by: Eric Blake <eblake@redhat.com>
11
(After the preceding patch, the node should be gone after
18
Reviewed-by: John Snow <jsnow@redhat.com>
12
bdrv_backup_top_drop(), so this should largely be a theoretical problem.
19
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
But still, better to be safe than sorry, and also I think it just makes
20
Reviewed-by: Fam Zheng <famz@redhat.com>
14
sense to check s->active in the I/O functions.)
15
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Message-Id: <20210219153348.41861-3-mreitz@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
19
---
23
block/dirty-bitmap.c | 26 ++++++++++++++------------
20
block/backup-top.c | 10 ++++++++++
24
1 file changed, 14 insertions(+), 12 deletions(-)
21
1 file changed, 10 insertions(+)
25
22
26
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
23
diff --git a/block/backup-top.c b/block/backup-top.c
27
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
28
--- a/block/dirty-bitmap.c
25
--- a/block/backup-top.c
29
+++ b/block/dirty-bitmap.c
26
+++ b/block/backup-top.c
30
@@ -XXX,XX +XXX,XX @@ struct BdrvDirtyBitmap {
27
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_co_preadv(
31
HBitmap *meta; /* Meta dirty bitmap */
28
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
32
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
29
QEMUIOVector *qiov, int flags)
33
char *name; /* Optional non-empty unique ID */
34
- int64_t size; /* Size of the bitmap (Number of sectors) */
35
+ int64_t size; /* Size of the bitmap, in bytes */
36
bool disabled; /* Bitmap is disabled. It ignores all writes to
37
the device */
38
int active_iterators; /* How many iterators are active */
39
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
40
{
30
{
41
int64_t bitmap_size;
31
+ BDRVBackupTopState *s = bs->opaque;
42
BdrvDirtyBitmap *bitmap;
32
+
43
- uint32_t sector_granularity;
33
+ if (!s->active) {
44
34
+ return -EIO;
45
- assert((granularity & (granularity - 1)) == 0);
35
+ }
46
+ assert(is_power_of_2(granularity) && granularity >= BDRV_SECTOR_SIZE);
36
+
47
37
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
48
if (name && bdrv_find_dirty_bitmap(bs, name)) {
49
error_setg(errp, "Bitmap already exists: %s", name);
50
return NULL;
51
}
52
- sector_granularity = granularity >> BDRV_SECTOR_BITS;
53
- assert(sector_granularity);
54
- bitmap_size = bdrv_nb_sectors(bs);
55
+ bitmap_size = bdrv_getlength(bs);
56
if (bitmap_size < 0) {
57
error_setg_errno(errp, -bitmap_size, "could not get length of device");
58
errno = -bitmap_size;
59
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
60
}
61
bitmap = g_new0(BdrvDirtyBitmap, 1);
62
bitmap->mutex = &bs->dirty_bitmap_mutex;
63
- bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
64
+ /*
65
+ * TODO - let hbitmap track full granularity. For now, it is tracking
66
+ * only sector granularity, as a shortcut for our iterators.
67
+ */
68
+ bitmap->bitmap = hbitmap_alloc(DIV_ROUND_UP(bitmap_size, BDRV_SECTOR_SIZE),
69
+ ctz32(granularity) - BDRV_SECTOR_BITS);
70
bitmap->size = bitmap_size;
71
bitmap->name = g_strdup(name);
72
bitmap->disabled = false;
73
@@ -XXX,XX +XXX,XX @@ void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
74
75
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
76
{
77
- return bitmap->size * BDRV_SECTOR_SIZE;
78
+ return bitmap->size;
79
}
38
}
80
39
81
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
40
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
82
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
41
BDRVBackupTopState *s = bs->opaque;
83
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
42
uint64_t off, end;
84
{
43
85
BdrvDirtyBitmap *bitmap;
44
+ if (!s->active) {
86
- int64_t size = DIV_ROUND_UP(bytes, BDRV_SECTOR_SIZE);
45
+ return -EIO;
87
46
+ }
88
bdrv_dirty_bitmaps_lock(bs);
47
+
89
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
48
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
90
assert(!bdrv_dirty_bitmap_frozen(bitmap));
49
return 0;
91
assert(!bitmap->active_iterators);
92
- hbitmap_truncate(bitmap->bitmap, size);
93
- bitmap->size = size;
94
+ hbitmap_truncate(bitmap->bitmap, DIV_ROUND_UP(bytes, BDRV_SECTOR_SIZE));
95
+ bitmap->size = bytes;
96
}
97
bdrv_dirty_bitmaps_unlock(bs);
98
}
99
@@ -XXX,XX +XXX,XX @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
100
hbitmap_reset_all(bitmap->bitmap);
101
} else {
102
HBitmap *backup = bitmap->bitmap;
103
- bitmap->bitmap = hbitmap_alloc(bitmap->size,
104
+ bitmap->bitmap = hbitmap_alloc(DIV_ROUND_UP(bitmap->size,
105
+ BDRV_SECTOR_SIZE),
106
hbitmap_granularity(backup));
107
*out = backup;
108
}
50
}
109
--
51
--
110
2.13.6
52
2.29.2
111
53
112
54
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
do_run_qemu() in iotest 195 first applies _filter_imgfmt when printing
3
Without any of HEAD^ or HEAD^^ applied, qemu will most likely crash on
4
qemu's command line and _filter_testdir only afterwards. Therefore, if
4
the qemu-io invocation, for a variety of immediate reasons. The
5
the image format is part of the test directory path, _filter_testdir
5
underlying problem is generally a use-after-free access into
6
will no longer apply and the actual output will differ from the
6
backup-top's BlockCopyState.
7
reference output even in case of success.
8
7
9
For example, TEST_DIR might be "/tmp/test-qcow2", in which case
8
With only HEAD^ applied, qemu-io will run into an EIO (which is not
10
_filter_imgfmt first transforms this to "/tmp/test-IMGFMT" which is no
9
capture by the output, but you can see that the qemu-io invocation will
11
longer recognized as the TEST_DIR by _filter_testdir.
10
be accepted (i.e., qemu-io will run) in contrast to the reference
11
output, where the node name cannot be found), and qemu will then crash
12
in query-named-block-nodes: bdrv_get_allocated_file_size() detects
13
backup-top to be a filter and passes the request through to its child.
14
However, after bdrv_backup_top_drop(), that child is NULL, so the
15
recursive call crashes.
12
16
13
Fix this by not applying _filter_imgfmt in do_run_qemu() but in
17
With HEAD^^ applied, this test should pass.
14
run_qemu() instead, and only after _filter_testdir.
15
18
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Message-id: 20170927211334.3988-1-mreitz@redhat.com
20
Message-Id: <20210219153348.41861-4-mreitz@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
22
---
21
tests/qemu-iotests/195 | 7 ++++---
23
tests/qemu-iotests/283 | 53 ++++++++++++++++++++++++++++++++++++++
22
1 file changed, 4 insertions(+), 3 deletions(-)
24
tests/qemu-iotests/283.out | 15 +++++++++++
25
2 files changed, 68 insertions(+)
23
26
24
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
27
diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283
25
index XXXXXXX..XXXXXXX 100755
28
index XXXXXXX..XXXXXXX 100755
26
--- a/tests/qemu-iotests/195
29
--- a/tests/qemu-iotests/283
27
+++ b/tests/qemu-iotests/195
30
+++ b/tests/qemu-iotests/283
28
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
31
@@ -XXX,XX +XXX,XX @@ vm.qmp_log('blockdev-add', **{
29
32
vm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
30
function do_run_qemu()
33
31
{
34
vm.shutdown()
32
- echo Testing: "$@" | _filter_imgfmt
35
+
33
+ echo Testing: "$@"
36
+
34
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
37
+print('\n=== backup-top should be gone after job-finalize ===\n')
35
echo
38
+
36
}
39
+# Check that the backup-top node is gone after job-finalize.
37
40
+#
38
function run_qemu()
41
+# During finalization, the node becomes inactive and can no longer
39
{
42
+# function. If it is still present, new parents might be attached, and
40
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
43
+# there would be no meaningful way to handle their I/O requests.
41
- | _filter_qemu_io | _filter_generated_node_ids
44
+
42
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \
45
+vm = iotests.VM()
43
+ | _filter_qmp | _filter_qemu_io \
46
+vm.launch()
44
+ | _filter_generated_node_ids
47
+
45
}
48
+vm.qmp_log('blockdev-add', **{
46
49
+ 'node-name': 'source',
47
size=64M
50
+ 'driver': 'null-co',
51
+})
52
+
53
+vm.qmp_log('blockdev-add', **{
54
+ 'node-name': 'target',
55
+ 'driver': 'null-co',
56
+})
57
+
58
+vm.qmp_log('blockdev-backup',
59
+ job_id='backup',
60
+ device='source',
61
+ target='target',
62
+ sync='full',
63
+ filter_node_name='backup-filter',
64
+ auto_finalize=False,
65
+ auto_dismiss=False)
66
+
67
+vm.event_wait('BLOCK_JOB_PENDING', 5.0)
68
+
69
+# The backup-top filter should still be present prior to finalization
70
+assert vm.node_info('backup-filter') is not None
71
+
72
+vm.qmp_log('job-finalize', id='backup')
73
+vm.event_wait('BLOCK_JOB_COMPLETED', 5.0)
74
+
75
+# The filter should be gone now. Check that by trying to access it
76
+# with qemu-io (which will most likely crash qemu if it is still
77
+# there.).
78
+vm.qmp_log('human-monitor-command',
79
+ command_line='qemu-io backup-filter "write 0 1M"')
80
+
81
+# (Also, do an explicit check.)
82
+assert vm.node_info('backup-filter') is None
83
+
84
+vm.qmp_log('job-dismiss', id='backup')
85
+vm.event_wait('JOB_STATUS_CHANGE', 5.0, {'data': {'status': 'null'}})
86
+
87
+vm.shutdown()
88
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
89
index XXXXXXX..XXXXXXX 100644
90
--- a/tests/qemu-iotests/283.out
91
+++ b/tests/qemu-iotests/283.out
92
@@ -XXX,XX +XXX,XX @@
93
{"return": {}}
94
{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
95
{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}}
96
+
97
+=== backup-top should be gone after job-finalize ===
98
+
99
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "source"}}
100
+{"return": {}}
101
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}}
102
+{"return": {}}
103
+{"execute": "blockdev-backup", "arguments": {"auto-dismiss": false, "auto-finalize": false, "device": "source", "filter-node-name": "backup-filter", "job-id": "backup", "sync": "full", "target": "target"}}
104
+{"return": {}}
105
+{"execute": "job-finalize", "arguments": {"id": "backup"}}
106
+{"return": {}}
107
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io backup-filter \"write 0 1M\""}}
108
+{"return": "Error: Cannot find device= nor node_name=backup-filter\r\n"}
109
+{"execute": "job-dismiss", "arguments": {"id": "backup"}}
110
+{"return": {}}
48
--
111
--
49
2.13.6
112
2.29.2
50
113
51
114
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Eric Blake <eblake@redhat.com>
2
2
3
Now that we have adjusted the majority of the calls this function
3
Break some long lines, and relax our type hints to be more generic to
4
makes to be byte-based, it is easier to read the code if it makes
4
any JSON, in order to more easily permit the additional JSON depth now
5
passes over the image using bytes rather than sectors.
5
possible in migration parameters. Detected by iotest 297.
6
6
7
Fixes: ca4bfec41d56
8
(qemu-iotests: 300: Add test case for modifying persistence of bitmap)
9
Reported-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20210215220518.1745469-1-eblake@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
12
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Fam Zheng <famz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
15
---
14
block/qcow2-bitmap.c | 22 ++++++++--------------
16
tests/qemu-iotests/300 | 10 ++++++----
15
1 file changed, 8 insertions(+), 14 deletions(-)
17
1 file changed, 6 insertions(+), 4 deletions(-)
16
18
17
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
19
diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300
18
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100755
19
--- a/block/qcow2-bitmap.c
21
--- a/tests/qemu-iotests/300
20
+++ b/block/qcow2-bitmap.c
22
+++ b/tests/qemu-iotests/300
21
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
23
@@ -XXX,XX +XXX,XX @@
22
{
24
import os
23
int ret = 0;
25
import random
24
BDRVQcow2State *s = bs->opaque;
26
import re
25
- uint64_t sector, limit, sbc;
27
-from typing import Dict, List, Optional, Union
26
+ uint64_t offset, limit;
28
+from typing import Dict, List, Optional
27
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
29
28
- uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
30
import iotests
29
uint8_t *buf = NULL;
31
30
uint64_t i, tab_size =
32
@@ -XXX,XX +XXX,XX @@ import iotests
31
size_to_clusters(s,
33
# pylint: disable=wrong-import-order
32
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
34
import qemu
33
35
34
buf = g_malloc(s->cluster_size);
36
-BlockBitmapMapping = List[Dict[str, Union[str, List[Dict[str, str]]]]]
35
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
37
+BlockBitmapMapping = List[Dict[str, object]]
36
- sbc = limit >> BDRV_SECTOR_BITS;
38
37
- for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
39
mig_sock = os.path.join(iotests.sock_dir, 'mig_sock')
38
- uint64_t count = MIN(bm_sectors - sector, sbc);
40
39
+ for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) {
41
@@ -XXX,XX +XXX,XX @@ class TestCrossAliasMigration(TestDirtyBitmapMigration):
40
+ uint64_t count = MIN(bm_size - offset, limit);
42
41
uint64_t entry = bitmap_table[i];
43
class TestAliasTransformMigration(TestDirtyBitmapMigration):
42
- uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
44
"""
43
+ uint64_t data_offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
45
- Tests the 'transform' option which modifies bitmap persistence on migration.
44
46
+ Tests the 'transform' option which modifies bitmap persistence on
45
assert(check_table_entry(entry, s->cluster_size) == 0);
47
+ migration.
46
48
"""
47
- if (offset == 0) {
49
48
+ if (data_offset == 0) {
50
src_node_name = 'node-a'
49
if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
51
@@ -XXX,XX +XXX,XX @@ class TestAliasTransformMigration(TestDirtyBitmapMigration):
50
- bdrv_dirty_bitmap_deserialize_ones(bitmap,
52
bitmaps = self.vm_b.query_bitmaps()
51
- sector * BDRV_SECTOR_SIZE,
53
52
- count * BDRV_SECTOR_SIZE,
54
for node in bitmaps:
53
+ bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count,
55
- bitmaps[node] = sorted(((bmap['name'], bmap['persistent']) for bmap in bitmaps[node]))
54
false);
56
+ bitmaps[node] = sorted(((bmap['name'], bmap['persistent'])
55
} else {
57
+ for bmap in bitmaps[node]))
56
/* No need to deserialize zeros because the dirty bitmap is
58
57
* already cleared */
59
self.assertEqual(bitmaps,
58
}
60
{'node-a': [('bmap-a', True), ('bmap-b', False)],
59
} else {
60
- ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
61
+ ret = bdrv_pread(bs->file, data_offset, buf, s->cluster_size);
62
if (ret < 0) {
63
goto finish;
64
}
65
- bdrv_dirty_bitmap_deserialize_part(bitmap, buf,
66
- sector * BDRV_SECTOR_SIZE,
67
- count * BDRV_SECTOR_SIZE,
68
+ bdrv_dirty_bitmap_deserialize_part(bitmap, buf, offset, count,
69
false);
70
}
71
}
72
--
61
--
73
2.13.6
62
2.29.2
74
63
75
64
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Thanks to recent cleanups, all callers were scaling a return value
3
When a block job fails, we report strerror(-job->job.ret) error
4
of sectors into bytes; do the scaling internally instead.
4
message, also if the job set an error object.
5
Let's report a better error message using error_get_pretty(job->job.err).
5
6
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
If an error object was not set, strerror(-job->ret) is used as fallback,
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
as explained in include/qemu/job.h:
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
9
Reviewed-by: Fam Zheng <famz@redhat.com>
10
typedef struct Job {
11
...
12
/**
13
* Error object for a failed job.
14
* If job->ret is nonzero and an error object was not set, it will be set
15
* to strerror(-job->ret) during job_completed.
16
*/
17
Error *err;
18
}
19
20
In block_job_query() there can be a transient where 'job.err' is not set
21
by a scheduled bottom half. In that case we use strerror(-job->ret) as it
22
was before.
23
24
Suggested-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
26
Message-Id: <20210225103633.76746-1-sgarzare@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
28
---
12
block/dirty-bitmap.c | 4 ++--
29
blockjob.c | 10 +++++++---
13
block/mirror.c | 16 ++++++----------
30
1 file changed, 7 insertions(+), 3 deletions(-)
14
migration/block.c | 2 +-
15
3 files changed, 9 insertions(+), 13 deletions(-)
16
31
17
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
32
diff --git a/blockjob.c b/blockjob.c
18
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
19
--- a/block/dirty-bitmap.c
34
--- a/blockjob.c
20
+++ b/block/dirty-bitmap.c
35
+++ b/blockjob.c
21
@@ -XXX,XX +XXX,XX @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
36
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
22
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
37
info->status = job->job.status;
23
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
38
info->auto_finalize = job->job.auto_finalize;
24
BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
39
info->auto_dismiss = job->job.auto_dismiss;
25
- info->count = bdrv_get_dirty_count(bm) << BDRV_SECTOR_BITS;
40
- info->has_error = job->job.ret != 0;
26
+ info->count = bdrv_get_dirty_count(bm);
41
- info->error = job->job.ret ? g_strdup(strerror(-job->job.ret)) : NULL;
27
info->granularity = bdrv_dirty_bitmap_granularity(bm);
42
+ if (job->job.ret) {
28
info->has_name = !!bm->name;
43
+ info->has_error = true;
29
info->name = g_strdup(bm->name);
44
+ info->error = job->job.err ?
30
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t offset)
45
+ g_strdup(error_get_pretty(job->job.err)) :
31
46
+ g_strdup(strerror(-job->job.ret));
32
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
47
+ }
33
{
48
return info;
34
- return hbitmap_count(bitmap->bitmap);
35
+ return hbitmap_count(bitmap->bitmap) << BDRV_SECTOR_BITS;
36
}
49
}
37
50
38
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
51
@@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(Notifier *n, void *opaque)
39
diff --git a/block/mirror.c b/block/mirror.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/mirror.c
42
+++ b/block/mirror.c
43
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
44
if (offset < 0) {
45
bdrv_set_dirty_iter(s->dbi, 0);
46
offset = bdrv_dirty_iter_next(s->dbi);
47
- trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) *
48
- BDRV_SECTOR_SIZE);
49
+ trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
50
assert(offset >= 0);
51
}
52
}
52
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
53
53
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
54
if (job->job.ret < 0) {
54
55
- msg = strerror(-job->job.ret);
55
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
56
+ msg = error_get_pretty(job->job.err);
56
/* s->common.offset contains the number of bytes already processed so
57
- * far, cnt is the number of dirty sectors remaining and
58
+ * far, cnt is the number of dirty bytes remaining and
59
* s->bytes_in_flight is the number of bytes currently being
60
* processed; together those are the current total operation length */
61
- s->common.len = s->common.offset + s->bytes_in_flight +
62
- cnt * BDRV_SECTOR_SIZE;
63
+ s->common.len = s->common.offset + s->bytes_in_flight + cnt;
64
65
/* Note that even when no rate limit is applied we need to yield
66
* periodically with no pending I/O so that bdrv_drain_all() returns.
67
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
68
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
69
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
70
(cnt == 0 && s->in_flight > 0)) {
71
- trace_mirror_yield(s, cnt * BDRV_SECTOR_SIZE,
72
- s->buf_free_count, s->in_flight);
73
+ trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight);
74
mirror_wait_for_io(s);
75
continue;
76
} else if (cnt != 0) {
77
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
78
* whether to switch to target check one last time if I/O has
79
* come in the meanwhile, and if not flush the data to disk.
80
*/
81
- trace_mirror_before_drain(s, cnt * BDRV_SECTOR_SIZE);
82
+ trace_mirror_before_drain(s, cnt);
83
84
bdrv_drained_begin(bs);
85
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
86
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
87
}
88
89
ret = 0;
90
- trace_mirror_before_sleep(s, cnt * BDRV_SECTOR_SIZE,
91
- s->synced, delay_ns);
92
+ trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
93
if (!s->synced) {
94
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
95
if (block_job_is_cancelled(&s->common)) {
96
diff --git a/migration/block.c b/migration/block.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/migration/block.c
99
+++ b/migration/block.c
100
@@ -XXX,XX +XXX,XX @@ static int64_t get_remaining_dirty(void)
101
aio_context_release(blk_get_aio_context(bmds->blk));
102
}
57
}
103
58
104
- return dirty << BDRV_SECTOR_BITS;
59
qapi_event_send_block_job_completed(job_type(&job->job),
105
+ return dirty;
106
}
107
108
109
--
60
--
110
2.13.6
61
2.29.2
111
62
112
63
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The variable is almost unused, and one of the two uses is actually
3
If the first character of optstring is '-', then each nonoption argv
4
uninitialized.
4
element is handled as if it were the argument of an option with character
5
code 1. This removes the reordering of the argv array, and enables usage
6
of loc_set_cmdline to provide better error messages.
5
7
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-Id: <20210301152844.291799-2-pbonzini@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
tests/qemu-iotests/check | 5 +----
13
storage-daemon/qemu-storage-daemon.c | 9 ++++-----
11
tests/qemu-iotests/common.rc | 2 +-
14
1 file changed, 4 insertions(+), 5 deletions(-)
12
2 files changed, 2 insertions(+), 5 deletions(-)
13
15
14
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
16
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
15
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/check
18
--- a/storage-daemon/qemu-storage-daemon.c
17
+++ b/tests/qemu-iotests/check
19
+++ b/storage-daemon/qemu-storage-daemon.c
18
@@ -XXX,XX +XXX,XX @@ interrupt=true
20
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
19
# by default don't output timestamps
21
* they are given on the command lines. This means that things must be
20
timestamp=${TIMESTAMP:=false}
22
* defined first before they can be referenced in another option.
21
23
*/
22
-# generic initialization
24
- while ((c = getopt_long(argc, argv, "hT:V", long_options, NULL)) != -1) {
23
-iam=check
25
+ while ((c = getopt_long(argc, argv, "-hT:V", long_options, NULL)) != -1) {
24
-
26
switch (c) {
25
_init_error()
27
case '?':
26
{
28
exit(EXIT_FAILURE);
27
- echo "$iam: $1" >&2
29
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
28
+ echo "check: $1" >&2
30
qobject_unref(args);
29
exit 1
31
break;
32
}
33
+ case 1:
34
+ error_report("Unexpected argument: %s", optarg);
35
+ exit(EXIT_FAILURE);
36
default:
37
g_assert_not_reached();
38
}
39
}
40
- if (optind != argc) {
41
- error_report("Unexpected argument: %s", argv[optind]);
42
- exit(EXIT_FAILURE);
43
- }
30
}
44
}
31
45
32
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
46
int main(int argc, char *argv[])
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/qemu-iotests/common.rc
35
+++ b/tests/qemu-iotests/common.rc
36
@@ -XXX,XX +XXX,XX @@ poke_file()
37
38
if ! . ./common.config
39
then
40
- echo "$iam: failed to source common.config"
41
+ echo "$0: failed to source common.config"
42
exit 1
43
fi
44
45
--
47
--
46
2.13.6
48
2.29.2
47
49
48
50
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Instead of ./check failing when a binary is missing, we try each test
3
Use the location management facilities that the emulator uses, so that
4
case now and each one fails with tons of test case diffs. Also, all the
4
the current command line option appears in the error message.
5
variables were initialized by "check" prior to "common" being sourced,
6
and then (uselessly) checked for emptiness again in "check".
7
5
8
Centralize the search for programs in "common" (which will soon be
6
Before:
9
one with "check"), including the "realpath" invocation which can be done
10
just once in "check" rather than in the tests.
11
7
12
For qnio_server, move the detection to "common", simplifying
8
$ storage-daemon/qemu-storage-daemon --nbd key..=
13
set_prog_path to stop handling the unused second argument, and
9
qemu-storage-daemon: Invalid parameter 'key..'
14
embedding the "realpath" pass.
15
10
11
After:
12
13
$ storage-daemon/qemu-storage-daemon --nbd key..=
14
qemu-storage-daemon: --nbd key..=: Invalid parameter 'key..'
15
16
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
18
Message-Id: <20210301152844.291799-3-pbonzini@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
---
20
tests/qemu-iotests/check | 41 ---------------------
21
storage-daemon/qemu-storage-daemon.c | 19 +++++++++++++++++--
21
tests/qemu-iotests/common | 77 +++++++++++++++++++++++++++++++++++++---
22
1 file changed, 17 insertions(+), 2 deletions(-)
22
tests/qemu-iotests/common.config | 61 +------------------------------
23
3 files changed, 73 insertions(+), 106 deletions(-)
24
23
25
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
24
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
26
index XXXXXXX..XXXXXXX 100755
27
--- a/tests/qemu-iotests/check
28
+++ b/tests/qemu-iotests/check
29
@@ -XXX,XX +XXX,XX @@ fi
30
31
build_root="$build_iotests/../.."
32
33
-if [ -x "$build_iotests/socket_scm_helper" ]
34
-then
35
- export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
36
-fi
37
-
38
-if [[ -z "$QEMU_PROG" && ! -x './qemu' ]]
39
-then
40
- arch=$(uname -m 2> /dev/null)
41
-
42
- if [[ -n $arch && -x "$build_root/$arch-softmmu/qemu-system-$arch" ]]
43
- then
44
- export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
45
- else
46
- pushd "$build_root" > /dev/null
47
- for binary in *-softmmu/qemu-system-*
48
- do
49
- if [ -x "$binary" ]
50
- then
51
- export QEMU_PROG="$build_root/$binary"
52
- break
53
- fi
54
- done
55
- popd > /dev/null
56
- fi
57
-fi
58
-
59
-if [[ -z $QEMU_IMG_PROG && -x "$build_root/qemu-img" && ! -x './qemu-img' ]]
60
-then
61
- export QEMU_IMG_PROG="$build_root/qemu-img"
62
-fi
63
-
64
-if [[ -z $QEMU_IO_PROG && -x "$build_root/qemu-io" && ! -x './qemu-io' ]]
65
-then
66
- export QEMU_IO_PROG="$build_root/qemu-io"
67
-fi
68
-
69
-if [[ -z $QEMU_NBD_PROG && -x "$build_root/qemu-nbd" && ! -x './qemu-nbd' ]]
70
-then
71
- export QEMU_NBD_PROG="$build_root/qemu-nbd"
72
-fi
73
-
74
# we need common.env
75
if ! . "$build_iotests/common.env"
76
then
77
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
78
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
79
--- a/tests/qemu-iotests/common
26
--- a/storage-daemon/qemu-storage-daemon.c
80
+++ b/tests/qemu-iotests/common
27
+++ b/storage-daemon/qemu-storage-daemon.c
81
@@ -XXX,XX +XXX,XX @@ _full_platform_details()
28
@@ -XXX,XX +XXX,XX @@ static void init_qmp_commands(void)
82
echo "$os/$platform $host $kernel"
29
qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
83
}
30
}
84
31
85
+# $1 = prog to look for
32
+static int getopt_set_loc(int argc, char **argv, const char *optstring,
86
+set_prog_path()
33
+ const struct option *longopts)
87
+{
34
+{
88
+ p=`command -v $1 2> /dev/null`
35
+ int c, save_index;
89
+ if [ -n "$p" -a -x "$p" ]; then
36
+
90
+ realpath -- "$(type -p "$p")"
37
+ optarg = NULL;
91
+ else
38
+ save_index = optind;
92
+ return 1
39
+ c = getopt_long(argc, argv, optstring, longopts, NULL);
93
+ fi
40
+ if (optarg) {
41
+ loc_set_cmdline(argv, save_index, MAX(1, optind - save_index));
42
+ }
43
+ return c;
94
+}
44
+}
95
+
45
+
96
diff="diff -u"
46
static void process_options(int argc, char *argv[])
97
verbose=false
98
debug=false
99
@@ -XXX,XX +XXX,XX @@ fi
100
list=`sort $tmp.list`
101
rm -f $tmp.list $tmp.tmp $tmp.sed
102
103
-[ "$QEMU" = "" ] && _fatal "qemu not found"
104
-[ "$QEMU_IMG" = "" ] && _fatal "qemu-img not found"
105
-[ "$QEMU_IO" = "" ] && _fatal "qemu-io not found"
106
+if [ -z "$QEMU_PROG" ]
107
+then
108
+ if [ -x "$build_iotests/qemu" ]; then
109
+ export QEMU_PROG="$build_iotests/qemu"
110
+ elif [ -x "$build_root/$arch-softmmu/qemu-system-$arch" ]; then
111
+ export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
112
+ else
113
+ pushd "$build_root" > /dev/null
114
+ for binary in *-softmmu/qemu-system-*
115
+ do
116
+ if [ -x "$binary" ]
117
+ then
118
+ export QEMU_PROG="$build_root/$binary"
119
+ break
120
+ fi
121
+ done
122
+ popd > /dev/null
123
+ [ "$QEMU_PROG" = "" ] && _init_error "qemu not found"
124
+ fi
125
+fi
126
+export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
127
+
128
+if [ -z "$QEMU_IMG_PROG" ]; then
129
+ if [ -x "$build_iotests/qemu-img" ]; then
130
+ export QEMU_IMG_PROG="$build_iotests/qemu-img"
131
+ elif [ -x "$build_root/qemu-img" ]; then
132
+ export QEMU_IMG_PROG="$build_root/qemu-img"
133
+ else
134
+ _init_error "qemu-img not found"
135
+ fi
136
+fi
137
+export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
138
+
139
+if [ -z "$QEMU_IO_PROG" ]; then
140
+ if [ -x "$build_iotests/qemu-io" ]; then
141
+ export QEMU_IO_PROG="$build_iotests/qemu-io"
142
+ elif [ -x "$build_root/qemu-io" ]; then
143
+ export QEMU_IO_PROG="$build_root/qemu-io"
144
+ else
145
+ _init_error "qemu-io not found"
146
+ fi
147
+fi
148
+export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
149
150
-if [ "$IMGPROTO" = "nbd" ] ; then
151
- [ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found"
152
+if [ -z $QEMU_NBD_PROG ]; then
153
+ if [ -x "$build_iotests/qemu-nbd" ]; then
154
+ export QEMU_NBD_PROG="$build_iotests/qemu-nbd"
155
+ elif [ -x "$build_root/qemu-nbd" ]; then
156
+ export QEMU_NBD_PROG="$build_root/qemu-nbd"
157
+ else
158
+ _init_error "qemu-nbd not found"
159
+ fi
160
+fi
161
+export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
162
+
163
+if [ -z "$QEMU_VXHS_PROG" ]; then
164
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
165
+fi
166
+
167
+if [ -x "$build_iotests/socket_scm_helper" ]
168
+then
169
+ export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
170
fi
171
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
172
index XXXXXXX..XXXXXXX 100644
173
--- a/tests/qemu-iotests/common.config
174
+++ b/tests/qemu-iotests/common.config
175
@@ -XXX,XX +XXX,XX @@ export LANG=C
176
PATH=".:$PATH"
177
178
HOSTOS=`uname -s`
179
+arch=`uname -m`
180
181
export PWD=`pwd`
182
183
@@ -XXX,XX +XXX,XX @@ export _QEMU_HANDLE=0
184
# make sure we have a standard umask
185
umask 022
186
187
-# $1 = prog to look for, $2* = default pathnames if not found in $PATH
188
-set_prog_path()
189
-{
190
- p=`command -v $1 2> /dev/null`
191
- if [ -n "$p" -a -x "$p" ]; then
192
- echo $p
193
- return 0
194
- fi
195
- p=$1
196
-
197
- shift
198
- for f; do
199
- if [ -x $f ]; then
200
- echo $f
201
- return 0
202
- fi
203
- done
204
-
205
- echo ""
206
- return 1
207
-}
208
-
209
_optstr_add()
210
{
47
{
211
if [ -n "$1" ]; then
48
int c;
212
@@ -XXX,XX +XXX,XX @@ _optstr_add()
49
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
213
fi
50
* they are given on the command lines. This means that things must be
51
* defined first before they can be referenced in another option.
52
*/
53
- while ((c = getopt_long(argc, argv, "-hT:V", long_options, NULL)) != -1) {
54
+ while ((c = getopt_set_loc(argc, argv, "-hT:V", long_options)) != -1) {
55
switch (c) {
56
case '?':
57
exit(EXIT_FAILURE);
58
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
59
break;
60
}
61
case 1:
62
- error_report("Unexpected argument: %s", optarg);
63
+ error_report("Unexpected argument");
64
exit(EXIT_FAILURE);
65
default:
66
g_assert_not_reached();
67
}
68
}
69
+ loc_set_none();
214
}
70
}
215
71
216
-_fatal()
72
int main(int argc, char *argv[])
217
-{
218
- echo "$*"
219
- status=1
220
- exit 1
221
-}
222
-
223
-if [ -z "$QEMU_PROG" ]; then
224
- export QEMU_PROG="`set_prog_path qemu`"
225
-fi
226
-
227
-if [ -z "$QEMU_IMG_PROG" ]; then
228
- export QEMU_IMG_PROG="`set_prog_path qemu-img`"
229
-fi
230
-
231
-if [ -z "$QEMU_IO_PROG" ]; then
232
- export QEMU_IO_PROG="`set_prog_path qemu-io`"
233
-fi
234
-
235
-if [ -z "$QEMU_NBD_PROG" ]; then
236
- export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
237
-fi
238
-
239
-if [ -z "$QEMU_VXHS_PROG" ]; then
240
- export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
241
-fi
242
-
243
-export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
244
-export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
245
-export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
246
-export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
247
-
248
-# This program is not built as part of qemu but (possibly) provided by the
249
-# system, so it may not be present at all
250
-if [ -n "$QEMU_VXHS_PROG" ]; then
251
- export QEMU_VXHS_PROG=$(realpath -- "$(type -p "$QEMU_VXHS_PROG")")
252
-fi
253
-
254
_qemu_wrapper()
255
{
256
(
257
--
73
--
258
2.13.6
74
2.29.2
259
75
260
76
diff view generated by jsdifflib
1
There is no good reason for bdrv_drop_intermediate() to know the active
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
layer above the subchain it is operating on - even more so, because
3
the assumption that there is a single active layer above it is not
4
generally true.
5
2
6
In order to prepare removal of the active parameter, use a BdrvChildRole
3
Daemons often have a --pidfile option where the pid is written to a file
7
callback to update the backing file string in the overlay image instead
4
so that scripts can stop the daemon by sending a signal.
8
of directly calling bdrv_change_backing_file().
9
5
6
The pid file also acts as a lock to prevent multiple instances of the
7
daemon from launching for a given pid file.
8
9
QEMU, qemu-nbd, qemu-ga, virtiofsd, and qemu-pr-helper all support the
10
--pidfile option. Add it to qemu-storage-daemon too.
11
12
Reported-by: Richard W.M. Jones <rjones@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20210302142746.170535-1-stefanha@redhat.com>
15
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
---
17
---
13
include/block/block_int.h | 6 ++++++
18
docs/tools/qemu-storage-daemon.rst | 14 +++++++++++
14
block.c | 33 ++++++++++++++++++++++++++++-----
19
storage-daemon/qemu-storage-daemon.c | 36 ++++++++++++++++++++++++++++
15
2 files changed, 34 insertions(+), 5 deletions(-)
20
2 files changed, 50 insertions(+)
16
21
17
diff --git a/include/block/block_int.h b/include/block/block_int.h
22
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
18
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block_int.h
24
--- a/docs/tools/qemu-storage-daemon.rst
20
+++ b/include/block/block_int.h
25
+++ b/docs/tools/qemu-storage-daemon.rst
21
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
26
@@ -XXX,XX +XXX,XX @@ Standard options:
22
27
List object properties with ``<type>,help``. See the :manpage:`qemu(1)`
23
void (*attach)(BdrvChild *child);
28
manual page for a description of the object properties.
24
void (*detach)(BdrvChild *child);
29
30
+.. option:: --pidfile PATH
25
+
31
+
26
+ /* Notifies the parent that the filename of its child has changed (e.g.
32
+ is the path to a file where the daemon writes its pid. This allows scripts to
27
+ * because the direct child was removed from the backing chain), so that it
33
+ stop the daemon by sending a signal::
28
+ * can update its reference. */
34
+
29
+ int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
35
+ $ kill -SIGTERM $(<path/to/qsd.pid)
30
+ const char *filename, Error **errp);
36
+
37
+ A file lock is applied to the file so only one instance of the daemon can run
38
+ with a given pid file path. The daemon unlinks its pid file when terminating.
39
+
40
+ The pid file is written after chardevs, exports, and NBD servers have been
41
+ created but before accepting connections. The daemon has started successfully
42
+ when the pid file is written and clients may begin connecting.
43
+
44
Examples
45
--------
46
Launch the daemon with QMP monitor socket ``qmp.sock`` so clients can execute
47
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/storage-daemon/qemu-storage-daemon.c
50
+++ b/storage-daemon/qemu-storage-daemon.c
51
@@ -XXX,XX +XXX,XX @@
52
#include "sysemu/runstate.h"
53
#include "trace/control.h"
54
55
+static const char *pid_file;
56
static volatile bool exit_requested = false;
57
58
void qemu_system_killed(int signal, pid_t pid)
59
@@ -XXX,XX +XXX,XX @@ static void help(void)
60
" See the qemu(1) man page for documentation of the\n"
61
" objects that can be added.\n"
62
"\n"
63
+" --pidfile <path> write process ID to a file after startup\n"
64
+"\n"
65
QEMU_HELP_BOTTOM "\n",
66
error_get_progname());
67
}
68
@@ -XXX,XX +XXX,XX @@ enum {
69
OPTION_MONITOR,
70
OPTION_NBD_SERVER,
71
OPTION_OBJECT,
72
+ OPTION_PIDFILE,
31
};
73
};
32
74
33
extern const BdrvChildRole child_file;
75
extern QemuOptsList qemu_chardev_opts;
34
diff --git a/block.c b/block.c
76
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
35
index XXXXXXX..XXXXXXX 100644
77
{"monitor", required_argument, NULL, OPTION_MONITOR},
36
--- a/block.c
78
{"nbd-server", required_argument, NULL, OPTION_NBD_SERVER},
37
+++ b/block.c
79
{"object", required_argument, NULL, OPTION_OBJECT},
38
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
80
+ {"pidfile", required_argument, NULL, OPTION_PIDFILE},
39
*child_flags = flags;
81
{"trace", required_argument, NULL, 'T'},
82
{"version", no_argument, NULL, 'V'},
83
{0, 0, 0, 0}
84
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
85
qobject_unref(args);
86
break;
87
}
88
+ case OPTION_PIDFILE:
89
+ pid_file = optarg;
90
+ break;
91
case 1:
92
error_report("Unexpected argument");
93
exit(EXIT_FAILURE);
94
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
95
loc_set_none();
40
}
96
}
41
97
42
+static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
98
+static void pid_file_cleanup(void)
43
+ const char *filename, Error **errp)
44
+{
99
+{
45
+ BlockDriverState *parent = c->opaque;
100
+ unlink(pid_file);
46
+ int ret;
101
+}
47
+
102
+
48
+ ret = bdrv_change_backing_file(parent, filename,
103
+static void pid_file_init(void)
49
+ base->drv ? base->drv->format_name : "");
104
+{
50
+ if (ret < 0) {
105
+ Error *err = NULL;
51
+ error_setg_errno(errp, ret, "Could not update backing file link");
106
+
107
+ if (!pid_file) {
108
+ return;
52
+ }
109
+ }
53
+
110
+
54
+ return ret;
111
+ if (!qemu_write_pidfile(pid_file, &err)) {
112
+ error_reportf_err(err, "cannot create PID file: ");
113
+ exit(EXIT_FAILURE);
114
+ }
115
+
116
+ atexit(pid_file_cleanup);
55
+}
117
+}
56
+
118
+
57
const BdrvChildRole child_backing = {
119
int main(int argc, char *argv[])
58
.get_parent_desc = bdrv_child_get_parent_desc,
120
{
59
.attach = bdrv_backing_attach,
121
#ifdef CONFIG_POSIX
60
@@ -XXX,XX +XXX,XX @@ const BdrvChildRole child_backing = {
122
@@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[])
61
.drained_begin = bdrv_child_cb_drained_begin,
123
qemu_init_main_loop(&error_fatal);
62
.drained_end = bdrv_child_cb_drained_end,
124
process_options(argc, argv);
63
.inactivate = bdrv_child_cb_inactivate,
125
64
+ .update_filename = bdrv_backing_update_filename,
126
+ /*
65
};
127
+ * Write the pid file after creating chardevs, exports, and NBD servers but
66
128
+ * before accepting connections. This ordering is documented. Do not change
67
static int bdrv_open_flags(BlockDriverState *bs, int flags)
129
+ * it.
68
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
130
+ */
69
Error *local_err = NULL;
131
+ pid_file_init();
70
int ret = -EIO;
71
72
+ bdrv_ref(top);
73
+
132
+
74
if (!top->drv || !base->drv) {
133
while (!exit_requested) {
75
goto exit;
134
main_loop_wait(false);
76
}
135
}
77
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
78
}
79
80
/* success - we can delete the intermediate states, and link top->base */
81
- backing_file_str = backing_file_str ? backing_file_str : base->filename;
82
- ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
83
- base->drv ? base->drv->format_name : "");
84
- if (ret) {
85
- goto exit;
86
+ if (new_top_bs->backing->role->update_filename) {
87
+ backing_file_str = backing_file_str ? backing_file_str : base->filename;
88
+ ret = new_top_bs->backing->role->update_filename(new_top_bs->backing,
89
+ base, backing_file_str,
90
+ &local_err);
91
+ if (ret < 0) {
92
+ bdrv_set_backing_hd(new_top_bs, top, &error_abort);
93
+ goto exit;
94
+ }
95
}
96
97
bdrv_set_backing_hd(new_top_bs, base, &local_err);
98
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
99
100
ret = 0;
101
exit:
102
+ bdrv_unref(top);
103
return ret;
104
}
105
106
--
136
--
107
2.13.6
137
2.29.2
108
138
109
139
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Handle a 0-length block status request up front, with a uniform
3
The QMP monitor, NBD server, and vhost-user-blk export all support file
4
return value claiming the area is not allocated.
4
descriptor passing. This is a useful technique because it allows the
5
parent process to spawn and wait for qemu-storage-daemon without busy
6
waiting, which may delay startup due to arbitrary sleep() calls.
5
7
6
Most callers don't pass a length of 0 to bdrv_get_block_status()
8
This Python example is inspired by the test case written for libnbd by
7
and friends; but it definitely happens with a 0-length read when
9
Richard W.M. Jones <rjones@redhat.com>:
8
copy-on-read is enabled. While we could audit all callers to
10
https://gitlab.com/nbdkit/libnbd/-/commit/89113f484effb0e6c322314ba75c1cbe07a04543
9
ensure that they never make a 0-length request, and then assert
10
that fact, it was just as easy to fix things to always report
11
success (as long as the callers are careful to not go into an
12
infinite loop). However, we had inconsistent behavior on whether
13
the status is reported as allocated or defers to the backing
14
layer, depending on what callbacks the driver implements, and
15
possibly wasting quite a few CPU cycles to get to that answer.
16
Consistently reporting unallocated up front doesn't really hurt
17
anything, and makes it easier both for callers (0-length requests
18
now have well-defined behavior) and for drivers (drivers don't
19
have to deal with 0-length requests).
20
11
21
Signed-off-by: Eric Blake <eblake@redhat.com>
12
Thanks to Daniel P. Berrangé <berrange@redhat.com> for suggestions on
22
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
how to get this working. Now let's document it!
14
15
Reported-by: Richard W.M. Jones <rjones@redhat.com>
16
Cc: Kevin Wolf <kwolf@redhat.com>
17
Cc: Daniel P. Berrangé <berrange@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-Id: <20210301172728.135331-2-stefanha@redhat.com>
20
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
21
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
23
---
25
block/io.c | 4 ++++
24
docs/tools/qemu-storage-daemon.rst | 42 ++++++++++++++++++++++++++++--
26
1 file changed, 4 insertions(+)
25
1 file changed, 40 insertions(+), 2 deletions(-)
27
26
28
diff --git a/block/io.c b/block/io.c
27
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
29
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
30
--- a/block/io.c
29
--- a/docs/tools/qemu-storage-daemon.rst
31
+++ b/block/io.c
30
+++ b/docs/tools/qemu-storage-daemon.rst
32
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
31
@@ -XXX,XX +XXX,XX @@ Standard options:
33
*pnum = 0;
32
34
return BDRV_BLOCK_EOF;
33
.. option:: --nbd-server addr.type=inet,addr.host=<host>,addr.port=<port>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
35
}
34
--nbd-server addr.type=unix,addr.path=<path>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
36
+ if (!nb_sectors) {
35
+ --nbd-server addr.type=fd,addr.str=<fd>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
37
+ *pnum = 0;
36
38
+ return 0;
37
is a server for NBD exports. Both TCP and UNIX domain sockets are supported.
39
+ }
38
- TLS encryption can be configured using ``--object`` tls-creds-* and authz-*
40
39
- secrets (see below).
41
n = total_sectors - sector_num;
40
+ A listen socket can be provided via file descriptor passing (see Examples
42
if (n < nb_sectors) {
41
+ below). TLS encryption can be configured using ``--object`` tls-creds-* and
42
+ authz-* secrets (see below).
43
44
To configure an NBD server on UNIX domain socket path ``/tmp/nbd.sock``::
45
46
@@ -XXX,XX +XXX,XX @@ QMP commands::
47
--chardev socket,path=qmp.sock,server=on,wait=off,id=char1 \
48
--monitor chardev=char1
49
50
+Launch the daemon from Python with a QMP monitor socket using file descriptor
51
+passing so there is no need to busy wait for the QMP monitor to become
52
+available::
53
+
54
+ #!/usr/bin/env python3
55
+ import subprocess
56
+ import socket
57
+
58
+ sock_path = '/var/run/qmp.sock'
59
+
60
+ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as listen_sock:
61
+ listen_sock.bind(sock_path)
62
+ listen_sock.listen()
63
+
64
+ fd = listen_sock.fileno()
65
+
66
+ subprocess.Popen(
67
+ ['qemu-storage-daemon',
68
+ '--chardev', f'socket,fd={fd},server=on,id=char1',
69
+ '--monitor', 'chardev=char1'],
70
+ pass_fds=[fd],
71
+ )
72
+
73
+ # listen_sock was automatically closed when leaving the 'with' statement
74
+ # body. If the daemon process terminated early then the following connect()
75
+ # will fail with "Connection refused" because no process has the listen
76
+ # socket open anymore. Launch errors can be detected this way.
77
+
78
+ qmp_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
79
+ qmp_sock.connect(sock_path)
80
+ ...QMP interaction...
81
+
82
+The same socket spawning approach also works with the ``--nbd-server
83
+addr.type=fd,addr.str=<fd>`` and ``--export
84
+type=vhost-user-blk,addr.type=fd,addr.str=<fd>`` options.
85
+
86
Export raw image file ``disk.img`` over NBD UNIX domain socket ``nbd.sock``::
87
88
$ qemu-storage-daemon \
43
--
89
--
44
2.13.6
90
2.29.2
45
91
46
92
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Improve our braindead copy-on-read implementation. Pre-patch,
3
World-writeable directories have security issues. Avoid showing them in
4
we have multiple issues:
4
the documentation since someone might accidentally use them in
5
- we create a bounce buffer and perform a write for the entire
5
situations where they are insecure.
6
request, even if the active image already has 99% of the
7
clusters occupied, and really only needs to copy-on-read the
8
remaining 1% of the clusters
9
- our bounce buffer was as large as the read request, and can
10
needlessly exhaust our memory by using double the memory of
11
the request size (the original request plus our bounce buffer),
12
rather than a capped maximum overhead beyond the original
13
- if a driver has a max_transfer limit, we are bypassing the
14
normal code in bdrv_aligned_preadv() that fragments to that
15
limit, and instead attempt to read the entire buffer from the
16
driver in one go, which some drivers may assert on
17
- a client can request a large request of nearly 2G such that
18
rounding the request out to cluster boundaries results in a
19
byte count larger than 2G. While this cannot exceed 32 bits,
20
it DOES have some follow-on problems:
21
-- the call to bdrv_driver_pread() can assert for exceeding
22
BDRV_REQUEST_MAX_BYTES, if the driver is old and lacks
23
.bdrv_co_preadv
24
-- if the buffer is all zeroes, the subsequent call to
25
bdrv_co_do_pwrite_zeroes is a no-op due to a negative size,
26
which means we did not actually copy on read
27
6
28
Fix all of these issues by breaking up the action into a loop,
7
There tend to be 3 security problems:
29
where each iteration is capped to sane limits. Also, querying
8
1. Denial of service. An adversary may be able to create the file
30
the allocation status allows us to optimize: when data is
9
beforehand, consume all space/inodes, etc to sabotage us.
31
already present in the active layer, we don't need to bounce.
10
2. Impersonation. An adversary may be able to create a listen socket and
11
accept incoming connections that were meant for us.
12
3. Unauthenticated client access. An adversary may be able to connect to
13
us if we did not set the uid/gid and permissions correctly.
32
14
33
Note that the code has a telling comment that copy-on-read
15
These can be prevented or mitigated with private /tmp, carefully setting
34
should probably be a filter driver rather than a bolt-on hack
16
the umask, etc but that requires special action and does not apply to
35
in io.c; but that remains a task for another day.
17
all situations. Just avoid using /tmp in examples.
36
18
37
CC: qemu-stable@nongnu.org
19
Reported-by: Richard W.M. Jones <rjones@redhat.com>
38
Signed-off-by: Eric Blake <eblake@redhat.com>
20
Reported-by: Daniel P. Berrangé <berrange@redhat.com>
39
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
40
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Message-Id: <20210301172728.135331-3-stefanha@redhat.com>
23
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
24
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
41
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
42
---
26
---
43
block/io.c | 120 +++++++++++++++++++++++++++++++++++++++++--------------------
27
docs/tools/qemu-storage-daemon.rst | 7 ++++---
44
1 file changed, 82 insertions(+), 38 deletions(-)
28
1 file changed, 4 insertions(+), 3 deletions(-)
45
29
46
diff --git a/block/io.c b/block/io.c
30
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
47
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
48
--- a/block/io.c
32
--- a/docs/tools/qemu-storage-daemon.rst
49
+++ b/block/io.c
33
+++ b/docs/tools/qemu-storage-daemon.rst
50
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ Standard options:
51
35
a description of character device properties. A common character device
52
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
36
definition configures a UNIX domain socket::
53
37
54
+/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
38
- --chardev socket,id=char1,path=/tmp/qmp.sock,server=on,wait=off
55
+#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
39
+ --chardev socket,id=char1,path=/var/run/qsd-qmp.sock,server=on,wait=off
56
+
40
57
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
41
.. option:: --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>][,writable=on|off][,bitmap=<name>]
58
int64_t offset, int bytes, BdrvRequestFlags flags);
42
--export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>]
59
43
@@ -XXX,XX +XXX,XX @@ Standard options:
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
44
below). TLS encryption can be configured using ``--object`` tls-creds-* and
61
45
authz-* secrets (see below).
62
BlockDriver *drv = bs->drv;
46
63
struct iovec iov;
47
- To configure an NBD server on UNIX domain socket path ``/tmp/nbd.sock``::
64
- QEMUIOVector bounce_qiov;
48
+ To configure an NBD server on UNIX domain socket path
65
+ QEMUIOVector local_qiov;
49
+ ``/var/run/qsd-nbd.sock``::
66
int64_t cluster_offset;
50
67
unsigned int cluster_bytes;
51
- --nbd-server addr.type=unix,addr.path=/tmp/nbd.sock
68
size_t skip_bytes;
52
+ --nbd-server addr.type=unix,addr.path=/var/run/qsd-nbd.sock
69
int ret;
53
70
+ int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
54
.. option:: --object help
71
+ BDRV_REQUEST_MAX_BYTES);
55
--object <type>,help
72
+ unsigned int progress = 0;
73
74
/* FIXME We cannot require callers to have write permissions when all they
75
* are doing is a read request. If we did things right, write permissions
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
77
// assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
78
79
/* Cover entire cluster so no additional backing file I/O is required when
80
- * allocating cluster in the image file.
81
+ * allocating cluster in the image file. Note that this value may exceed
82
+ * BDRV_REQUEST_MAX_BYTES (even when the original read did not), which
83
+ * is one reason we loop rather than doing it all at once.
84
*/
85
bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
86
+ skip_bytes = offset - cluster_offset;
87
88
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
89
cluster_offset, cluster_bytes);
90
91
- iov.iov_len = cluster_bytes;
92
- iov.iov_base = bounce_buffer = qemu_try_blockalign(bs, iov.iov_len);
93
+ bounce_buffer = qemu_try_blockalign(bs,
94
+ MIN(MIN(max_transfer, cluster_bytes),
95
+ MAX_BOUNCE_BUFFER));
96
if (bounce_buffer == NULL) {
97
ret = -ENOMEM;
98
goto err;
99
}
100
101
- qemu_iovec_init_external(&bounce_qiov, &iov, 1);
102
+ while (cluster_bytes) {
103
+ int64_t pnum;
104
105
- ret = bdrv_driver_preadv(bs, cluster_offset, cluster_bytes,
106
- &bounce_qiov, 0);
107
- if (ret < 0) {
108
- goto err;
109
- }
110
+ ret = bdrv_is_allocated(bs, cluster_offset,
111
+ MIN(cluster_bytes, max_transfer), &pnum);
112
+ if (ret < 0) {
113
+ /* Safe to treat errors in querying allocation as if
114
+ * unallocated; we'll probably fail again soon on the
115
+ * read, but at least that will set a decent errno.
116
+ */
117
+ pnum = MIN(cluster_bytes, max_transfer);
118
+ }
119
120
- bdrv_debug_event(bs, BLKDBG_COR_WRITE);
121
- if (drv->bdrv_co_pwrite_zeroes &&
122
- buffer_is_zero(bounce_buffer, iov.iov_len)) {
123
- /* FIXME: Should we (perhaps conditionally) be setting
124
- * BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
125
- * that still correctly reads as zero? */
126
- ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, cluster_bytes, 0);
127
- } else {
128
- /* This does not change the data on the disk, it is not necessary
129
- * to flush even in cache=writethrough mode.
130
- */
131
- ret = bdrv_driver_pwritev(bs, cluster_offset, cluster_bytes,
132
- &bounce_qiov, 0);
133
- }
134
+ assert(skip_bytes < pnum);
135
136
- if (ret < 0) {
137
- /* It might be okay to ignore write errors for guest requests. If this
138
- * is a deliberate copy-on-read then we don't want to ignore the error.
139
- * Simply report it in all cases.
140
- */
141
- goto err;
142
- }
143
+ if (ret <= 0) {
144
+ /* Must copy-on-read; use the bounce buffer */
145
+ iov.iov_base = bounce_buffer;
146
+ iov.iov_len = pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
147
+ qemu_iovec_init_external(&local_qiov, &iov, 1);
148
149
- skip_bytes = offset - cluster_offset;
150
- qemu_iovec_from_buf(qiov, 0, bounce_buffer + skip_bytes, bytes);
151
+ ret = bdrv_driver_preadv(bs, cluster_offset, pnum,
152
+ &local_qiov, 0);
153
+ if (ret < 0) {
154
+ goto err;
155
+ }
156
+
157
+ bdrv_debug_event(bs, BLKDBG_COR_WRITE);
158
+ if (drv->bdrv_co_pwrite_zeroes &&
159
+ buffer_is_zero(bounce_buffer, pnum)) {
160
+ /* FIXME: Should we (perhaps conditionally) be setting
161
+ * BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
162
+ * that still correctly reads as zero? */
163
+ ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, 0);
164
+ } else {
165
+ /* This does not change the data on the disk, it is not
166
+ * necessary to flush even in cache=writethrough mode.
167
+ */
168
+ ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
169
+ &local_qiov, 0);
170
+ }
171
+
172
+ if (ret < 0) {
173
+ /* It might be okay to ignore write errors for guest
174
+ * requests. If this is a deliberate copy-on-read
175
+ * then we don't want to ignore the error. Simply
176
+ * report it in all cases.
177
+ */
178
+ goto err;
179
+ }
180
+
181
+ qemu_iovec_from_buf(qiov, progress, bounce_buffer + skip_bytes,
182
+ pnum - skip_bytes);
183
+ } else {
184
+ /* Read directly into the destination */
185
+ qemu_iovec_init(&local_qiov, qiov->niov);
186
+ qemu_iovec_concat(&local_qiov, qiov, progress, pnum - skip_bytes);
187
+ ret = bdrv_driver_preadv(bs, offset + progress, local_qiov.size,
188
+ &local_qiov, 0);
189
+ qemu_iovec_destroy(&local_qiov);
190
+ if (ret < 0) {
191
+ goto err;
192
+ }
193
+ }
194
+
195
+ cluster_offset += pnum;
196
+ cluster_bytes -= pnum;
197
+ progress += pnum - skip_bytes;
198
+ skip_bytes = 0;
199
+ }
200
+ ret = 0;
201
202
err:
203
qemu_vfree(bounce_buffer);
204
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num,
205
return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0);
206
}
207
208
-/* Maximum buffer for write zeroes fallback, in bytes */
209
-#define MAX_WRITE_ZEROES_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
210
-
211
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
212
int64_t offset, int bytes, BdrvRequestFlags flags)
213
{
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
215
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
216
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
217
bs->bl.request_alignment);
218
- int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
219
- MAX_WRITE_ZEROES_BOUNCE_BUFFER);
220
+ int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
221
222
assert(alignment % bs->bl.request_alignment == 0);
223
head = offset % alignment;
224
--
56
--
225
2.13.6
57
2.29.2
226
58
227
59
diff view generated by jsdifflib
1
We don't need to make any assumptions about the graph layout above the
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
top node of the commit operation any more. Remove the use of
3
bdrv_find_overlay() and related variables from the commit job code.
4
2
5
bdrv_drop_intermediate() doesn't use the 'active' parameter any more, so
3
Treat the num_queues field as virtio-endian. On big-endian hosts the
6
we can just drop it.
4
vhost-user-blk num_queues field was in the wrong endianness.
7
5
8
The overlay node was previously added to the block job to get a
6
Move the blkcfg.num_queues store operation from realize to
9
BLK_PERM_GRAPH_MOD. We really need to respect those permissions in
7
vhost_user_blk_update_config() so feature negotiation has finished and
10
bdrv_drop_intermediate() now, but as long as we haven't figured out yet
8
we know the endianness of the device. VIRTIO 1.0 devices are
11
how BLK_PERM_GRAPH_MOD is actually supposed to work, just leave a TODO
9
little-endian, but in case someone wants to use legacy VIRTIO we support
12
comment there.
10
all endianness cases.
13
11
14
With this change, it is now possible to perform another block job on an
12
Cc: qemu-stable@nongnu.org
15
overlay node without conflicts. qemu-iotests 030 is changed accordingly.
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
15
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
16
Message-Id: <20210223144653.811468-2-stefanha@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
hw/block/vhost-user-blk.c | 7 +++----
20
1 file changed, 3 insertions(+), 4 deletions(-)
16
21
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
---
20
include/block/block.h | 3 +--
21
block.c | 6 +++--
22
block/commit.c | 62 ++++++++++++--------------------------------------
23
tests/qemu-iotests/030 | 4 ----
24
4 files changed, 20 insertions(+), 55 deletions(-)
25
26
diff --git a/include/block/block.h b/include/block/block.h
27
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/block.h
24
--- a/hw/block/vhost-user-blk.c
29
+++ b/include/block/block.h
25
+++ b/hw/block/vhost-user-blk.c
30
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs);
26
@@ -XXX,XX +XXX,XX @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
31
int bdrv_change_backing_file(BlockDriverState *bs,
32
const char *backing_file, const char *backing_fmt);
33
void bdrv_register(BlockDriver *bdrv);
34
-int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
35
- BlockDriverState *base,
36
+int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
37
const char *backing_file_str);
38
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
39
BlockDriverState *bs);
40
diff --git a/block.c b/block.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block.c
43
+++ b/block.c
44
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
45
* if active == top, that is considered an error
46
*
47
*/
48
-int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
49
- BlockDriverState *base, const char *backing_file_str)
50
+int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
51
+ const char *backing_file_str)
52
{
27
{
53
BdrvChild *c, *next;
28
VHostUserBlk *s = VHOST_USER_BLK(vdev);
54
Error *local_err = NULL;
29
55
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
30
+ /* Our num_queues overrides the device backend */
31
+ virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues);
32
+
33
memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config));
34
}
35
36
@@ -XXX,XX +XXX,XX @@ reconnect:
37
goto reconnect;
56
}
38
}
57
39
58
/* success - we can delete the intermediate states, and link top->base */
40
- if (s->blkcfg.num_queues != s->num_queues) {
59
+ /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
41
- s->blkcfg.num_queues = s->num_queues;
60
+ * we've figured out how they should work. */
61
backing_file_str = backing_file_str ? backing_file_str : base->filename;
62
63
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
64
diff --git a/block/commit.c b/block/commit.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/commit.c
67
+++ b/block/commit.c
68
@@ -XXX,XX +XXX,XX @@ enum {
69
typedef struct CommitBlockJob {
70
BlockJob common;
71
RateLimit limit;
72
- BlockDriverState *active;
73
BlockDriverState *commit_top_bs;
74
BlockBackend *top;
75
BlockBackend *base;
76
BlockdevOnError on_error;
77
int base_flags;
78
- int orig_overlay_flags;
79
char *backing_file_str;
80
} CommitBlockJob;
81
82
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
83
{
84
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
85
CommitCompleteData *data = opaque;
86
- BlockDriverState *active = s->active;
87
BlockDriverState *top = blk_bs(s->top);
88
BlockDriverState *base = blk_bs(s->base);
89
- BlockDriverState *overlay_bs = bdrv_find_overlay(active, s->commit_top_bs);
90
+ BlockDriverState *commit_top_bs = s->commit_top_bs;
91
int ret = data->ret;
92
bool remove_commit_top_bs = false;
93
94
- /* Make sure overlay_bs and top stay around until bdrv_set_backing_hd() */
95
+ /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
96
bdrv_ref(top);
97
- if (overlay_bs) {
98
- bdrv_ref(overlay_bs);
99
- }
100
+ bdrv_ref(commit_top_bs);
101
102
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
103
* the normal backing chain can be restored. */
104
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
105
106
if (!block_job_is_cancelled(&s->common) && ret == 0) {
107
/* success */
108
- ret = bdrv_drop_intermediate(active, s->commit_top_bs, base,
109
+ ret = bdrv_drop_intermediate(s->commit_top_bs, base,
110
s->backing_file_str);
111
- } else if (overlay_bs) {
112
+ } else {
113
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
114
* after the failed/cancelled commit job is gone? If we already wrote
115
* something to base, the intermediate images aren't valid any more. */
116
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
117
if (s->base_flags != bdrv_get_flags(base)) {
118
bdrv_reopen(base, s->base_flags, NULL);
119
}
120
- if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
121
- bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
122
- }
123
g_free(s->backing_file_str);
124
blk_unref(s->top);
125
126
@@ -XXX,XX +XXX,XX @@ static void commit_complete(BlockJob *job, void *opaque)
127
* filter driver from the backing chain. Do this as the final step so that
128
* the 'consistent read' permission can be granted. */
129
if (remove_commit_top_bs) {
130
- bdrv_set_backing_hd(overlay_bs, top, &error_abort);
131
+ bdrv_child_try_set_perm(commit_top_bs->backing, 0, BLK_PERM_ALL,
132
+ &error_abort);
133
+ bdrv_replace_node(commit_top_bs, backing_bs(commit_top_bs),
134
+ &error_abort);
135
}
136
137
- bdrv_unref(overlay_bs);
138
+ bdrv_unref(commit_top_bs);
139
bdrv_unref(top);
140
}
141
142
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
143
{
144
CommitBlockJob *s;
145
BlockReopenQueue *reopen_queue = NULL;
146
- int orig_overlay_flags;
147
int orig_base_flags;
148
BlockDriverState *iter;
149
- BlockDriverState *overlay_bs;
150
BlockDriverState *commit_top_bs = NULL;
151
Error *local_err = NULL;
152
int ret;
153
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
154
return;
155
}
156
157
- overlay_bs = bdrv_find_overlay(bs, top);
158
-
159
- if (overlay_bs == NULL) {
160
- error_setg(errp, "Could not find overlay image for %s:", top->filename);
161
- return;
162
- }
42
- }
163
-
43
-
164
s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
44
return;
165
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
45
166
if (!s) {
46
virtio_err:
167
return;
168
}
169
170
- orig_base_flags = bdrv_get_flags(base);
171
- orig_overlay_flags = bdrv_get_flags(overlay_bs);
172
-
173
- /* convert base & overlay_bs to r/w, if necessary */
174
+ /* convert base to r/w, if necessary */
175
+ orig_base_flags = bdrv_get_flags(base);
176
if (!(orig_base_flags & BDRV_O_RDWR)) {
177
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
178
orig_base_flags | BDRV_O_RDWR);
179
}
180
- if (!(orig_overlay_flags & BDRV_O_RDWR)) {
181
- reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
182
- orig_overlay_flags | BDRV_O_RDWR);
183
- }
184
+
185
if (reopen_queue) {
186
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
187
if (local_err != NULL) {
188
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
189
goto fail;
190
}
191
192
- /* overlay_bs must be blocked because it needs to be modified to
193
- * update the backing image string. */
194
- ret = block_job_add_bdrv(&s->common, "overlay of top", overlay_bs,
195
- BLK_PERM_GRAPH_MOD, BLK_PERM_ALL, errp);
196
- if (ret < 0) {
197
- goto fail;
198
- }
199
-
200
s->base = blk_new(BLK_PERM_CONSISTENT_READ
201
| BLK_PERM_WRITE
202
| BLK_PERM_RESIZE,
203
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
204
goto fail;
205
}
206
207
- s->active = bs;
208
-
209
- s->base_flags = orig_base_flags;
210
- s->orig_overlay_flags = orig_overlay_flags;
211
-
212
+ s->base_flags = orig_base_flags;
213
s->backing_file_str = g_strdup(backing_file_str);
214
-
215
s->on_error = on_error;
216
217
trace_commit_start(bs, base, top, s);
218
@@ -XXX,XX +XXX,XX @@ fail:
219
blk_unref(s->top);
220
}
221
if (commit_top_bs) {
222
- bdrv_set_backing_hd(overlay_bs, top, &error_abort);
223
+ bdrv_replace_node(commit_top_bs, top, &error_abort);
224
}
225
block_job_early_fail(&s->common);
226
}
227
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
228
index XXXXXXX..XXXXXXX 100755
229
--- a/tests/qemu-iotests/030
230
+++ b/tests/qemu-iotests/030
231
@@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase):
232
result = self.vm.qmp('block-stream', device='node6', base=self.imgs[4], job_id='stream-node6-v2')
233
self.assert_qmp(result, 'error/class', 'GenericError')
234
235
- # This fails because block-commit needs to block node6, the overlay of the 'top' image
236
- result = self.vm.qmp('block-stream', device='node7', base=self.imgs[5], job_id='stream-node6-v3')
237
- self.assert_qmp(result, 'error/class', 'GenericError')
238
-
239
# This fails because block-commit currently blocks the active layer even if it's not used
240
result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0')
241
self.assert_qmp(result, 'error/class', 'GenericError')
242
--
47
--
243
2.13.6
48
2.29.2
244
49
245
50
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3
Add an API that returns a new UNIX domain socket in the listen state.
4
Reviewed-by: Eric Blake <eblake@redhat.com>
4
The code for this was already there but only used internally in
5
init_socket().
6
7
This new API will be used by vhost-user-blk-test.
8
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Thomas Huth <thuth@redhat.com>
11
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
12
Message-Id: <20210223144653.811468-3-stefanha@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
14
---
7
tests/qemu-iotests/check | 4 ++--
15
tests/qtest/libqos/libqtest.h | 8 +++++++
8
tests/qemu-iotests/common | 2 +-
16
tests/qtest/libqtest.c | 40 ++++++++++++++++++++---------------
9
tests/qemu-iotests/common.config | 3 ---
17
2 files changed, 31 insertions(+), 17 deletions(-)
10
3 files changed, 3 insertions(+), 6 deletions(-)
11
18
12
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
19
diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
13
index XXXXXXX..XXXXXXX 100755
20
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/check
21
--- a/tests/qtest/libqos/libqtest.h
15
+++ b/tests/qemu-iotests/check
22
+++ b/tests/qtest/libqos/libqtest.h
16
@@ -XXX,XX +XXX,XX @@ tmp="${TEST_DIR}"/$$
23
@@ -XXX,XX +XXX,XX @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...)
17
24
void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
18
_wallclock()
25
GCC_FMT_ATTR(2, 3);
26
27
+/**
28
+ * qtest_socket_server:
29
+ * @socket_path: the UNIX domain socket path
30
+ *
31
+ * Create and return a listen socket file descriptor, or abort on failure.
32
+ */
33
+int qtest_socket_server(const char *socket_path);
34
+
35
/**
36
* qtest_vqmp_fds:
37
* @s: #QTestState instance to operate on.
38
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/tests/qtest/libqtest.c
41
+++ b/tests/qtest/libqtest.c
42
@@ -XXX,XX +XXX,XX @@ static void qtest_client_set_rx_handler(QTestState *s, QTestRecvFn recv);
43
44
static int init_socket(const char *socket_path)
19
{
45
{
20
- date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }'
46
- struct sockaddr_un addr;
21
+ date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
47
- int sock;
48
- int ret;
49
-
50
- sock = socket(PF_UNIX, SOCK_STREAM, 0);
51
- g_assert_cmpint(sock, !=, -1);
52
-
53
- addr.sun_family = AF_UNIX;
54
- snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
55
+ int sock = qtest_socket_server(socket_path);
56
qemu_set_cloexec(sock);
57
-
58
- do {
59
- ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
60
- } while (ret == -1 && errno == EINTR);
61
- g_assert_cmpint(ret, !=, -1);
62
- ret = listen(sock, 1);
63
- g_assert_cmpint(ret, !=, -1);
64
-
65
return sock;
22
}
66
}
23
67
24
_timestamp()
68
@@ -XXX,XX +XXX,XX @@ QDict *qtest_qmp_receive_dict(QTestState *s)
25
@@ -XXX,XX +XXX,XX @@ _wrapup()
69
return qmp_fd_receive(s->qmp_fd);
26
if [ -f $TIMESTAMP_FILE -a -f $tmp.time ]
27
then
28
cat $TIMESTAMP_FILE $tmp.time \
29
- | $AWK_PROG '
30
+ | awk '
31
{ t[$1] = $2 }
32
END { if (NR > 0) {
33
for (i in t) print i " " t[i]
34
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
35
index XXXXXXX..XXXXXXX 100644
36
--- a/tests/qemu-iotests/common
37
+++ b/tests/qemu-iotests/common
38
@@ -XXX,XX +XXX,XX @@ testlist options
39
if $xpand
40
then
41
have_test_arg=true
42
- $AWK_PROG </dev/null '
43
+ awk </dev/null '
44
BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
45
| while read id
46
do
47
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
48
index XXXXXXX..XXXXXXX 100644
49
--- a/tests/qemu-iotests/common.config
50
+++ b/tests/qemu-iotests/common.config
51
@@ -XXX,XX +XXX,XX @@ _fatal()
52
exit 1
53
}
70
}
54
71
55
-export AWK_PROG="`set_prog_path awk`"
72
+int qtest_socket_server(const char *socket_path)
56
-[ "$AWK_PROG" = "" ] && _fatal "awk not found"
73
+{
57
-
74
+ struct sockaddr_un addr;
58
if [ -z "$QEMU_PROG" ]; then
75
+ int sock;
59
export QEMU_PROG="`set_prog_path qemu`"
76
+ int ret;
60
fi
77
+
78
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
79
+ g_assert_cmpint(sock, !=, -1);
80
+
81
+ addr.sun_family = AF_UNIX;
82
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
83
+
84
+ do {
85
+ ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
86
+ } while (ret == -1 && errno == EINTR);
87
+ g_assert_cmpint(ret, !=, -1);
88
+ ret = listen(sock, 1);
89
+ g_assert_cmpint(ret, !=, -1);
90
+
91
+ return sock;
92
+}
93
+
94
/**
95
* Allow users to send a message without waiting for the reply,
96
* in the case that they choose to discard all replies up until
61
--
97
--
62
2.13.6
98
2.29.2
63
99
64
100
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Split "check" parts from tests part.
3
Tests that manage multiple processes may wish to kill QEMU before
4
destroying the QTestState. Expose a function to do that.
4
5
5
For the directory setup, the actual computation of directories goes
6
The vhost-user-blk-test testcase will need this.
6
in "check", while the sanity checks go in the tests.
7
7
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
10
Message-Id: <20210223144653.811468-4-stefanha@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
---
12
tests/qemu-iotests/common | 24 ++++++++++++++++++++
13
tests/qtest/libqos/libqtest.h | 11 +++++++++++
13
tests/qemu-iotests/common.config | 49 ----------------------------------------
14
tests/qtest/libqtest.c | 7 ++++---
14
tests/qemu-iotests/common.qemu | 1 +
15
2 files changed, 15 insertions(+), 3 deletions(-)
15
tests/qemu-iotests/common.rc | 25 ++++++++++++++++++++
16
4 files changed, 50 insertions(+), 49 deletions(-)
17
16
18
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
17
diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/common
19
--- a/tests/qtest/libqos/libqtest.h
21
+++ b/tests/qemu-iotests/common
20
+++ b/tests/qtest/libqos/libqtest.h
22
@@ -XXX,XX +XXX,XX @@ set_prog_path()
21
@@ -XXX,XX +XXX,XX @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
23
fi
22
*/
23
QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd);
24
25
+/**
26
+ * qtest_kill_qemu:
27
+ * @s: #QTestState instance to operate on.
28
+ *
29
+ * Kill the QEMU process and wait for it to terminate. It is safe to call this
30
+ * function multiple times. Normally qtest_quit() is used instead because it
31
+ * also frees QTestState. Use qtest_kill_qemu() when you just want to kill QEMU
32
+ * and qtest_quit() will be called later.
33
+ */
34
+void qtest_kill_qemu(QTestState *s);
35
+
36
/**
37
* qtest_quit:
38
* @s: #QTestState instance to operate on.
39
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/tests/qtest/libqtest.c
42
+++ b/tests/qtest/libqtest.c
43
@@ -XXX,XX +XXX,XX @@ void qtest_set_expected_status(QTestState *s, int status)
44
s->expected_status = status;
24
}
45
}
25
46
26
+if [ -z "$TEST_DIR" ]; then
47
-static void kill_qemu(QTestState *s)
27
+ TEST_DIR=`pwd`/scratch
48
+void qtest_kill_qemu(QTestState *s)
28
+fi
49
{
29
+
50
pid_t pid = s->qemu_pid;
30
+if [ ! -e "$TEST_DIR" ]; then
51
int wstatus;
31
+ mkdir "$TEST_DIR"
52
@@ -XXX,XX +XXX,XX @@ static void kill_qemu(QTestState *s)
32
+fi
53
kill(pid, SIGTERM);
33
+
54
TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0));
34
diff="diff -u"
55
assert(pid == s->qemu_pid);
35
verbose=false
56
+ s->qemu_pid = -1;
36
debug=false
57
}
37
@@ -XXX,XX +XXX,XX @@ if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null
58
38
IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
59
/*
39
fi
60
@@ -XXX,XX +XXX,XX @@ static void kill_qemu(QTestState *s)
40
61
41
+if [ -z "$SAMPLE_IMG_DIR" ]; then
62
static void kill_qemu_hook_func(void *s)
42
+ SAMPLE_IMG_DIR="$source_iotests/sample_images"
63
{
43
+fi
64
- kill_qemu(s);
44
+
65
+ qtest_kill_qemu(s);
45
+export TEST_DIR
46
+export SAMPLE_IMG_DIR
47
+
48
if [ -s $tmp.list ]
49
then
50
# found some valid test numbers ... this is good
51
@@ -XXX,XX +XXX,XX @@ if [ -x "$build_iotests/socket_scm_helper" ]
52
then
53
export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
54
fi
55
+
56
+default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
57
+default_alias_machine=$($QEMU_PROG -machine help | \
58
+ sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
59
+if [[ "$default_alias_machine" ]]; then
60
+ default_machine="$default_alias_machine"
61
+fi
62
+
63
+export QEMU_DEFAULT_MACHINE="$default_machine"
64
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
65
index XXXXXXX..XXXXXXX 100644
66
--- a/tests/qemu-iotests/common.config
67
+++ b/tests/qemu-iotests/common.config
68
@@ -XXX,XX +XXX,XX @@ arch=`uname -m`
69
70
export PWD=`pwd`
71
72
-export _QEMU_HANDLE=0
73
-
74
# make sure we have a standard umask
75
umask 022
76
77
@@ -XXX,XX +XXX,XX @@ _optstr_add()
78
fi
79
}
66
}
80
67
81
-QEMU_IMG_EXTRA_ARGS=
68
static void sigabrt_handler(int signo)
82
-if [ "$IMGOPTSSYNTAX" = "true" ]; then
69
@@ -XXX,XX +XXX,XX @@ void qtest_quit(QTestState *s)
83
- QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
70
/* Uninstall SIGABRT handler on last instance */
84
- if [ -n "$IMGKEYSECRET" ]; then
71
cleanup_sigabrt_handler();
85
- QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
72
86
- fi
73
- kill_qemu(s);
87
-fi
74
+ qtest_kill_qemu(s);
88
-export QEMU_IMG_EXTRA_ARGS
75
close(s->fd);
89
-
76
close(s->qmp_fd);
90
-
77
g_string_free(s->rx, true);
91
-default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
92
-default_alias_machine=$($QEMU_PROG -machine help | \
93
- sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
94
-if [[ "$default_alias_machine" ]]; then
95
- default_machine="$default_alias_machine"
96
-fi
97
-
98
-export QEMU_DEFAULT_MACHINE="$default_machine"
99
-
100
-if [ -z "$TEST_DIR" ]; then
101
- TEST_DIR=`pwd`/scratch
102
-fi
103
-
104
-QEMU_TEST_DIR="${TEST_DIR}"
105
-
106
-if [ ! -e "$TEST_DIR" ]; then
107
- mkdir "$TEST_DIR"
108
-fi
109
-
110
-if [ ! -d "$TEST_DIR" ]; then
111
- echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
112
- exit 1
113
-fi
114
-
115
-export TEST_DIR
116
-
117
-if [ -z "$SAMPLE_IMG_DIR" ]; then
118
- SAMPLE_IMG_DIR="$source_iotests/sample_images"
119
-fi
120
-
121
-if [ ! -d "$SAMPLE_IMG_DIR" ]; then
122
- echo "common.config: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
123
- exit 1
124
-fi
125
-
126
-export SAMPLE_IMG_DIR
127
-
128
# make sure this script returns success
129
true
130
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
131
index XXXXXXX..XXXXXXX 100644
132
--- a/tests/qemu-iotests/common.qemu
133
+++ b/tests/qemu-iotests/common.qemu
134
@@ -XXX,XX +XXX,XX @@ QEMU_FIFO_IN="${QEMU_TEST_DIR}/qmp-in-$$"
135
QEMU_FIFO_OUT="${QEMU_TEST_DIR}/qmp-out-$$"
136
137
QEMU_HANDLE=0
138
+export _QEMU_HANDLE=0
139
140
# If bash version is >= 4.1, these will be overwritten and dynamic
141
# file descriptor values assigned.
142
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
143
index XXXXXXX..XXXXXXX 100644
144
--- a/tests/qemu-iotests/common.rc
145
+++ b/tests/qemu-iotests/common.rc
146
@@ -XXX,XX +XXX,XX @@ export QEMU_VXHS=_qemu_vxhs_wrapper
147
148
if [ "$IMGOPTSSYNTAX" = "true" ]; then
149
DRIVER="driver=$IMGFMT"
150
+ QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
151
+ if [ -n "$IMGKEYSECRET" ]; then
152
+ QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
153
+ fi
154
if [ "$IMGFMT" = "luks" ]; then
155
DRIVER="$DRIVER,key-secret=keysec0"
156
fi
157
@@ -XXX,XX +XXX,XX @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
158
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
159
fi
160
else
161
+ QEMU_IMG_EXTRA_ARGS=
162
if [ "$IMGPROTO" = "file" ]; then
163
TEST_IMG=$TEST_DIR/t.$IMGFMT
164
elif [ "$IMGPROTO" = "nbd" ]; then
165
@@ -XXX,XX +XXX,XX @@ else
166
fi
167
ORIG_TEST_IMG="$TEST_IMG"
168
169
+if [ -z "$TEST_DIR" ]; then
170
+ TEST_DIR=`pwd`/scratch
171
+fi
172
+
173
+QEMU_TEST_DIR="${TEST_DIR}"
174
+
175
+if [ ! -e "$TEST_DIR" ]; then
176
+ mkdir "$TEST_DIR"
177
+fi
178
+
179
+if [ ! -d "$TEST_DIR" ]; then
180
+ echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
181
+ exit 1
182
+fi
183
+
184
+if [ ! -d "$SAMPLE_IMG_DIR" ]; then
185
+ echo "common.config: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
186
+ exit 1
187
+fi
188
+
189
_use_sample_img()
190
{
191
SAMPLE_IMG_FILE="${1%\.bz2}"
192
--
78
--
193
2.13.6
79
2.29.2
194
80
195
81
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
These are never used by "check", with one exception that does not need
3
Add a function to remove previously-added abrt handler functions.
4
$QEMU_OPTIONS. Keep them in common.rc, which will be soon included only
5
by the tests.
6
4
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Now that a symmetric pair of add/remove functions exists we can also
8
Reviewed-by: Eric Blake <eblake@redhat.com>
6
balance the SIGABRT handler installation. The signal handler was
7
installed each time qtest_add_abrt_handler() was called. Now it is
8
installed when the abrt handler list becomes non-empty and removed again
9
when the list becomes empty.
10
11
The qtest_remove_abrt_handler() function will be used by
12
vhost-user-blk-test.
13
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
16
Message-Id: <20210223144653.811468-5-stefanha@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
18
---
11
tests/qemu-iotests/039.out | 10 +++---
19
tests/qtest/libqos/libqtest.h | 18 ++++++++++++++++++
12
tests/qemu-iotests/061.out | 4 +--
20
tests/qtest/libqtest.c | 35 +++++++++++++++++++++++++++++------
13
tests/qemu-iotests/137.out | 2 +-
21
2 files changed, 47 insertions(+), 6 deletions(-)
14
tests/qemu-iotests/common.config | 69 ++--------------------------------------
15
tests/qemu-iotests/common.rc | 65 +++++++++++++++++++++++++++++++++++++
16
5 files changed, 75 insertions(+), 75 deletions(-)
17
22
18
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
23
diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
19
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/039.out
25
--- a/tests/qtest/libqos/libqtest.h
21
+++ b/tests/qemu-iotests/039.out
26
+++ b/tests/qtest/libqos/libqtest.h
22
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
27
@@ -XXX,XX +XXX,XX @@ void qtest_add_data_func_full(const char *str, void *data,
23
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
28
g_free(path); \
24
wrote 512/512 bytes at offset 0
29
} while (0)
25
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
30
26
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
31
+/**
27
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
32
+ * qtest_add_abrt_handler:
28
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
33
+ * @fn: Handler function
29
else
34
+ * @data: Argument that is passed to the handler
30
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
35
+ *
31
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0
36
+ * Add a handler function that is invoked on SIGABRT. This can be used to
32
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
37
+ * terminate processes and perform other cleanup. The handler can be removed
33
wrote 512/512 bytes at offset 0
38
+ * with qtest_remove_abrt_handler().
34
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
39
+ */
35
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
40
void qtest_add_abrt_handler(GHookFunc fn, const void *data);
36
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
41
37
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
42
+/**
38
else
43
+ * qtest_remove_abrt_handler:
39
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
44
+ * @data: Argument previously passed to qtest_add_abrt_handler()
40
@@ -XXX,XX +XXX,XX @@ incompatible_features 0x0
45
+ *
41
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
46
+ * Remove an abrt handler that was previously added with
42
wrote 512/512 bytes at offset 0
47
+ * qtest_add_abrt_handler().
43
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
48
+ */
44
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
49
+void qtest_remove_abrt_handler(void *data);
45
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
50
+
46
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
51
/**
47
else
52
* qtest_qmp_assert_success:
48
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
53
* @qts: QTestState instance to operate on
49
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
54
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
50
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
51
wrote 512/512 bytes at offset 0
52
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
53
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
54
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
55
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
56
else
57
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
58
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
59
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
60
wrote 512/512 bytes at offset 0
61
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
62
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
63
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
64
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
65
else
66
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
67
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
68
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/061.out
56
--- a/tests/qtest/libqtest.c
70
+++ b/tests/qemu-iotests/061.out
57
+++ b/tests/qtest/libqtest.c
71
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
58
@@ -XXX,XX +XXX,XX @@ static void cleanup_sigabrt_handler(void)
72
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
59
sigaction(SIGABRT, &sigact_old, NULL);
73
wrote 131072/131072 bytes at offset 0
74
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
76
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
77
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
78
else
79
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
80
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
81
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
82
wrote 131072/131072 bytes at offset 0
83
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
84
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
85
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
86
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
87
else
88
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
89
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
90
index XXXXXXX..XXXXXXX 100644
91
--- a/tests/qemu-iotests/137.out
92
+++ b/tests/qemu-iotests/137.out
93
@@ -XXX,XX +XXX,XX @@ Cache clean interval too big
94
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
95
wrote 512/512 bytes at offset 0
96
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
97
-./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
98
+./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
99
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
100
else
101
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
102
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
103
index XXXXXXX..XXXXXXX 100644
104
--- a/tests/qemu-iotests/common.config
105
+++ b/tests/qemu-iotests/common.config
106
@@ -XXX,XX +XXX,XX @@ _optstr_add()
107
fi
108
}
60
}
109
61
110
-_qemu_wrapper()
62
+static bool hook_list_is_empty(GHookList *hook_list)
111
-{
112
- (
113
- if [ -n "${QEMU_NEED_PID}" ]; then
114
- echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
115
- fi
116
- exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
117
- )
118
-}
119
-
120
-_qemu_img_wrapper()
121
-{
122
- (exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
123
-}
124
-
125
-_qemu_io_wrapper()
126
-{
127
- local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
128
- local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
129
- if [ "$IMGOPTSSYNTAX" = "true" ]; then
130
- QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
131
- if [ -n "$IMGKEYSECRET" ]; then
132
- QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
133
- fi
134
- fi
135
- local RETVAL
136
- (
137
- if [ "${VALGRIND_QEMU}" == "y" ]; then
138
- exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
139
- else
140
- exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
141
- fi
142
- )
143
- RETVAL=$?
144
- if [ "${VALGRIND_QEMU}" == "y" ]; then
145
- if [ $RETVAL == 99 ]; then
146
- cat "${VALGRIND_LOGFILE}"
147
- fi
148
- rm -f "${VALGRIND_LOGFILE}"
149
- fi
150
- (exit $RETVAL)
151
-}
152
-
153
-_qemu_nbd_wrapper()
154
-{
155
- (
156
- echo $BASHPID > "${QEMU_TEST_DIR}/qemu-nbd.pid"
157
- exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
158
- )
159
-}
160
-
161
-_qemu_vxhs_wrapper()
162
-{
163
- (
164
- echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
165
- exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
166
- )
167
-}
168
-
169
-export QEMU=_qemu_wrapper
170
-export QEMU_IMG=_qemu_img_wrapper
171
-export QEMU_IO=_qemu_io_wrapper
172
-export QEMU_NBD=_qemu_nbd_wrapper
173
-export QEMU_VXHS=_qemu_vxhs_wrapper
174
-
175
QEMU_IMG_EXTRA_ARGS=
176
if [ "$IMGOPTSSYNTAX" = "true" ]; then
177
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
178
@@ -XXX,XX +XXX,XX @@ fi
179
export QEMU_IMG_EXTRA_ARGS
180
181
182
-default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p')
183
-default_alias_machine=$($QEMU -machine help | \
184
+default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
185
+default_alias_machine=$($QEMU_PROG -machine help | \
186
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
187
if [[ "$default_alias_machine" ]]; then
188
default_machine="$default_alias_machine"
189
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
190
index XXXXXXX..XXXXXXX 100644
191
--- a/tests/qemu-iotests/common.rc
192
+++ b/tests/qemu-iotests/common.rc
193
@@ -XXX,XX +XXX,XX @@ then
194
fi
195
fi
196
197
+_qemu_wrapper()
198
+{
63
+{
199
+ (
64
+ GHook *hook = g_hook_first_valid(hook_list, TRUE);
200
+ if [ -n "${QEMU_NEED_PID}" ]; then
65
+
201
+ echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
66
+ if (!hook) {
202
+ fi
67
+ return false;
203
+ exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
68
+ }
204
+ )
69
+
70
+ g_hook_unref(hook_list, hook);
71
+ return true;
205
+}
72
+}
206
+
73
+
207
+_qemu_img_wrapper()
74
void qtest_add_abrt_handler(GHookFunc fn, const void *data)
75
{
76
GHook *hook;
77
78
- /* Only install SIGABRT handler once */
79
if (!abrt_hooks.is_setup) {
80
g_hook_list_init(&abrt_hooks, sizeof(GHook));
81
}
82
- setup_sigabrt_handler();
83
+
84
+ /* Only install SIGABRT handler once */
85
+ if (hook_list_is_empty(&abrt_hooks)) {
86
+ setup_sigabrt_handler();
87
+ }
88
89
hook = g_hook_alloc(&abrt_hooks);
90
hook->func = fn;
91
@@ -XXX,XX +XXX,XX @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
92
g_hook_prepend(&abrt_hooks, hook);
93
}
94
95
+void qtest_remove_abrt_handler(void *data)
208
+{
96
+{
209
+ (exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
97
+ GHook *hook = g_hook_find_data(&abrt_hooks, TRUE, data);
98
+ g_hook_destroy_link(&abrt_hooks, hook);
99
+
100
+ /* Uninstall SIGABRT handler on last instance */
101
+ if (hook_list_is_empty(&abrt_hooks)) {
102
+ cleanup_sigabrt_handler();
103
+ }
210
+}
104
+}
211
+
105
+
212
+_qemu_io_wrapper()
106
static const char *qtest_qemu_binary(void)
213
+{
107
{
214
+ local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
108
const char *qemu_bin;
215
+ local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
109
@@ -XXX,XX +XXX,XX @@ QTestState *qtest_init_with_serial(const char *extra_args, int *sock_fd)
216
+ if [ "$IMGOPTSSYNTAX" = "true" ]; then
110
217
+ QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
111
void qtest_quit(QTestState *s)
218
+ if [ -n "$IMGKEYSECRET" ]; then
112
{
219
+ QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
113
- g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s));
220
+ fi
114
-
221
+ fi
115
- /* Uninstall SIGABRT handler on last instance */
222
+ local RETVAL
116
- cleanup_sigabrt_handler();
223
+ (
117
+ qtest_remove_abrt_handler(s);
224
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
118
225
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
119
qtest_kill_qemu(s);
226
+ else
120
close(s->fd);
227
+ exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
228
+ fi
229
+ )
230
+ RETVAL=$?
231
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
232
+ if [ $RETVAL == 99 ]; then
233
+ cat "${VALGRIND_LOGFILE}"
234
+ fi
235
+ rm -f "${VALGRIND_LOGFILE}"
236
+ fi
237
+ (exit $RETVAL)
238
+}
239
+
240
+_qemu_nbd_wrapper()
241
+{
242
+ (
243
+ echo $BASHPID > "${QEMU_TEST_DIR}/qemu-nbd.pid"
244
+ exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
245
+ )
246
+}
247
+
248
+_qemu_vxhs_wrapper()
249
+{
250
+ (
251
+ echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
252
+ exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
253
+ )
254
+}
255
+
256
+export QEMU=_qemu_wrapper
257
+export QEMU_IMG=_qemu_img_wrapper
258
+export QEMU_IO=_qemu_io_wrapper
259
+export QEMU_NBD=_qemu_nbd_wrapper
260
+export QEMU_VXHS=_qemu_vxhs_wrapper
261
+
262
if [ "$IMGOPTSSYNTAX" = "true" ]; then
263
DRIVER="driver=$IMGFMT"
264
if [ "$IMGFMT" = "luks" ]; then
265
--
121
--
266
2.13.6
122
2.29.2
267
123
268
124
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
2
3
Add a test for qcow2 copy-on-read behavior, including exposure
3
This test case has the same tests as tests/virtio-blk-test.c except for
4
for the just-fixed bugs.
4
tests have block_resize. Since the vhost-user-blk export only serves one
5
client one time, two exports are started by qemu-storage-daemon for the
6
hotplug test.
5
7
6
The copy-on-read behavior is always to a qcow2 image, but the
8
Suggested-by: Thomas Huth <thuth@redhat.com>
7
test is careful to allow running with most image protocol/format
9
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
8
combos as the backing file being copied from (luks being the
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
exception, as it is harder to pass the right secret to all the
11
Message-Id: <20210223144653.811468-6-stefanha@redhat.com>
10
right places). In fact, for './check nbd', this appears to be
11
the first time we've had a qcow2 image wrapping NBD, requiring
12
an additional line in _filter_img_create to match the similar
13
line in _filter_img_info.
14
15
Invoking blkdebug to prove we don't write too much took some
16
effort to get working; and it requires that $TEST_WRAP (based
17
on $TEST_DIR) not be subject to word splitting. We may decide
18
later to have the entire iotests suite use relative rather than
19
absolute names, to avoid problems inherited by the absolute
20
name of $PWD or $TEST_DIR, at which point the sanity check in
21
this commit could be simplified.
22
23
This test requires at least 2G of consecutive memory to succeed;
24
as such, it is prone to spurious failures, particularly on
25
32-bit machines under load. This situation is detected and
26
triggers an early exit to skip the test, rather than a failure.
27
To manually provoke this setup on a beefier machine, I used:
28
$ (ulimit -S -v 1000000; ./check -qcow2 197)
29
30
Signed-off-by: Eric Blake <eblake@redhat.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
---
13
---
33
tests/qemu-iotests/197 | 109 +++++++++++++++++++++++++++++++++++++++
14
tests/qtest/libqos/vhost-user-blk.h | 48 ++
34
tests/qemu-iotests/197.out | 26 ++++++++++
15
tests/qtest/libqos/vhost-user-blk.c | 130 +++++
35
tests/qemu-iotests/common.filter | 1 +
16
tests/qtest/vhost-user-blk-test.c | 788 ++++++++++++++++++++++++++++
36
tests/qemu-iotests/group | 1 +
17
MAINTAINERS | 2 +
37
4 files changed, 137 insertions(+)
18
tests/qtest/libqos/meson.build | 1 +
38
create mode 100755 tests/qemu-iotests/197
19
tests/qtest/meson.build | 4 +
39
create mode 100644 tests/qemu-iotests/197.out
20
6 files changed, 973 insertions(+)
21
create mode 100644 tests/qtest/libqos/vhost-user-blk.h
22
create mode 100644 tests/qtest/libqos/vhost-user-blk.c
23
create mode 100644 tests/qtest/vhost-user-blk-test.c
40
24
41
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
25
diff --git a/tests/qtest/libqos/vhost-user-blk.h b/tests/qtest/libqos/vhost-user-blk.h
42
new file mode 100755
43
index XXXXXXX..XXXXXXX
44
--- /dev/null
45
+++ b/tests/qemu-iotests/197
46
@@ -XXX,XX +XXX,XX @@
47
+#!/bin/bash
48
+#
49
+# Test case for copy-on-read into qcow2
50
+#
51
+# Copyright (C) 2017 Red Hat, Inc.
52
+#
53
+# This program is free software; you can redistribute it and/or modify
54
+# it under the terms of the GNU General Public License as published by
55
+# the Free Software Foundation; either version 2 of the License, or
56
+# (at your option) any later version.
57
+#
58
+# This program is distributed in the hope that it will be useful,
59
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
60
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61
+# GNU General Public License for more details.
62
+#
63
+# You should have received a copy of the GNU General Public License
64
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
65
+#
66
+
67
+# creator
68
+owner=eblake@redhat.com
69
+
70
+seq="$(basename $0)"
71
+echo "QA output created by $seq"
72
+
73
+here="$PWD"
74
+status=1 # failure is the default!
75
+
76
+# get standard environment, filters and checks
77
+. ./common.rc
78
+. ./common.filter
79
+
80
+TEST_WRAP="$TEST_DIR/t.wrap.qcow2"
81
+BLKDBG_CONF="$TEST_DIR/blkdebug.conf"
82
+
83
+# Sanity check: our use of blkdebug fails if $TEST_DIR contains spaces
84
+# or other problems
85
+case "$TEST_DIR" in
86
+ *[^-_a-zA-Z0-9/]*)
87
+ _notrun "Suspicious TEST_DIR='$TEST_DIR', cowardly refusing to run" ;;
88
+esac
89
+
90
+_cleanup()
91
+{
92
+ _cleanup_test_img
93
+ rm -f "$BLKDBG_CONF"
94
+}
95
+trap "_cleanup; exit \$status" 0 1 2 3 15
96
+
97
+# Test is supported for any backing file; but we force qcow2 for our wrapper.
98
+_supported_fmt generic
99
+_supported_proto generic
100
+_supported_os Linux
101
+# LUKS support may be possible, but it complicates things.
102
+_unsupported_fmt luks
103
+
104
+echo
105
+echo '=== Copy-on-read ==='
106
+echo
107
+
108
+# Prep the images
109
+_make_test_img 4G
110
+$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
111
+IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
112
+ _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
113
+$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
114
+
115
+# Ensure that a read of two clusters, but where one is already allocated,
116
+# does not re-write the allocated cluster
117
+cat > "$BLKDBG_CONF" <<EOF
118
+[inject-error]
119
+event = "cor_write"
120
+sector = "2048"
121
+EOF
122
+$QEMU_IO -c "open -C \
123
+ -o driver=blkdebug,config=$BLKDBG_CONF,image.driver=qcow2 $TEST_WRAP" \
124
+ -c "read -P 0 1M 128k" | _filter_qemu_io
125
+
126
+# Read the areas we want copied. A zero-length read should still be a
127
+# no-op. The next read is under 2G, but aligned so that rounding to
128
+# clusters copies more than 2G of zeroes. The final read will pick up
129
+# the non-zero data in the same cluster. Since a 2G read may exhaust
130
+# memory on some machines (particularly 32-bit), we skip the test if
131
+# that fails due to memory pressure.
132
+$QEMU_IO -f qcow2 -C -c "read 0 0" "$TEST_WRAP" | _filter_qemu_io
133
+output=$($QEMU_IO -f qcow2 -C -c "read -P 0 1k $((2*1024*1024*1024 - 512))" \
134
+ "$TEST_WRAP" 2>&1 | _filter_qemu_io)
135
+case $output in
136
+ *allocate*)
137
+ _notrun "Insufficent memory to run test" ;;
138
+ *) printf '%s\n' "$output" ;;
139
+esac
140
+$QEMU_IO -f qcow2 -C -c "read -P 0 $((3*1024*1024*1024 + 1024)) 1k" \
141
+ "$TEST_WRAP" | _filter_qemu_io
142
+
143
+# Copy-on-read is incompatible with read-only
144
+$QEMU_IO -f qcow2 -C -r "$TEST_WRAP" 2>&1 | _filter_testdir
145
+
146
+# Break the backing chain, and show that images are identical, and that
147
+# we properly copied over explicit zeros.
148
+$QEMU_IMG rebase -u -b "" -f qcow2 "$TEST_WRAP"
149
+$QEMU_IO -f qcow2 -c map "$TEST_WRAP"
150
+_check_test_img
151
+$QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP"
152
+
153
+# success, all done
154
+echo '*** done'
155
+status=0
156
diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out
157
new file mode 100644
26
new file mode 100644
158
index XXXXXXX..XXXXXXX
27
index XXXXXXX..XXXXXXX
159
--- /dev/null
28
--- /dev/null
160
+++ b/tests/qemu-iotests/197.out
29
+++ b/tests/qtest/libqos/vhost-user-blk.h
161
@@ -XXX,XX +XXX,XX @@
30
@@ -XXX,XX +XXX,XX @@
162
+QA output created by 197
31
+/*
163
+
32
+ * libqos driver framework
164
+=== Copy-on-read ===
33
+ *
165
+
34
+ * Based on tests/qtest/libqos/virtio-blk.c
166
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296
35
+ *
167
+wrote 1024/1024 bytes at offset 3221225472
36
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
168
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
37
+ *
169
+Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
38
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
170
+wrote 65536/65536 bytes at offset 1048576
39
+ *
171
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
40
+ * This library is free software; you can redistribute it and/or
172
+read 131072/131072 bytes at offset 1048576
41
+ * modify it under the terms of the GNU Lesser General Public
173
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
42
+ * License version 2 as published by the Free Software Foundation.
174
+read 0/0 bytes at offset 0
43
+ *
175
+0 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
44
+ * This library is distributed in the hope that it will be useful,
176
+read 2147483136/2147483136 bytes at offset 1024
45
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
177
+2 GiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
46
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
178
+read 1024/1024 bytes at offset 3221226496
47
+ * Lesser General Public License for more details.
179
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
48
+ *
180
+can't open device TEST_DIR/t.wrap.qcow2: Can't use copy-on-read on read-only device
49
+ * You should have received a copy of the GNU Lesser General Public
181
+2 GiB (0x80010000) bytes allocated at offset 0 bytes (0x0)
50
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
182
+1023.938 MiB (0x3fff0000) bytes not allocated at offset 2 GiB (0x80010000)
51
+ */
183
+64 KiB (0x10000) bytes allocated at offset 3 GiB (0xc0000000)
52
+
184
+1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000)
53
+#ifndef TESTS_LIBQOS_VHOST_USER_BLK_H
185
+No errors were found on the image.
54
+#define TESTS_LIBQOS_VHOST_USER_BLK_H
186
+Images are identical.
55
+
187
+*** done
56
+#include "qgraph.h"
188
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
57
+#include "virtio.h"
58
+#include "virtio-pci.h"
59
+
60
+typedef struct QVhostUserBlk QVhostUserBlk;
61
+typedef struct QVhostUserBlkPCI QVhostUserBlkPCI;
62
+typedef struct QVhostUserBlkDevice QVhostUserBlkDevice;
63
+
64
+struct QVhostUserBlk {
65
+ QVirtioDevice *vdev;
66
+};
67
+
68
+struct QVhostUserBlkPCI {
69
+ QVirtioPCIDevice pci_vdev;
70
+ QVhostUserBlk blk;
71
+};
72
+
73
+struct QVhostUserBlkDevice {
74
+ QOSGraphObject obj;
75
+ QVhostUserBlk blk;
76
+};
77
+
78
+#endif
79
diff --git a/tests/qtest/libqos/vhost-user-blk.c b/tests/qtest/libqos/vhost-user-blk.c
80
new file mode 100644
81
index XXXXXXX..XXXXXXX
82
--- /dev/null
83
+++ b/tests/qtest/libqos/vhost-user-blk.c
84
@@ -XXX,XX +XXX,XX @@
85
+/*
86
+ * libqos driver framework
87
+ *
88
+ * Based on tests/qtest/libqos/virtio-blk.c
89
+ *
90
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
91
+ *
92
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
93
+ *
94
+ * This library is free software; you can redistribute it and/or
95
+ * modify it under the terms of the GNU Lesser General Public
96
+ * License version 2.1 as published by the Free Software Foundation.
97
+ *
98
+ * This library is distributed in the hope that it will be useful,
99
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
100
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
101
+ * Lesser General Public License for more details.
102
+ *
103
+ * You should have received a copy of the GNU Lesser General Public
104
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
105
+ */
106
+
107
+#include "qemu/osdep.h"
108
+#include "libqtest.h"
109
+#include "qemu/module.h"
110
+#include "standard-headers/linux/virtio_blk.h"
111
+#include "vhost-user-blk.h"
112
+
113
+#define PCI_SLOT 0x04
114
+#define PCI_FN 0x00
115
+
116
+/* virtio-blk-device */
117
+static void *qvhost_user_blk_get_driver(QVhostUserBlk *v_blk,
118
+ const char *interface)
119
+{
120
+ if (!g_strcmp0(interface, "vhost-user-blk")) {
121
+ return v_blk;
122
+ }
123
+ if (!g_strcmp0(interface, "virtio")) {
124
+ return v_blk->vdev;
125
+ }
126
+
127
+ fprintf(stderr, "%s not present in vhost-user-blk-device\n", interface);
128
+ g_assert_not_reached();
129
+}
130
+
131
+static void *qvhost_user_blk_device_get_driver(void *object,
132
+ const char *interface)
133
+{
134
+ QVhostUserBlkDevice *v_blk = object;
135
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
136
+}
137
+
138
+static void *vhost_user_blk_device_create(void *virtio_dev,
139
+ QGuestAllocator *t_alloc,
140
+ void *addr)
141
+{
142
+ QVhostUserBlkDevice *vhost_user_blk = g_new0(QVhostUserBlkDevice, 1);
143
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
144
+
145
+ interface->vdev = virtio_dev;
146
+
147
+ vhost_user_blk->obj.get_driver = qvhost_user_blk_device_get_driver;
148
+
149
+ return &vhost_user_blk->obj;
150
+}
151
+
152
+/* virtio-blk-pci */
153
+static void *qvhost_user_blk_pci_get_driver(void *object, const char *interface)
154
+{
155
+ QVhostUserBlkPCI *v_blk = object;
156
+ if (!g_strcmp0(interface, "pci-device")) {
157
+ return v_blk->pci_vdev.pdev;
158
+ }
159
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
160
+}
161
+
162
+static void *vhost_user_blk_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
163
+ void *addr)
164
+{
165
+ QVhostUserBlkPCI *vhost_user_blk = g_new0(QVhostUserBlkPCI, 1);
166
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
167
+ QOSGraphObject *obj = &vhost_user_blk->pci_vdev.obj;
168
+
169
+ virtio_pci_init(&vhost_user_blk->pci_vdev, pci_bus, addr);
170
+ interface->vdev = &vhost_user_blk->pci_vdev.vdev;
171
+
172
+ g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_BLOCK);
173
+
174
+ obj->get_driver = qvhost_user_blk_pci_get_driver;
175
+
176
+ return obj;
177
+}
178
+
179
+static void vhost_user_blk_register_nodes(void)
180
+{
181
+ /*
182
+ * FIXME: every test using these two nodes needs to setup a
183
+ * -drive,id=drive0 otherwise QEMU is not going to start.
184
+ * Therefore, we do not include "produces" edge for virtio
185
+ * and pci-device yet.
186
+ */
187
+
188
+ char *arg = g_strdup_printf("id=drv0,chardev=char1,addr=%x.%x",
189
+ PCI_SLOT, PCI_FN);
190
+
191
+ QPCIAddress addr = {
192
+ .devfn = QPCI_DEVFN(PCI_SLOT, PCI_FN),
193
+ };
194
+
195
+ QOSGraphEdgeOptions opts = { };
196
+
197
+ /* virtio-blk-device */
198
+ /** opts.extra_device_opts = "drive=drive0"; */
199
+ qos_node_create_driver("vhost-user-blk-device",
200
+ vhost_user_blk_device_create);
201
+ qos_node_consumes("vhost-user-blk-device", "virtio-bus", &opts);
202
+ qos_node_produces("vhost-user-blk-device", "vhost-user-blk");
203
+
204
+ /* virtio-blk-pci */
205
+ opts.extra_device_opts = arg;
206
+ add_qpci_address(&opts, &addr);
207
+ qos_node_create_driver("vhost-user-blk-pci", vhost_user_blk_pci_create);
208
+ qos_node_consumes("vhost-user-blk-pci", "pci-bus", &opts);
209
+ qos_node_produces("vhost-user-blk-pci", "vhost-user-blk");
210
+
211
+ g_free(arg);
212
+}
213
+
214
+libqos_init(vhost_user_blk_register_nodes);
215
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
216
new file mode 100644
217
index XXXXXXX..XXXXXXX
218
--- /dev/null
219
+++ b/tests/qtest/vhost-user-blk-test.c
220
@@ -XXX,XX +XXX,XX @@
221
+/*
222
+ * QTest testcase for Vhost-user Block Device
223
+ *
224
+ * Based on tests/qtest//virtio-blk-test.c
225
+
226
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
227
+ * Copyright (c) 2014 Marc Marí
228
+ * Copyright (c) 2020 Coiby Xu
229
+ *
230
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
231
+ * See the COPYING file in the top-level directory.
232
+ */
233
+
234
+#include "qemu/osdep.h"
235
+#include "libqtest-single.h"
236
+#include "qemu/bswap.h"
237
+#include "qemu/module.h"
238
+#include "standard-headers/linux/virtio_blk.h"
239
+#include "standard-headers/linux/virtio_pci.h"
240
+#include "libqos/qgraph.h"
241
+#include "libqos/vhost-user-blk.h"
242
+#include "libqos/libqos-pc.h"
243
+
244
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
245
+#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
246
+#define PCI_SLOT_HP 0x06
247
+
248
+typedef struct {
249
+ pid_t pid;
250
+} QemuStorageDaemonState;
251
+
252
+typedef struct QVirtioBlkReq {
253
+ uint32_t type;
254
+ uint32_t ioprio;
255
+ uint64_t sector;
256
+ char *data;
257
+ uint8_t status;
258
+} QVirtioBlkReq;
259
+
260
+#ifdef HOST_WORDS_BIGENDIAN
261
+static const bool host_is_big_endian = true;
262
+#else
263
+static const bool host_is_big_endian; /* false */
264
+#endif
265
+
266
+static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
267
+{
268
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
269
+ req->type = bswap32(req->type);
270
+ req->ioprio = bswap32(req->ioprio);
271
+ req->sector = bswap64(req->sector);
272
+ }
273
+}
274
+
275
+static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
276
+ struct virtio_blk_discard_write_zeroes *dwz_hdr)
277
+{
278
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
279
+ dwz_hdr->sector = bswap64(dwz_hdr->sector);
280
+ dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
281
+ dwz_hdr->flags = bswap32(dwz_hdr->flags);
282
+ }
283
+}
284
+
285
+static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
286
+ QVirtioBlkReq *req, uint64_t data_size)
287
+{
288
+ uint64_t addr;
289
+ uint8_t status = 0xFF;
290
+ QTestState *qts = global_qtest;
291
+
292
+ switch (req->type) {
293
+ case VIRTIO_BLK_T_IN:
294
+ case VIRTIO_BLK_T_OUT:
295
+ g_assert_cmpuint(data_size % 512, ==, 0);
296
+ break;
297
+ case VIRTIO_BLK_T_DISCARD:
298
+ case VIRTIO_BLK_T_WRITE_ZEROES:
299
+ g_assert_cmpuint(data_size %
300
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
301
+ break;
302
+ default:
303
+ g_assert_cmpuint(data_size, ==, 0);
304
+ }
305
+
306
+ addr = guest_alloc(alloc, sizeof(*req) + data_size);
307
+
308
+ virtio_blk_fix_request(d, req);
309
+
310
+ qtest_memwrite(qts, addr, req, 16);
311
+ qtest_memwrite(qts, addr + 16, req->data, data_size);
312
+ qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
313
+
314
+ return addr;
315
+}
316
+
317
+/* Returns the request virtqueue so the caller can perform further tests */
318
+static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
319
+{
320
+ QVirtioBlkReq req;
321
+ uint64_t req_addr;
322
+ uint64_t capacity;
323
+ uint64_t features;
324
+ uint32_t free_head;
325
+ uint8_t status;
326
+ char *data;
327
+ QTestState *qts = global_qtest;
328
+ QVirtQueue *vq;
329
+
330
+ features = qvirtio_get_features(dev);
331
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
332
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
333
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
334
+ (1u << VIRTIO_BLK_F_SCSI));
335
+ qvirtio_set_features(dev, features);
336
+
337
+ capacity = qvirtio_config_readq(dev, 0);
338
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
339
+
340
+ vq = qvirtqueue_setup(dev, alloc, 0);
341
+
342
+ qvirtio_set_driver_ok(dev);
343
+
344
+ /* Write and read with 3 descriptor layout */
345
+ /* Write request */
346
+ req.type = VIRTIO_BLK_T_OUT;
347
+ req.ioprio = 1;
348
+ req.sector = 0;
349
+ req.data = g_malloc0(512);
350
+ strcpy(req.data, "TEST");
351
+
352
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
353
+
354
+ g_free(req.data);
355
+
356
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
357
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
358
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
359
+
360
+ qvirtqueue_kick(qts, dev, vq, free_head);
361
+
362
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
363
+ QVIRTIO_BLK_TIMEOUT_US);
364
+ status = readb(req_addr + 528);
365
+ g_assert_cmpint(status, ==, 0);
366
+
367
+ guest_free(alloc, req_addr);
368
+
369
+ /* Read request */
370
+ req.type = VIRTIO_BLK_T_IN;
371
+ req.ioprio = 1;
372
+ req.sector = 0;
373
+ req.data = g_malloc0(512);
374
+
375
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
376
+
377
+ g_free(req.data);
378
+
379
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
380
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
381
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
382
+
383
+ qvirtqueue_kick(qts, dev, vq, free_head);
384
+
385
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
386
+ QVIRTIO_BLK_TIMEOUT_US);
387
+ status = readb(req_addr + 528);
388
+ g_assert_cmpint(status, ==, 0);
389
+
390
+ data = g_malloc0(512);
391
+ qtest_memread(qts, req_addr + 16, data, 512);
392
+ g_assert_cmpstr(data, ==, "TEST");
393
+ g_free(data);
394
+
395
+ guest_free(alloc, req_addr);
396
+
397
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
398
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
399
+ void *expected;
400
+
401
+ /*
402
+ * WRITE_ZEROES request on the same sector of previous test where
403
+ * we wrote "TEST".
404
+ */
405
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
406
+ req.data = (char *) &dwz_hdr;
407
+ dwz_hdr.sector = 0;
408
+ dwz_hdr.num_sectors = 1;
409
+ dwz_hdr.flags = 0;
410
+
411
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
412
+
413
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
414
+
415
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
416
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
417
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
418
+ false);
419
+
420
+ qvirtqueue_kick(qts, dev, vq, free_head);
421
+
422
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
423
+ QVIRTIO_BLK_TIMEOUT_US);
424
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
425
+ g_assert_cmpint(status, ==, 0);
426
+
427
+ guest_free(alloc, req_addr);
428
+
429
+ /* Read request to check if the sector contains all zeroes */
430
+ req.type = VIRTIO_BLK_T_IN;
431
+ req.ioprio = 1;
432
+ req.sector = 0;
433
+ req.data = g_malloc0(512);
434
+
435
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
436
+
437
+ g_free(req.data);
438
+
439
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
440
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
441
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
442
+
443
+ qvirtqueue_kick(qts, dev, vq, free_head);
444
+
445
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
446
+ QVIRTIO_BLK_TIMEOUT_US);
447
+ status = readb(req_addr + 528);
448
+ g_assert_cmpint(status, ==, 0);
449
+
450
+ data = g_malloc(512);
451
+ expected = g_malloc0(512);
452
+ qtest_memread(qts, req_addr + 16, data, 512);
453
+ g_assert_cmpmem(data, 512, expected, 512);
454
+ g_free(expected);
455
+ g_free(data);
456
+
457
+ guest_free(alloc, req_addr);
458
+ }
459
+
460
+ if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
461
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
462
+
463
+ req.type = VIRTIO_BLK_T_DISCARD;
464
+ req.data = (char *) &dwz_hdr;
465
+ dwz_hdr.sector = 0;
466
+ dwz_hdr.num_sectors = 1;
467
+ dwz_hdr.flags = 0;
468
+
469
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
470
+
471
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
472
+
473
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
474
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
475
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
476
+ 1, true, false);
477
+
478
+ qvirtqueue_kick(qts, dev, vq, free_head);
479
+
480
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
481
+ QVIRTIO_BLK_TIMEOUT_US);
482
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
483
+ g_assert_cmpint(status, ==, 0);
484
+
485
+ guest_free(alloc, req_addr);
486
+ }
487
+
488
+ if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
489
+ /* Write and read with 2 descriptor layout */
490
+ /* Write request */
491
+ req.type = VIRTIO_BLK_T_OUT;
492
+ req.ioprio = 1;
493
+ req.sector = 1;
494
+ req.data = g_malloc0(512);
495
+ strcpy(req.data, "TEST");
496
+
497
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
498
+
499
+ g_free(req.data);
500
+
501
+ free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
502
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
503
+ qvirtqueue_kick(qts, dev, vq, free_head);
504
+
505
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
506
+ QVIRTIO_BLK_TIMEOUT_US);
507
+ status = readb(req_addr + 528);
508
+ g_assert_cmpint(status, ==, 0);
509
+
510
+ guest_free(alloc, req_addr);
511
+
512
+ /* Read request */
513
+ req.type = VIRTIO_BLK_T_IN;
514
+ req.ioprio = 1;
515
+ req.sector = 1;
516
+ req.data = g_malloc0(512);
517
+
518
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
519
+
520
+ g_free(req.data);
521
+
522
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
523
+ qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
524
+
525
+ qvirtqueue_kick(qts, dev, vq, free_head);
526
+
527
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
528
+ QVIRTIO_BLK_TIMEOUT_US);
529
+ status = readb(req_addr + 528);
530
+ g_assert_cmpint(status, ==, 0);
531
+
532
+ data = g_malloc0(512);
533
+ qtest_memread(qts, req_addr + 16, data, 512);
534
+ g_assert_cmpstr(data, ==, "TEST");
535
+ g_free(data);
536
+
537
+ guest_free(alloc, req_addr);
538
+ }
539
+
540
+ return vq;
541
+}
542
+
543
+static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
544
+{
545
+ QVhostUserBlk *blk_if = obj;
546
+ QVirtQueue *vq;
547
+
548
+ vq = test_basic(blk_if->vdev, t_alloc);
549
+ qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
550
+
551
+}
552
+
553
+static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
554
+{
555
+ QVirtQueue *vq;
556
+ QVhostUserBlk *blk_if = obj;
557
+ QVirtioDevice *dev = blk_if->vdev;
558
+ QVirtioBlkReq req;
559
+ QVRingIndirectDesc *indirect;
560
+ uint64_t req_addr;
561
+ uint64_t capacity;
562
+ uint64_t features;
563
+ uint32_t free_head;
564
+ uint8_t status;
565
+ char *data;
566
+ QTestState *qts = global_qtest;
567
+
568
+ features = qvirtio_get_features(dev);
569
+ g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
570
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
571
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
572
+ (1u << VIRTIO_BLK_F_SCSI));
573
+ qvirtio_set_features(dev, features);
574
+
575
+ capacity = qvirtio_config_readq(dev, 0);
576
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
577
+
578
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
579
+ qvirtio_set_driver_ok(dev);
580
+
581
+ /* Write request */
582
+ req.type = VIRTIO_BLK_T_OUT;
583
+ req.ioprio = 1;
584
+ req.sector = 0;
585
+ req.data = g_malloc0(512);
586
+ strcpy(req.data, "TEST");
587
+
588
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
589
+
590
+ g_free(req.data);
591
+
592
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
593
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
594
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
595
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
596
+ qvirtqueue_kick(qts, dev, vq, free_head);
597
+
598
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
599
+ QVIRTIO_BLK_TIMEOUT_US);
600
+ status = readb(req_addr + 528);
601
+ g_assert_cmpint(status, ==, 0);
602
+
603
+ g_free(indirect);
604
+ guest_free(t_alloc, req_addr);
605
+
606
+ /* Read request */
607
+ req.type = VIRTIO_BLK_T_IN;
608
+ req.ioprio = 1;
609
+ req.sector = 0;
610
+ req.data = g_malloc0(512);
611
+ strcpy(req.data, "TEST");
612
+
613
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
614
+
615
+ g_free(req.data);
616
+
617
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
618
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
619
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
620
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
621
+ qvirtqueue_kick(qts, dev, vq, free_head);
622
+
623
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
624
+ QVIRTIO_BLK_TIMEOUT_US);
625
+ status = readb(req_addr + 528);
626
+ g_assert_cmpint(status, ==, 0);
627
+
628
+ data = g_malloc0(512);
629
+ qtest_memread(qts, req_addr + 16, data, 512);
630
+ g_assert_cmpstr(data, ==, "TEST");
631
+ g_free(data);
632
+
633
+ g_free(indirect);
634
+ guest_free(t_alloc, req_addr);
635
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
636
+}
637
+
638
+static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
639
+{
640
+ QVirtQueue *vq;
641
+ QVhostUserBlkPCI *blk = obj;
642
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
643
+ QVirtioDevice *dev = &pdev->vdev;
644
+ QVirtioBlkReq req;
645
+ uint64_t req_addr;
646
+ uint64_t capacity;
647
+ uint64_t features;
648
+ uint32_t free_head;
649
+ uint32_t write_head;
650
+ uint32_t desc_idx;
651
+ uint8_t status;
652
+ char *data;
653
+ QOSGraphObject *blk_object = obj;
654
+ QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
655
+ QTestState *qts = global_qtest;
656
+
657
+ if (qpci_check_buggy_msi(pci_dev)) {
658
+ return;
659
+ }
660
+
661
+ qpci_msix_enable(pdev->pdev);
662
+ qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
663
+
664
+ features = qvirtio_get_features(dev);
665
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
666
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
667
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
668
+ (1u << VIRTIO_BLK_F_SCSI));
669
+ qvirtio_set_features(dev, features);
670
+
671
+ capacity = qvirtio_config_readq(dev, 0);
672
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
673
+
674
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
675
+ qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
676
+
677
+ qvirtio_set_driver_ok(dev);
678
+
679
+ /* Write request */
680
+ req.type = VIRTIO_BLK_T_OUT;
681
+ req.ioprio = 1;
682
+ req.sector = 0;
683
+ req.data = g_malloc0(512);
684
+ strcpy(req.data, "TEST");
685
+
686
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
687
+
688
+ g_free(req.data);
689
+
690
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
691
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
692
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
693
+ qvirtqueue_kick(qts, dev, vq, free_head);
694
+
695
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
696
+ QVIRTIO_BLK_TIMEOUT_US);
697
+
698
+ /* Write request */
699
+ req.type = VIRTIO_BLK_T_OUT;
700
+ req.ioprio = 1;
701
+ req.sector = 1;
702
+ req.data = g_malloc0(512);
703
+ strcpy(req.data, "TEST");
704
+
705
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
706
+
707
+ g_free(req.data);
708
+
709
+ /* Notify after processing the third request */
710
+ qvirtqueue_set_used_event(qts, vq, 2);
711
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
712
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
713
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
714
+ qvirtqueue_kick(qts, dev, vq, free_head);
715
+ write_head = free_head;
716
+
717
+ /* No notification expected */
718
+ status = qvirtio_wait_status_byte_no_isr(qts, dev,
719
+ vq, req_addr + 528,
720
+ QVIRTIO_BLK_TIMEOUT_US);
721
+ g_assert_cmpint(status, ==, 0);
722
+
723
+ guest_free(t_alloc, req_addr);
724
+
725
+ /* Read request */
726
+ req.type = VIRTIO_BLK_T_IN;
727
+ req.ioprio = 1;
728
+ req.sector = 1;
729
+ req.data = g_malloc0(512);
730
+
731
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
732
+
733
+ g_free(req.data);
734
+
735
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
736
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
737
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
738
+
739
+ qvirtqueue_kick(qts, dev, vq, free_head);
740
+
741
+ /* We get just one notification for both requests */
742
+ qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
743
+ QVIRTIO_BLK_TIMEOUT_US);
744
+ g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
745
+ g_assert_cmpint(desc_idx, ==, free_head);
746
+
747
+ status = readb(req_addr + 528);
748
+ g_assert_cmpint(status, ==, 0);
749
+
750
+ data = g_malloc0(512);
751
+ qtest_memread(qts, req_addr + 16, data, 512);
752
+ g_assert_cmpstr(data, ==, "TEST");
753
+ g_free(data);
754
+
755
+ guest_free(t_alloc, req_addr);
756
+
757
+ /* End test */
758
+ qpci_msix_disable(pdev->pdev);
759
+
760
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
761
+}
762
+
763
+static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
764
+{
765
+ QVirtioPCIDevice *dev1 = obj;
766
+ QVirtioPCIDevice *dev;
767
+ QTestState *qts = dev1->pdev->bus->qts;
768
+
769
+ /* plug secondary disk */
770
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
771
+ "{'addr': %s, 'chardev': 'char2'}",
772
+ stringify(PCI_SLOT_HP) ".0");
773
+
774
+ dev = virtio_pci_new(dev1->pdev->bus,
775
+ &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
776
+ });
777
+ g_assert_nonnull(dev);
778
+ g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
779
+ qvirtio_pci_device_disable(dev);
780
+ qos_object_destroy((QOSGraphObject *)dev);
781
+
782
+ /* unplug secondary disk */
783
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
784
+}
785
+
786
+/*
787
+ * Check that setting the vring addr on a non-existent virtqueue does
788
+ * not crash.
789
+ */
790
+static void test_nonexistent_virtqueue(void *obj, void *data,
791
+ QGuestAllocator *t_alloc)
792
+{
793
+ QVhostUserBlkPCI *blk = obj;
794
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
795
+ QPCIBar bar0;
796
+ QPCIDevice *dev;
797
+
798
+ dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
799
+ g_assert(dev != NULL);
800
+ qpci_device_enable(dev);
801
+
802
+ bar0 = qpci_iomap(dev, 0, NULL);
803
+
804
+ qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
805
+ qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
806
+
807
+ g_free(dev);
808
+}
809
+
810
+static const char *qtest_qemu_storage_daemon_binary(void)
811
+{
812
+ const char *qemu_storage_daemon_bin;
813
+
814
+ qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
815
+ if (!qemu_storage_daemon_bin) {
816
+ fprintf(stderr, "Environment variable "
817
+ "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
818
+ exit(0);
819
+ }
820
+
821
+ return qemu_storage_daemon_bin;
822
+}
823
+
824
+/* g_test_queue_destroy() cleanup function for files */
825
+static void destroy_file(void *path)
826
+{
827
+ unlink(path);
828
+ g_free(path);
829
+ qos_invalidate_command_line();
830
+}
831
+
832
+static char *drive_create(void)
833
+{
834
+ int fd, ret;
835
+ /** vhost-user-blk won't recognize drive located in /tmp */
836
+ char *t_path = g_strdup("qtest.XXXXXX");
837
+
838
+ /** Create a temporary raw image */
839
+ fd = mkstemp(t_path);
840
+ g_assert_cmpint(fd, >=, 0);
841
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
842
+ g_assert_cmpint(ret, ==, 0);
843
+ close(fd);
844
+
845
+ g_test_queue_destroy(destroy_file, t_path);
846
+ return t_path;
847
+}
848
+
849
+static char *create_listen_socket(int *fd)
850
+{
851
+ int tmp_fd;
852
+ char *path;
853
+
854
+ /* No race because our pid makes the path unique */
855
+ path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid());
856
+ tmp_fd = mkstemp(path);
857
+ g_assert_cmpint(tmp_fd, >=, 0);
858
+ close(tmp_fd);
859
+ unlink(path);
860
+
861
+ *fd = qtest_socket_server(path);
862
+ g_test_queue_destroy(destroy_file, path);
863
+ return path;
864
+}
865
+
866
+/*
867
+ * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
868
+ * qemu-storage-daemon.
869
+ */
870
+static void quit_storage_daemon(void *data)
871
+{
872
+ QemuStorageDaemonState *qsd = data;
873
+ int wstatus;
874
+ pid_t pid;
875
+
876
+ /*
877
+ * If we were invoked as a g_test_queue_destroy() cleanup function we need
878
+ * to remove the abrt handler to avoid being called again if the code below
879
+ * aborts. Also, we must not leave the abrt handler installed after
880
+ * cleanup.
881
+ */
882
+ qtest_remove_abrt_handler(data);
883
+
884
+ /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
885
+ qtest_kill_qemu(global_qtest);
886
+
887
+ kill(qsd->pid, SIGTERM);
888
+ pid = waitpid(qsd->pid, &wstatus, 0);
889
+ g_assert_cmpint(pid, ==, qsd->pid);
890
+ if (!WIFEXITED(wstatus)) {
891
+ fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
892
+ __func__);
893
+ abort();
894
+ }
895
+ if (WEXITSTATUS(wstatus) != 0) {
896
+ fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
897
+ "successfully, got %d\n",
898
+ __func__, WEXITSTATUS(wstatus));
899
+ abort();
900
+ }
901
+
902
+ g_free(data);
903
+}
904
+
905
+static void start_vhost_user_blk(GString *cmd_line, int vus_instances)
906
+{
907
+ const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
908
+ int i;
909
+ gchar *img_path;
910
+ GString *storage_daemon_command = g_string_new(NULL);
911
+ QemuStorageDaemonState *qsd;
912
+
913
+ g_string_append_printf(storage_daemon_command,
914
+ "exec %s ",
915
+ vhost_user_blk_bin);
916
+
917
+ g_string_append_printf(cmd_line,
918
+ " -object memory-backend-memfd,id=mem,size=256M,share=on "
919
+ " -M memory-backend=mem -m 256M ");
920
+
921
+ for (i = 0; i < vus_instances; i++) {
922
+ int fd;
923
+ char *sock_path = create_listen_socket(&fd);
924
+
925
+ /* create image file */
926
+ img_path = drive_create();
927
+ g_string_append_printf(storage_daemon_command,
928
+ "--blockdev driver=file,node-name=disk%d,filename=%s "
929
+ "--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
930
+ "node-name=disk%i,writable=on ",
931
+ i, img_path, i, sock_path, i);
932
+
933
+ g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
934
+ i + 1, sock_path);
935
+ }
936
+
937
+ g_test_message("starting vhost-user backend: %s",
938
+ storage_daemon_command->str);
939
+ pid_t pid = fork();
940
+ if (pid == 0) {
941
+ /*
942
+ * Close standard file descriptors so tap-driver.pl pipe detects when
943
+ * our parent terminates.
944
+ */
945
+ close(0);
946
+ close(1);
947
+ open("/dev/null", O_RDONLY);
948
+ open("/dev/null", O_WRONLY);
949
+
950
+ execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
951
+ exit(1);
952
+ }
953
+ g_string_free(storage_daemon_command, true);
954
+
955
+ qsd = g_new(QemuStorageDaemonState, 1);
956
+ qsd->pid = pid;
957
+
958
+ /* Make sure qemu-storage-daemon is stopped */
959
+ qtest_add_abrt_handler(quit_storage_daemon, qsd);
960
+ g_test_queue_destroy(quit_storage_daemon, qsd);
961
+}
962
+
963
+static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
964
+{
965
+ start_vhost_user_blk(cmd_line, 1);
966
+ return arg;
967
+}
968
+
969
+/*
970
+ * Setup for hotplug.
971
+ *
972
+ * Since vhost-user server only serves one vhost-user client one time,
973
+ * another exprot
974
+ *
975
+ */
976
+static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
977
+{
978
+ /* "-chardev socket,id=char2" is used for pci_hotplug*/
979
+ start_vhost_user_blk(cmd_line, 2);
980
+ return arg;
981
+}
982
+
983
+static void register_vhost_user_blk_test(void)
984
+{
985
+ QOSGraphTestOptions opts = {
986
+ .before = vhost_user_blk_test_setup,
987
+ };
988
+
989
+ /*
990
+ * tests for vhost-user-blk and vhost-user-blk-pci
991
+ * The tests are borrowed from tests/virtio-blk-test.c. But some tests
992
+ * regarding block_resize don't work for vhost-user-blk.
993
+ * vhost-user-blk device doesn't have -drive, so tests containing
994
+ * block_resize are also abandoned,
995
+ * - config
996
+ * - resize
997
+ */
998
+ qos_add_test("basic", "vhost-user-blk", basic, &opts);
999
+ qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
1000
+ qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
1001
+ qos_add_test("nxvirtq", "vhost-user-blk-pci",
1002
+ test_nonexistent_virtqueue, &opts);
1003
+
1004
+ opts.before = vhost_user_blk_hotplug_test_setup;
1005
+ qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
1006
+}
1007
+
1008
+libqos_init(register_vhost_user_blk_test);
1009
diff --git a/MAINTAINERS b/MAINTAINERS
189
index XXXXXXX..XXXXXXX 100644
1010
index XXXXXXX..XXXXXXX 100644
190
--- a/tests/qemu-iotests/common.filter
1011
--- a/MAINTAINERS
191
+++ b/tests/qemu-iotests/common.filter
1012
+++ b/MAINTAINERS
192
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
1013
@@ -XXX,XX +XXX,XX @@ F: block/export/vhost-user-blk-server.c
193
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
1014
F: block/export/vhost-user-blk-server.h
194
-e "s#$TEST_DIR#TEST_DIR#g" \
1015
F: include/qemu/vhost-user-server.h
195
-e "s#$IMGFMT#IMGFMT#g" \
1016
F: tests/qtest/libqos/vhost-user-blk.c
196
+ -e 's#nbd:127.0.0.1:10810#TEST_DIR/t.IMGFMT#g' \
1017
+F: tests/qtest/libqos/vhost-user-blk.h
197
-e "s# encryption=off##g" \
1018
+F: tests/qtest/vhost-user-blk-test.c
198
-e "s# cluster_size=[0-9]\\+##g" \
1019
F: util/vhost-user-server.c
199
-e "s# table_size=[0-9]\\+##g" \
1020
200
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
1021
FUSE block device exports
1022
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
201
index XXXXXXX..XXXXXXX 100644
1023
index XXXXXXX..XXXXXXX 100644
202
--- a/tests/qemu-iotests/group
1024
--- a/tests/qtest/libqos/meson.build
203
+++ b/tests/qemu-iotests/group
1025
+++ b/tests/qtest/libqos/meson.build
204
@@ -XXX,XX +XXX,XX @@
1026
@@ -XXX,XX +XXX,XX @@ libqos_srcs = files('../libqtest.c',
205
192 rw auto quick
1027
'virtio-9p.c',
206
194 rw auto migration quick
1028
'virtio-balloon.c',
207
195 rw auto quick
1029
'virtio-blk.c',
208
+197 rw auto quick
1030
+ 'vhost-user-blk.c',
1031
'virtio-mmio.c',
1032
'virtio-net.c',
1033
'virtio-pci.c',
1034
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
1035
index XXXXXXX..XXXXXXX 100644
1036
--- a/tests/qtest/meson.build
1037
+++ b/tests/qtest/meson.build
1038
@@ -XXX,XX +XXX,XX @@ if have_virtfs
1039
qos_test_ss.add(files('virtio-9p-test.c'))
1040
endif
1041
qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c'))
1042
+if have_vhost_user_blk_server
1043
+ qos_test_ss.add(files('vhost-user-blk-test.c'))
1044
+endif
1045
1046
tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c']
1047
1048
@@ -XXX,XX +XXX,XX @@ foreach dir : target_dirs
1049
endif
1050
qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh')
1051
qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base)
1052
+ qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon')
1053
1054
foreach test : target_qtests
1055
# Executables are shared across targets, declare them only the first time we
209
--
1056
--
210
2.13.6
1057
2.29.2
211
1058
212
1059
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Right now, the dirty-bitmap code exposes the fact that we use
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
a scale of sector granularity in the underlying hbitmap to anything
4
Message-Id: <20210223144653.811468-7-stefanha@redhat.com>
5
that wants to serialize a dirty bitmap. It's nicer to uniformly
6
expose bytes as our dirty-bitmap interface, matching the previous
7
change to bitmap size. The only caller to serialization is currently
8
qcow2-cluster.c, which becomes a bit more verbose because it is still
9
tracking sectors for other reasons, but a later patch will fix that
10
to more uniformly use byte offsets everywhere. Likewise, within
11
dirty-bitmap, we have to add more assertions that we are not
12
truncating incorrectly, which can go away once the internal hbitmap
13
is byte-based rather than sector-based.
14
15
Signed-off-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: John Snow <jsnow@redhat.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Fam Zheng <famz@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
6
---
21
include/block/dirty-bitmap.h | 14 +++++++-------
7
tests/qtest/vhost-user-blk-test.c | 81 +++++++++++++++++++++++++++++--
22
block/dirty-bitmap.c | 37 ++++++++++++++++++++++++-------------
8
1 file changed, 76 insertions(+), 5 deletions(-)
23
block/qcow2-bitmap.c | 22 ++++++++++++++--------
24
3 files changed, 45 insertions(+), 28 deletions(-)
25
9
26
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
10
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
27
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/dirty-bitmap.h
12
--- a/tests/qtest/vhost-user-blk-test.c
29
+++ b/include/block/dirty-bitmap.h
13
+++ b/tests/qtest/vhost-user-blk-test.c
30
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
14
@@ -XXX,XX +XXX,XX @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
31
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
15
qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
32
33
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
34
- uint64_t start, uint64_t count);
35
+ uint64_t offset, uint64_t bytes);
36
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
37
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
38
- uint8_t *buf, uint64_t start,
39
- uint64_t count);
40
+ uint8_t *buf, uint64_t offset,
41
+ uint64_t bytes);
42
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
43
- uint8_t *buf, uint64_t start,
44
- uint64_t count, bool finish);
45
+ uint8_t *buf, uint64_t offset,
46
+ uint64_t bytes, bool finish);
47
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
48
- uint64_t start, uint64_t count,
49
+ uint64_t offset, uint64_t bytes,
50
bool finish);
51
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
52
- uint64_t start, uint64_t count,
53
+ uint64_t offset, uint64_t bytes,
54
bool finish);
55
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
56
57
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/dirty-bitmap.c
60
+++ b/block/dirty-bitmap.c
61
@@ -XXX,XX +XXX,XX @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
62
}
16
}
63
17
64
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
18
+static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
65
- uint64_t start, uint64_t count)
19
+{
66
+ uint64_t offset, uint64_t bytes)
20
+ QVirtioPCIDevice *pdev1 = obj;
21
+ QVirtioDevice *dev1 = &pdev1->vdev;
22
+ QVirtioPCIDevice *pdev8;
23
+ QVirtioDevice *dev8;
24
+ QTestState *qts = pdev1->pdev->bus->qts;
25
+ uint64_t features;
26
+ uint16_t num_queues;
27
+
28
+ /*
29
+ * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
30
+ * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
31
+ * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
32
+ * is also spec-compliant).
33
+ */
34
+ features = qvirtio_get_features(dev1);
35
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
36
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
37
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
38
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
39
+ (1u << VIRTIO_BLK_F_SCSI));
40
+ qvirtio_set_features(dev1, features);
41
+
42
+ /* Hotplug a secondary device with 8 queues */
43
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
44
+ "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
45
+ stringify(PCI_SLOT_HP) ".0");
46
+
47
+ pdev8 = virtio_pci_new(pdev1->pdev->bus,
48
+ &(QPCIAddress) {
49
+ .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
50
+ });
51
+ g_assert_nonnull(pdev8);
52
+ g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
53
+
54
+ qos_object_start_hw(&pdev8->obj);
55
+
56
+ dev8 = &pdev8->vdev;
57
+ features = qvirtio_get_features(dev8);
58
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
59
+ ==,
60
+ (1u << VIRTIO_BLK_F_MQ));
61
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
62
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
63
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
64
+ (1u << VIRTIO_BLK_F_SCSI) |
65
+ (1u << VIRTIO_BLK_F_MQ));
66
+ qvirtio_set_features(dev8, features);
67
+
68
+ num_queues = qvirtio_config_readw(dev8,
69
+ offsetof(struct virtio_blk_config, num_queues));
70
+ g_assert_cmpint(num_queues, ==, 8);
71
+
72
+ qvirtio_pci_device_disable(pdev8);
73
+ qos_object_destroy(&pdev8->obj);
74
+
75
+ /* unplug secondary disk */
76
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
77
+}
78
+
79
/*
80
* Check that setting the vring addr on a non-existent virtqueue does
81
* not crash.
82
@@ -XXX,XX +XXX,XX @@ static void quit_storage_daemon(void *data)
83
g_free(data);
84
}
85
86
-static void start_vhost_user_blk(GString *cmd_line, int vus_instances)
87
+static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
88
+ int num_queues)
67
{
89
{
68
- return hbitmap_serialization_size(bitmap->bitmap, start, count);
90
const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
69
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
91
int i;
70
+ return hbitmap_serialization_size(bitmap->bitmap,
92
@@ -XXX,XX +XXX,XX @@ static void start_vhost_user_blk(GString *cmd_line, int vus_instances)
71
+ offset >> BDRV_SECTOR_BITS,
93
g_string_append_printf(storage_daemon_command,
72
+ bytes >> BDRV_SECTOR_BITS);
94
"--blockdev driver=file,node-name=disk%d,filename=%s "
95
"--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
96
- "node-name=disk%i,writable=on ",
97
- i, img_path, i, sock_path, i);
98
+ "node-name=disk%i,writable=on,num-queues=%d ",
99
+ i, img_path, i, sock_path, i, num_queues);
100
101
g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
102
i + 1, sock_path);
103
@@ -XXX,XX +XXX,XX @@ static void start_vhost_user_blk(GString *cmd_line, int vus_instances)
104
105
static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
106
{
107
- start_vhost_user_blk(cmd_line, 1);
108
+ start_vhost_user_blk(cmd_line, 1, 1);
109
return arg;
73
}
110
}
74
111
75
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
112
@@ -XXX,XX +XXX,XX @@ static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
113
static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
76
{
114
{
77
- return hbitmap_serialization_align(bitmap->bitmap);
115
/* "-chardev socket,id=char2" is used for pci_hotplug*/
78
+ return hbitmap_serialization_align(bitmap->bitmap) * BDRV_SECTOR_SIZE;
116
- start_vhost_user_blk(cmd_line, 2);
117
+ start_vhost_user_blk(cmd_line, 2, 1);
118
+ return arg;
119
+}
120
+
121
+static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
122
+{
123
+ start_vhost_user_blk(cmd_line, 2, 8);
124
return arg;
79
}
125
}
80
126
81
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
127
@@ -XXX,XX +XXX,XX @@ static void register_vhost_user_blk_test(void)
82
- uint8_t *buf, uint64_t start,
128
83
- uint64_t count)
129
opts.before = vhost_user_blk_hotplug_test_setup;
84
+ uint8_t *buf, uint64_t offset,
130
qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
85
+ uint64_t bytes)
131
+
86
{
132
+ opts.before = vhost_user_blk_multiqueue_test_setup;
87
- hbitmap_serialize_part(bitmap->bitmap, buf, start, count);
133
+ qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
88
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
89
+ hbitmap_serialize_part(bitmap->bitmap, buf, offset >> BDRV_SECTOR_BITS,
90
+ bytes >> BDRV_SECTOR_BITS);
91
}
134
}
92
135
93
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
136
libqos_init(register_vhost_user_blk_test);
94
- uint8_t *buf, uint64_t start,
95
- uint64_t count, bool finish)
96
+ uint8_t *buf, uint64_t offset,
97
+ uint64_t bytes, bool finish)
98
{
99
- hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish);
100
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
101
+ hbitmap_deserialize_part(bitmap->bitmap, buf, offset >> BDRV_SECTOR_BITS,
102
+ bytes >> BDRV_SECTOR_BITS, finish);
103
}
104
105
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
106
- uint64_t start, uint64_t count,
107
+ uint64_t offset, uint64_t bytes,
108
bool finish)
109
{
110
- hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
111
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
112
+ hbitmap_deserialize_zeroes(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
113
+ bytes >> BDRV_SECTOR_BITS, finish);
114
}
115
116
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
117
- uint64_t start, uint64_t count,
118
+ uint64_t offset, uint64_t bytes,
119
bool finish)
120
{
121
- hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish);
122
+ assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
123
+ hbitmap_deserialize_ones(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
124
+ bytes >> BDRV_SECTOR_BITS, finish);
125
}
126
127
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
128
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/block/qcow2-bitmap.c
131
+++ b/block/qcow2-bitmap.c
132
@@ -XXX,XX +XXX,XX @@ static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
133
bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
134
uint64_t sbc = sector_granularity * (s->cluster_size << 3);
135
136
- assert(QEMU_IS_ALIGNED(sbc,
137
+ assert(QEMU_IS_ALIGNED(sbc << BDRV_SECTOR_BITS,
138
bdrv_dirty_bitmap_serialization_align(bitmap)));
139
return sbc;
140
}
141
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
142
uint8_t *buf = NULL;
143
uint64_t i, tab_size =
144
size_to_clusters(s,
145
- bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_sectors));
146
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
147
148
if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) {
149
return -EINVAL;
150
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
151
152
if (offset == 0) {
153
if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
154
- bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count,
155
+ bdrv_dirty_bitmap_deserialize_ones(bitmap,
156
+ sector * BDRV_SECTOR_SIZE,
157
+ count * BDRV_SECTOR_SIZE,
158
false);
159
} else {
160
/* No need to deserialize zeros because the dirty bitmap is
161
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
162
if (ret < 0) {
163
goto finish;
164
}
165
- bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count,
166
+ bdrv_dirty_bitmap_deserialize_part(bitmap, buf,
167
+ sector * BDRV_SECTOR_SIZE,
168
+ count * BDRV_SECTOR_SIZE,
169
false);
170
}
171
}
172
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
173
uint64_t *tb;
174
uint64_t tb_size =
175
size_to_clusters(s,
176
- bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_sectors));
177
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
178
179
if (tb_size > BME_MAX_TABLE_SIZE ||
180
tb_size * s->cluster_size > BME_MAX_PHYS_SIZE)
181
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
182
183
sector = cluster * sbc;
184
end = MIN(bm_sectors, sector + sbc);
185
- write_size =
186
- bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
187
+ write_size = bdrv_dirty_bitmap_serialization_size(bitmap,
188
+ sector * BDRV_SECTOR_SIZE, (end - sector) * BDRV_SECTOR_SIZE);
189
assert(write_size <= s->cluster_size);
190
191
off = qcow2_alloc_clusters(bs, s->cluster_size);
192
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
193
}
194
tb[cluster] = off;
195
196
- bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector);
197
+ bdrv_dirty_bitmap_serialize_part(bitmap, buf,
198
+ sector * BDRV_SECTOR_SIZE,
199
+ (end - sector) * BDRV_SECTOR_SIZE);
200
if (write_size < s->cluster_size) {
201
memset(buf + write_size, 0, s->cluster_size - write_size);
202
}
203
--
137
--
204
2.13.6
138
2.29.2
205
139
206
140
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Now that we have adjusted the majority of the calls this function
3
The config->blk_size field is little-endian. Use the native-endian
4
makes to be byte-based, it is easier to read the code if it makes
4
blk_size variable to avoid double byteswapping.
5
passes over the image using bytes rather than sectors.
6
5
7
Signed-off-by: Eric Blake <eblake@redhat.com>
6
Fixes: 11f60f7eaee2630dd6fa0c3a8c49f792e46c4cf1 ("block/export: make vhost-user-blk config space little-endian")
8
Reviewed-by: John Snow <jsnow@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20210223144653.811468-8-stefanha@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
10
---
13
block/mirror.c | 38 ++++++++++++++------------------------
11
block/export/vhost-user-blk-server.c | 2 +-
14
1 file changed, 14 insertions(+), 24 deletions(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
15
13
16
diff --git a/block/mirror.c b/block/mirror.c
14
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/block/mirror.c
16
--- a/block/export/vhost-user-blk-server.c
19
+++ b/block/mirror.c
17
+++ b/block/export/vhost-user-blk-server.c
20
@@ -XXX,XX +XXX,XX @@ static void mirror_throttle(MirrorBlockJob *s)
18
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
21
19
config->num_queues = cpu_to_le16(num_queues);
22
static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
20
config->max_discard_sectors = cpu_to_le32(32768);
23
{
21
config->max_discard_seg = cpu_to_le32(1);
24
- int64_t sector_num, end;
22
- config->discard_sector_alignment = cpu_to_le32(config->blk_size >> 9);
25
+ int64_t offset;
23
+ config->discard_sector_alignment = cpu_to_le32(blk_size >> 9);
26
BlockDriverState *base = s->base;
24
config->max_write_zeroes_sectors = cpu_to_le32(32768);
27
BlockDriverState *bs = s->source;
25
config->max_write_zeroes_seg = cpu_to_le32(1);
28
BlockDriverState *target_bs = blk_bs(s->target);
29
- int ret, n;
30
+ int ret;
31
int64_t count;
32
33
- end = s->bdev_length / BDRV_SECTOR_SIZE;
34
-
35
if (base == NULL && !bdrv_has_zero_init(target_bs)) {
36
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
37
bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
39
}
40
41
s->initial_zeroing_ongoing = true;
42
- for (sector_num = 0; sector_num < end; ) {
43
- int nb_sectors = MIN(end - sector_num,
44
- QEMU_ALIGN_DOWN(INT_MAX, s->granularity) >> BDRV_SECTOR_BITS);
45
+ for (offset = 0; offset < s->bdev_length; ) {
46
+ int bytes = MIN(s->bdev_length - offset,
47
+ QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
48
49
mirror_throttle(s);
50
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
52
continue;
53
}
54
55
- mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE,
56
- nb_sectors * BDRV_SECTOR_SIZE, false);
57
- sector_num += nb_sectors;
58
+ mirror_do_zero_or_discard(s, offset, bytes, false);
59
+ offset += bytes;
60
}
61
62
mirror_wait_for_all_io(s);
63
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
64
}
65
66
/* First part, loop on the sectors and initialize the dirty bitmap. */
67
- for (sector_num = 0; sector_num < end; ) {
68
+ for (offset = 0; offset < s->bdev_length; ) {
69
/* Just to make sure we are not exceeding int limit. */
70
- int nb_sectors = MIN(INT_MAX >> BDRV_SECTOR_BITS,
71
- end - sector_num);
72
+ int bytes = MIN(s->bdev_length - offset,
73
+ QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
74
75
mirror_throttle(s);
76
77
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
78
return 0;
79
}
80
81
- ret = bdrv_is_allocated_above(bs, base, sector_num * BDRV_SECTOR_SIZE,
82
- nb_sectors * BDRV_SECTOR_SIZE, &count);
83
+ ret = bdrv_is_allocated_above(bs, base, offset, bytes, &count);
84
if (ret < 0) {
85
return ret;
86
}
87
88
- /* TODO: Relax this once bdrv_is_allocated_above and dirty
89
- * bitmaps no longer require sector alignment. */
90
- assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
91
- n = count >> BDRV_SECTOR_BITS;
92
- assert(n > 0);
93
+ assert(count);
94
if (ret == 1) {
95
- bdrv_set_dirty_bitmap(s->dirty_bitmap,
96
- sector_num * BDRV_SECTOR_SIZE,
97
- n * BDRV_SECTOR_SIZE);
98
+ bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, count);
99
}
100
- sector_num += n;
101
+ offset += count;
102
}
103
return 0;
104
}
26
}
105
--
27
--
106
2.13.6
28
2.29.2
107
29
108
30
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Make it easier to enable copy-on-read during iotests, by
3
Use VIRTIO_BLK_SECTOR_BITS and VIRTIO_BLK_SECTOR_SIZE when dealing with
4
exposing a new bool option to main and open.
4
virtio-blk sector numbers. Although the values happen to be the same as
5
BDRV_SECTOR_BITS and BDRV_SECTOR_SIZE, they are conceptually different.
6
This makes it clearer when we are dealing with virtio-blk sector units.
5
7
6
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Use VIRTIO_BLK_SECTOR_BITS in vu_blk_initialize_config(). Later patches
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
will use it the new constants the virtqueue request processing code
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
path.
9
Reviewed-by: John Snow <jsnow@redhat.com>
11
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Suggested-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20210223144653.811468-9-stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
16
---
13
qemu-io.c | 15 ++++++++++++---
17
block/export/vhost-user-blk-server.c | 15 ++++++++++++---
14
1 file changed, 12 insertions(+), 3 deletions(-)
18
1 file changed, 12 insertions(+), 3 deletions(-)
15
19
16
diff --git a/qemu-io.c b/qemu-io.c
20
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io.c
22
--- a/block/export/vhost-user-blk-server.c
19
+++ b/qemu-io.c
23
+++ b/block/export/vhost-user-blk-server.c
20
@@ -XXX,XX +XXX,XX @@ static void open_help(void)
24
@@ -XXX,XX +XXX,XX @@
21
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
25
#include "sysemu/block-backend.h"
22
" -r, -- open file read-only\n"
26
#include "util/block-helpers.h"
23
" -s, -- use snapshot file\n"
27
24
+" -C, -- use copy-on-read\n"
28
+/*
25
" -n, -- disable host cache, short for -t none\n"
29
+ * Sector units are 512 bytes regardless of the
26
" -U, -- force shared permissions\n"
30
+ * virtio_blk_config->blk_size value.
27
" -k, -- use kernel AIO implementation (on Linux only)\n"
31
+ */
28
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t open_cmd = {
32
+#define VIRTIO_BLK_SECTOR_BITS 9
29
.argmin = 1,
33
+#define VIRTIO_BLK_SECTOR_SIZE (1ull << VIRTIO_BLK_SECTOR_BITS)
30
.argmax = -1,
34
+
31
.flags = CMD_NOFILE_OK,
35
enum {
32
- .args = "[-rsnkU] [-t cache] [-d discard] [-o options] [path]",
36
VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1,
33
+ .args = "[-rsCnkU] [-t cache] [-d discard] [-o options] [path]",
34
.oneline = "open the file specified by path",
35
.help = open_help,
36
};
37
};
37
@@ -XXX,XX +XXX,XX @@ static int open_f(BlockBackend *blk, int argc, char **argv)
38
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
38
QDict *opts;
39
uint32_t blk_size,
39
bool force_share = false;
40
uint16_t num_queues)
40
41
- while ((c = getopt(argc, argv, "snro:kt:d:U")) != -1) {
42
+ while ((c = getopt(argc, argv, "snCro:kt:d:U")) != -1) {
43
switch (c) {
44
case 's':
45
flags |= BDRV_O_SNAPSHOT;
46
@@ -XXX,XX +XXX,XX @@ static int open_f(BlockBackend *blk, int argc, char **argv)
47
flags |= BDRV_O_NOCACHE;
48
writethrough = false;
49
break;
50
+ case 'C':
51
+ flags |= BDRV_O_COPY_ON_READ;
52
+ break;
53
case 'r':
54
readonly = 1;
55
break;
56
@@ -XXX,XX +XXX,XX @@ static void usage(const char *name)
57
" -r, --read-only export read-only\n"
58
" -s, --snapshot use snapshot file\n"
59
" -n, --nocache disable host cache, short for -t none\n"
60
+" -C, --copy-on-read enable copy-on-read\n"
61
" -m, --misalign misalign allocations for O_DIRECT\n"
62
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
63
" -t, --cache=MODE use the given cache mode for the image\n"
64
@@ -XXX,XX +XXX,XX @@ static QemuOptsList file_opts = {
65
int main(int argc, char **argv)
66
{
41
{
67
int readonly = 0;
42
- config->capacity = cpu_to_le64(bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
68
- const char *sopt = "hVc:d:f:rsnmkt:T:U";
43
+ config->capacity =
69
+ const char *sopt = "hVc:d:f:rsnCmkt:T:U";
44
+ cpu_to_le64(bdrv_getlength(bs) >> VIRTIO_BLK_SECTOR_BITS);
70
const struct option lopt[] = {
45
config->blk_size = cpu_to_le32(blk_size);
71
{ "help", no_argument, NULL, 'h' },
46
config->size_max = cpu_to_le32(0);
72
{ "version", no_argument, NULL, 'V' },
47
config->seg_max = cpu_to_le32(128 - 2);
73
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
48
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
74
{ "read-only", no_argument, NULL, 'r' },
49
config->num_queues = cpu_to_le16(num_queues);
75
{ "snapshot", no_argument, NULL, 's' },
50
config->max_discard_sectors = cpu_to_le32(32768);
76
{ "nocache", no_argument, NULL, 'n' },
51
config->max_discard_seg = cpu_to_le32(1);
77
+ { "copy-on-read", no_argument, NULL, 'C' },
52
- config->discard_sector_alignment = cpu_to_le32(blk_size >> 9);
78
{ "misalign", no_argument, NULL, 'm' },
53
+ config->discard_sector_alignment =
79
{ "native-aio", no_argument, NULL, 'k' },
54
+ cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS);
80
{ "discard", required_argument, NULL, 'd' },
55
config->max_write_zeroes_sectors = cpu_to_le32(32768);
81
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
56
config->max_write_zeroes_seg = cpu_to_le32(1);
82
flags |= BDRV_O_NOCACHE;
57
}
83
writethrough = false;
58
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
84
break;
59
if (vu_opts->has_logical_block_size) {
85
+ case 'C':
60
logical_block_size = vu_opts->logical_block_size;
86
+ flags |= BDRV_O_COPY_ON_READ;
61
} else {
87
+ break;
62
- logical_block_size = BDRV_SECTOR_SIZE;
88
case 'd':
63
+ logical_block_size = VIRTIO_BLK_SECTOR_SIZE;
89
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
64
}
90
error_report("Invalid discard option: %s", optarg);
65
check_block_size(exp->id, "logical-block-size", logical_block_size,
66
&local_err);
91
--
67
--
92
2.13.6
68
2.29.2
93
69
94
70
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Now that we have adjusted the majority of the calls this function
3
The driver is supposed to honor the blk_size field but the protocol
4
makes to be byte-based, it is easier to read the code if it makes
4
still uses 512-byte sector numbers. It is incorrect to multiply
5
passes over the image using bytes rather than sectors.
5
req->sector_num by blk_size.
6
6
7
iotests 165 was rather weak - on a default 64k-cluster image, where
7
VIRTIO 1.1 5.2.5 Device Initialization says:
8
bitmap granularity also defaults to 64k bytes, a single cluster of
9
the bitmap table thus covers (64*1024*8) bits which each cover 64k
10
bytes, or 32G of image space. But the test only uses a 1G image,
11
so it cannot trigger any more than one loop of the code in
12
store_bitmap_data(); and it was writing to the first cluster. In
13
order to test that we are properly aligning which portions of the
14
bitmap are being written to the file, we really want to test a case
15
where the first dirty bit returned by bdrv_dirty_iter_next() is not
16
aligned to the start of a cluster, which we can do by modifying the
17
test to write data that doesn't happen to fall in the first cluster
18
of the image.
19
8
20
Signed-off-by: Eric Blake <eblake@redhat.com>
9
blk_size can be read to determine the optimal sector size for the
21
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
driver to use. This does not affect the units used in the protocol
22
Reviewed-by: John Snow <jsnow@redhat.com>
11
(always 512 bytes), but awareness of the correct value can affect
23
Reviewed-by: Fam Zheng <famz@redhat.com>
12
performance.
13
14
Fixes: 3578389bcf76c824a5d82e6586a6f0c71e56f2aa ("block/export: vhost-user block device backend server")
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Message-Id: <20210223144653.811468-10-stefanha@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
18
---
26
block/qcow2-bitmap.c | 31 ++++++++++++++++---------------
19
block/export/vhost-user-blk-server.c | 2 +-
27
tests/qemu-iotests/165 | 2 +-
20
1 file changed, 1 insertion(+), 1 deletion(-)
28
2 files changed, 17 insertions(+), 16 deletions(-)
29
21
30
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
22
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
31
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
32
--- a/block/qcow2-bitmap.c
24
--- a/block/export/vhost-user-blk-server.c
33
+++ b/block/qcow2-bitmap.c
25
+++ b/block/export/vhost-user-blk-server.c
34
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
26
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
35
{
36
int ret;
37
BDRVQcow2State *s = bs->opaque;
38
- int64_t sector;
39
- uint64_t limit, sbc;
40
+ int64_t offset;
41
+ uint64_t limit;
42
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
43
- uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
44
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
45
uint8_t *buf = NULL;
46
BdrvDirtyBitmapIter *dbi;
47
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
48
dbi = bdrv_dirty_iter_new(bitmap);
49
buf = g_malloc(s->cluster_size);
50
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
51
- sbc = limit >> BDRV_SECTOR_BITS;
52
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
53
54
- while ((sector = bdrv_dirty_iter_next(dbi) >> BDRV_SECTOR_BITS) >= 0) {
55
- uint64_t cluster = sector / sbc;
56
+ while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
57
+ uint64_t cluster = offset / limit;
58
uint64_t end, write_size;
59
int64_t off;
60
61
- sector = cluster * sbc;
62
- end = MIN(bm_sectors, sector + sbc);
63
- write_size = bdrv_dirty_bitmap_serialization_size(bitmap,
64
- sector * BDRV_SECTOR_SIZE, (end - sector) * BDRV_SECTOR_SIZE);
65
+ /*
66
+ * We found the first dirty offset, but want to write out the
67
+ * entire cluster of the bitmap that includes that offset,
68
+ * including any leading zero bits.
69
+ */
70
+ offset = QEMU_ALIGN_DOWN(offset, limit);
71
+ end = MIN(bm_size, offset + limit);
72
+ write_size = bdrv_dirty_bitmap_serialization_size(bitmap, offset,
73
+ end - offset);
74
assert(write_size <= s->cluster_size);
75
76
off = qcow2_alloc_clusters(bs, s->cluster_size);
77
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
78
}
79
tb[cluster] = off;
80
81
- bdrv_dirty_bitmap_serialize_part(bitmap, buf,
82
- sector * BDRV_SECTOR_SIZE,
83
- (end - sector) * BDRV_SECTOR_SIZE);
84
+ bdrv_dirty_bitmap_serialize_part(bitmap, buf, offset, end - offset);
85
if (write_size < s->cluster_size) {
86
memset(buf + write_size, 0, s->cluster_size - write_size);
87
}
88
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
89
goto fail;
90
}
91
92
- if (end >= bm_sectors) {
93
+ if (end >= bm_size) {
94
break;
27
break;
95
}
28
}
96
29
97
- bdrv_set_dirty_iter(dbi, end * BDRV_SECTOR_SIZE);
30
- int64_t offset = req->sector_num * vexp->blk_size;
98
+ bdrv_set_dirty_iter(dbi, end);
31
+ int64_t offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS;
99
}
32
QEMUIOVector qiov;
100
33
if (is_write) {
101
*bitmap_table_size = tb_size;
34
qemu_iovec_init_external(&qiov, out_iov, out_num);
102
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
103
index XXXXXXX..XXXXXXX 100755
104
--- a/tests/qemu-iotests/165
105
+++ b/tests/qemu-iotests/165
106
@@ -XXX,XX +XXX,XX @@ disk = os.path.join(iotests.test_dir, 'disk')
107
disk_size = 0x40000000 # 1G
108
109
# regions for qemu_io: (start, count) in bytes
110
-regions1 = ((0, 0x100000),
111
+regions1 = ((0x0fff00, 0x10000),
112
(0x200000, 0x100000))
113
114
regions2 = ((0x10000000, 0x20000),
115
--
35
--
116
2.13.6
36
2.29.2
117
37
118
38
diff view generated by jsdifflib
1
This changes the commit block job to support operation in a graph where
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
there is more than a single active layer that references the top node.
3
2
4
This involves inserting the commit filter node not only on the path
3
Validate discard/write zeroes the same way we do for virtio-blk. Some of
5
between the given active node and the top node, but between the top node
4
these checks are mandated by the VIRTIO specification, others are
6
and all of its parents.
5
internal to QEMU.
7
6
8
On completion, bdrv_drop_intermediate() must consider all parents for
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
updating the backing file link. These parents may be backing files
8
Message-Id: <20210223144653.811468-11-stefanha@redhat.com>
10
themselves and as such read-only; reopen them temporarily if necessary.
11
Previously this was achieved by the bdrv_reopen() calls in the commit
12
block job that made overlay_bs read-write for the whole duration of the
13
block job, even though write access is only needed on completion.
14
15
Now that we consider all parents, overlay_bs is meaningless. It is left
16
in place in this commit, but we'll remove it soon.
17
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
10
---
20
block.c | 68 ++++++++++++++++++++++++++++++++++------------------------
11
block/export/vhost-user-blk-server.c | 116 +++++++++++++++++++++------
21
block/commit.c | 2 +-
12
1 file changed, 93 insertions(+), 23 deletions(-)
22
2 files changed, 41 insertions(+), 29 deletions(-)
23
13
24
diff --git a/block.c b/block.c
14
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/block.c
16
--- a/block/export/vhost-user-blk-server.c
27
+++ b/block.c
17
+++ b/block/export/vhost-user-blk-server.c
28
@@ -XXX,XX +XXX,XX @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
18
@@ -XXX,XX +XXX,XX @@
29
const char *filename, Error **errp)
19
20
enum {
21
VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1,
22
+ VHOST_USER_BLK_MAX_DISCARD_SECTORS = 32768,
23
+ VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS = 32768,
24
};
25
struct virtio_blk_inhdr {
26
unsigned char status;
27
@@ -XXX,XX +XXX,XX @@ static void vu_blk_req_complete(VuBlkReq *req)
28
free(req);
29
}
30
31
+static bool vu_blk_sect_range_ok(VuBlkExport *vexp, uint64_t sector,
32
+ size_t size)
33
+{
34
+ uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
35
+ uint64_t total_sectors;
36
+
37
+ if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
38
+ return false;
39
+ }
40
+ if ((sector << VIRTIO_BLK_SECTOR_BITS) % vexp->blk_size) {
41
+ return false;
42
+ }
43
+ blk_get_geometry(vexp->export.blk, &total_sectors);
44
+ if (sector > total_sectors || nb_sectors > total_sectors - sector) {
45
+ return false;
46
+ }
47
+ return true;
48
+}
49
+
50
static int coroutine_fn
51
-vu_blk_discard_write_zeroes(BlockBackend *blk, struct iovec *iov,
52
+vu_blk_discard_write_zeroes(VuBlkExport *vexp, struct iovec *iov,
53
uint32_t iovcnt, uint32_t type)
30
{
54
{
31
BlockDriverState *parent = c->opaque;
55
+ BlockBackend *blk = vexp->export.blk;
32
+ int orig_flags = bdrv_get_flags(parent);
56
struct virtio_blk_discard_write_zeroes desc;
33
int ret;
57
- ssize_t size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
34
58
+ ssize_t size;
35
+ if (!(orig_flags & BDRV_O_RDWR)) {
59
+ uint64_t sector;
36
+ ret = bdrv_reopen(parent, orig_flags | BDRV_O_RDWR, errp);
60
+ uint32_t num_sectors;
37
+ if (ret < 0) {
61
+ uint32_t max_sectors;
38
+ return ret;
62
+ uint32_t flags;
39
+ }
63
+ int bytes;
64
+
65
+ /* Only one desc is currently supported */
66
+ if (unlikely(iov_size(iov, iovcnt) > sizeof(desc))) {
67
+ return VIRTIO_BLK_S_UNSUPP;
40
+ }
68
+ }
41
+
69
+
42
ret = bdrv_change_backing_file(parent, filename,
70
+ size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
43
base->drv ? base->drv->format_name : "");
71
if (unlikely(size != sizeof(desc))) {
44
if (ret < 0) {
72
- error_report("Invalid size %zd, expect %zu", size, sizeof(desc));
45
error_setg_errno(errp, ret, "Could not update backing file link");
73
- return -EINVAL;
74
+ error_report("Invalid size %zd, expected %zu", size, sizeof(desc));
75
+ return VIRTIO_BLK_S_IOERR;
46
}
76
}
47
77
48
+ if (!(orig_flags & BDRV_O_RDWR)) {
78
- uint64_t range[2] = { le64_to_cpu(desc.sector) << 9,
49
+ bdrv_reopen(parent, orig_flags, NULL);
79
- le32_to_cpu(desc.num_sectors) << 9 };
80
- if (type == VIRTIO_BLK_T_DISCARD) {
81
- if (blk_co_pdiscard(blk, range[0], range[1]) == 0) {
82
- return 0;
83
+ sector = le64_to_cpu(desc.sector);
84
+ num_sectors = le32_to_cpu(desc.num_sectors);
85
+ flags = le32_to_cpu(desc.flags);
86
+ max_sectors = (type == VIRTIO_BLK_T_WRITE_ZEROES) ?
87
+ VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS :
88
+ VHOST_USER_BLK_MAX_DISCARD_SECTORS;
89
+
90
+ /* This check ensures that 'bytes' fits in an int */
91
+ if (unlikely(num_sectors > max_sectors)) {
92
+ return VIRTIO_BLK_S_IOERR;
50
+ }
93
+ }
51
+
94
+
52
return ret;
95
+ bytes = num_sectors << VIRTIO_BLK_SECTOR_BITS;
53
}
54
55
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
56
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
57
BlockDriverState *base, const char *backing_file_str)
58
{
59
- BlockDriverState *new_top_bs = NULL;
60
+ BdrvChild *c, *next;
61
Error *local_err = NULL;
62
int ret = -EIO;
63
64
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
65
goto exit;
66
}
67
68
- new_top_bs = bdrv_find_overlay(active, top);
69
-
70
- if (new_top_bs == NULL) {
71
- /* we could not find the image above 'top', this is an error */
72
- goto exit;
73
- }
74
-
75
- /* special case of new_top_bs->backing->bs already pointing to base - nothing
76
- * to do, no intermediate images */
77
- if (backing_bs(new_top_bs) == base) {
78
- ret = 0;
79
- goto exit;
80
- }
81
-
82
/* Make sure that base is in the backing chain of top */
83
if (!bdrv_chain_contains(top, base)) {
84
goto exit;
85
}
86
87
/* success - we can delete the intermediate states, and link top->base */
88
- if (new_top_bs->backing->role->update_filename) {
89
- backing_file_str = backing_file_str ? backing_file_str : base->filename;
90
- ret = new_top_bs->backing->role->update_filename(new_top_bs->backing,
91
- base, backing_file_str,
92
- &local_err);
93
- if (ret < 0) {
94
- bdrv_set_backing_hd(new_top_bs, top, &error_abort);
95
+ backing_file_str = backing_file_str ? backing_file_str : base->filename;
96
+
96
+
97
+ QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
97
+ if (unlikely(!vu_blk_sect_range_ok(vexp, sector, bytes))) {
98
+ /* Check whether we are allowed to switch c from top to base */
98
+ return VIRTIO_BLK_S_IOERR;
99
+ GSList *ignore_children = g_slist_prepend(NULL, c);
99
+ }
100
+ bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
100
+
101
+ ignore_children, &local_err);
101
+ /*
102
+ if (local_err) {
102
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
103
+ ret = -EPERM;
103
+ * and write zeroes commands if any unknown flag is set.
104
+ error_report_err(local_err);
104
+ */
105
goto exit;
105
+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
106
}
106
+ return VIRTIO_BLK_S_UNSUPP;
107
- }
107
+ }
108
+ g_slist_free(ignore_children);
108
+
109
109
+ if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
110
- bdrv_set_backing_hd(new_top_bs, base, &local_err);
110
+ int blk_flags = 0;
111
- if (local_err) {
111
+
112
- ret = -EPERM;
112
+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
113
- error_report_err(local_err);
113
+ blk_flags |= BDRV_REQ_MAY_UNMAP;
114
- goto exit;
115
+ /* If so, update the backing file path in the image file */
116
+ if (c->role->update_filename) {
117
+ ret = c->role->update_filename(c, base, backing_file_str,
118
+ &local_err);
119
+ if (ret < 0) {
120
+ bdrv_abort_perm_update(base);
121
+ error_report_err(local_err);
122
+ goto exit;
123
+ }
124
+ }
114
+ }
125
+
115
+
126
+ /* Do the actual switch in the in-memory graph.
116
+ if (blk_co_pwrite_zeroes(blk, sector << VIRTIO_BLK_SECTOR_BITS,
127
+ * Completes bdrv_check_update_perm() transaction internally. */
117
+ bytes, blk_flags) == 0) {
128
+ bdrv_ref(base);
118
+ return VIRTIO_BLK_S_OK;
129
+ bdrv_replace_child(c, base);
119
}
130
+ bdrv_unref(top);
120
- } else if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
121
- if (blk_co_pwrite_zeroes(blk, range[0], range[1], 0) == 0) {
122
- return 0;
123
+ } else if (type == VIRTIO_BLK_T_DISCARD) {
124
+ /*
125
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
126
+ * discard commands if the unmap flag is set.
127
+ */
128
+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
129
+ return VIRTIO_BLK_S_UNSUPP;
130
+ }
131
+
132
+ if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS,
133
+ bytes) == 0) {
134
+ return VIRTIO_BLK_S_OK;
135
}
131
}
136
}
132
137
133
ret = 0;
138
- return -EINVAL;
134
diff --git a/block/commit.c b/block/commit.c
139
+ return VIRTIO_BLK_S_IOERR;
135
index XXXXXXX..XXXXXXX 100644
140
}
136
--- a/block/commit.c
141
137
+++ b/block/commit.c
142
static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
138
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
143
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
139
error_propagate(errp, local_err);
140
goto fail;
141
}
144
}
142
- bdrv_set_backing_hd(overlay_bs, commit_top_bs, &local_err);
145
case VIRTIO_BLK_T_DISCARD:
143
+ bdrv_replace_node(top, commit_top_bs, &local_err);
146
case VIRTIO_BLK_T_WRITE_ZEROES: {
144
if (local_err) {
147
- int rc;
145
bdrv_unref(commit_top_bs);
148
-
146
commit_top_bs = NULL;
149
if (!vexp->writable) {
150
req->in->status = VIRTIO_BLK_S_IOERR;
151
break;
152
}
153
154
- rc = vu_blk_discard_write_zeroes(blk, &elem->out_sg[1], out_num, type);
155
- if (rc == 0) {
156
- req->in->status = VIRTIO_BLK_S_OK;
157
- } else {
158
- req->in->status = VIRTIO_BLK_S_IOERR;
159
- }
160
+ req->in->status = vu_blk_discard_write_zeroes(vexp, out_iov, out_num,
161
+ type);
162
break;
163
}
164
default:
165
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
166
config->min_io_size = cpu_to_le16(1);
167
config->opt_io_size = cpu_to_le32(1);
168
config->num_queues = cpu_to_le16(num_queues);
169
- config->max_discard_sectors = cpu_to_le32(32768);
170
+ config->max_discard_sectors =
171
+ cpu_to_le32(VHOST_USER_BLK_MAX_DISCARD_SECTORS);
172
config->max_discard_seg = cpu_to_le32(1);
173
config->discard_sector_alignment =
174
cpu_to_le32(blk_size >> VIRTIO_BLK_SECTOR_BITS);
175
- config->max_write_zeroes_sectors = cpu_to_le32(32768);
176
+ config->max_write_zeroes_sectors
177
+ = cpu_to_le32(VHOST_USER_BLK_MAX_WRITE_ZEROES_SECTORS);
178
config->max_write_zeroes_seg = cpu_to_le32(1);
179
}
180
147
--
181
--
148
2.13.6
182
2.29.2
149
183
150
184
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
We are gradually converting to byte-based interfaces, as they are
3
Exercise input validation code paths in
4
easier to reason about than sector-based. Change the qcow2 bitmap
4
block/export/vhost-user-blk-server.c.
5
helper function sectors_covered_by_bitmap_cluster(), renaming it
6
to bytes_covered_by_bitmap_cluster() in the process.
7
5
8
Signed-off-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
7
Message-Id: <20210223144653.811468-12-stefanha@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Fam Zheng <famz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
9
---
14
block/qcow2-bitmap.c | 28 ++++++++++++++--------------
10
tests/qtest/vhost-user-blk-test.c | 124 ++++++++++++++++++++++++++++++
15
1 file changed, 14 insertions(+), 14 deletions(-)
11
1 file changed, 124 insertions(+)
16
12
17
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
13
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
18
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-bitmap.c
15
--- a/tests/qtest/vhost-user-blk-test.c
20
+++ b/block/qcow2-bitmap.c
16
+++ b/tests/qtest/vhost-user-blk-test.c
21
@@ -XXX,XX +XXX,XX @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
17
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
22
return 0;
18
return addr;
23
}
19
}
24
20
25
-/* This function returns the number of disk sectors covered by a single qcow2
21
+static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
26
- * cluster of bitmap data. */
22
+ QGuestAllocator *alloc,
27
-static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
23
+ QTestState *qts,
28
- const BdrvDirtyBitmap *bitmap)
24
+ QVirtQueue *vq,
29
+/* Return the disk size covered by a single qcow2 cluster of bitmap data. */
25
+ uint32_t type)
30
+static uint64_t bytes_covered_by_bitmap_cluster(const BDRVQcow2State *s,
26
+{
31
+ const BdrvDirtyBitmap *bitmap)
27
+ QVirtioBlkReq req;
28
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
29
+ struct virtio_blk_discard_write_zeroes dwz_hdr2[2];
30
+ uint64_t req_addr;
31
+ uint32_t free_head;
32
+ uint8_t status;
33
+
34
+ /* More than one dwz is not supported */
35
+ req.type = type;
36
+ req.data = (char *) dwz_hdr2;
37
+ dwz_hdr2[0].sector = 0;
38
+ dwz_hdr2[0].num_sectors = 1;
39
+ dwz_hdr2[0].flags = 0;
40
+ dwz_hdr2[1].sector = 1;
41
+ dwz_hdr2[1].num_sectors = 1;
42
+ dwz_hdr2[1].flags = 0;
43
+
44
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
45
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
46
+
47
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
48
+
49
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
50
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true);
51
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true,
52
+ false);
53
+
54
+ qvirtqueue_kick(qts, dev, vq, free_head);
55
+
56
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
57
+ QVIRTIO_BLK_TIMEOUT_US);
58
+ status = readb(req_addr + 16 + sizeof(dwz_hdr2));
59
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
60
+
61
+ guest_free(alloc, req_addr);
62
+
63
+ /* num_sectors must be less than config->max_write_zeroes_sectors */
64
+ req.type = type;
65
+ req.data = (char *) &dwz_hdr;
66
+ dwz_hdr.sector = 0;
67
+ dwz_hdr.num_sectors = 0xffffffff;
68
+ dwz_hdr.flags = 0;
69
+
70
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
71
+
72
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
73
+
74
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
75
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
76
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
77
+ false);
78
+
79
+ qvirtqueue_kick(qts, dev, vq, free_head);
80
+
81
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
82
+ QVIRTIO_BLK_TIMEOUT_US);
83
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
84
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
85
+
86
+ guest_free(alloc, req_addr);
87
+
88
+ /* sector must be less than the device capacity */
89
+ req.type = type;
90
+ req.data = (char *) &dwz_hdr;
91
+ dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1;
92
+ dwz_hdr.num_sectors = 1;
93
+ dwz_hdr.flags = 0;
94
+
95
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
96
+
97
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
98
+
99
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
100
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
101
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
102
+ false);
103
+
104
+ qvirtqueue_kick(qts, dev, vq, free_head);
105
+
106
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
107
+ QVIRTIO_BLK_TIMEOUT_US);
108
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
109
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
110
+
111
+ guest_free(alloc, req_addr);
112
+
113
+ /* reserved flag bits must be zero */
114
+ req.type = type;
115
+ req.data = (char *) &dwz_hdr;
116
+ dwz_hdr.sector = 0;
117
+ dwz_hdr.num_sectors = 1;
118
+ dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
119
+
120
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
121
+
122
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
123
+
124
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
125
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
126
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
127
+ false);
128
+
129
+ qvirtqueue_kick(qts, dev, vq, free_head);
130
+
131
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
132
+ QVIRTIO_BLK_TIMEOUT_US);
133
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
134
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
135
+
136
+ guest_free(alloc, req_addr);
137
+}
138
+
139
/* Returns the request virtqueue so the caller can perform further tests */
140
static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
32
{
141
{
33
- uint64_t sector_granularity =
142
@@ -XXX,XX +XXX,XX @@ static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
34
- bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
143
g_free(data);
35
- uint64_t sbc = sector_granularity * (s->cluster_size << 3);
144
36
+ uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
145
guest_free(alloc, req_addr);
37
+ uint64_t limit = granularity * (s->cluster_size << 3);
146
+
38
147
+ test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
39
- assert(QEMU_IS_ALIGNED(sbc << BDRV_SECTOR_BITS,
148
+ VIRTIO_BLK_T_WRITE_ZEROES);
40
+ assert(QEMU_IS_ALIGNED(limit,
41
bdrv_dirty_bitmap_serialization_align(bitmap)));
42
- return sbc;
43
+ return limit;
44
}
45
46
/* load_bitmap_data
47
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
48
{
49
int ret = 0;
50
BDRVQcow2State *s = bs->opaque;
51
- uint64_t sector, sbc;
52
+ uint64_t sector, limit, sbc;
53
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
54
uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
55
uint8_t *buf = NULL;
56
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
57
}
149
}
58
150
59
buf = g_malloc(s->cluster_size);
151
if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
60
- sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
152
@@ -XXX,XX +XXX,XX @@ static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
61
+ limit = bytes_covered_by_bitmap_cluster(s, bitmap);
153
g_assert_cmpint(status, ==, 0);
62
+ sbc = limit >> BDRV_SECTOR_BITS;
154
63
for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
155
guest_free(alloc, req_addr);
64
uint64_t count = MIN(bm_sectors - sector, sbc);
156
+
65
uint64_t entry = bitmap_table[i];
157
+ test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
66
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
158
+ VIRTIO_BLK_T_DISCARD);
67
int ret;
159
}
68
BDRVQcow2State *s = bs->opaque;
160
69
int64_t sector;
161
if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
70
- uint64_t sbc;
71
+ uint64_t limit, sbc;
72
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
73
uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
74
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
75
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
76
77
dbi = bdrv_dirty_iter_new(bitmap, 0);
78
buf = g_malloc(s->cluster_size);
79
- sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
80
- assert(DIV_ROUND_UP(bm_sectors, sbc) == tb_size);
81
+ limit = bytes_covered_by_bitmap_cluster(s, bitmap);
82
+ sbc = limit >> BDRV_SECTOR_BITS;
83
+ assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
84
85
while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
86
uint64_t cluster = sector / sbc;
87
--
162
--
88
2.13.6
163
2.29.2
89
164
90
165
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
We're already reporting bytes for bdrv_dirty_bitmap_granularity();
3
Check that the sector number and byte count are valid.
4
mixing bytes and sectors in our return values is a recipe for
5
confusion. A later cleanup will convert dirty bitmap internals
6
to be entirely byte-based, but in the meantime, we should report
7
the bitmap size in bytes.
8
4
9
The only external caller in qcow2-bitmap.c is temporarily more verbose
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
(because it is still using sector-based math), but will later be
6
Message-Id: <20210223144653.811468-13-stefanha@redhat.com>
11
switched to track progress by bytes instead of sectors.
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Fam Zheng <famz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
8
---
19
block/dirty-bitmap.c | 2 +-
9
block/export/vhost-user-blk-server.c | 19 ++++++++++++++++---
20
block/qcow2-bitmap.c | 14 ++++++++------
10
1 file changed, 16 insertions(+), 3 deletions(-)
21
2 files changed, 9 insertions(+), 7 deletions(-)
22
11
23
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
12
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
24
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
25
--- a/block/dirty-bitmap.c
14
--- a/block/export/vhost-user-blk-server.c
26
+++ b/block/dirty-bitmap.c
15
+++ b/block/export/vhost-user-blk-server.c
27
@@ -XXX,XX +XXX,XX @@ void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
16
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
28
17
switch (type & ~VIRTIO_BLK_T_BARRIER) {
29
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
18
case VIRTIO_BLK_T_IN:
30
{
19
case VIRTIO_BLK_T_OUT: {
31
- return bitmap->size;
20
+ QEMUIOVector qiov;
32
+ return bitmap->size * BDRV_SECTOR_SIZE;
21
+ int64_t offset;
33
}
22
ssize_t ret = 0;
34
23
bool is_write = type & VIRTIO_BLK_T_OUT;
35
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
24
req->sector_num = le64_to_cpu(req->out.sector);
36
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
25
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/qcow2-bitmap.c
39
+++ b/block/qcow2-bitmap.c
40
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
41
BDRVQcow2State *s = bs->opaque;
42
uint64_t sector, sbc;
43
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
44
+ uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
45
uint8_t *buf = NULL;
46
uint64_t i, tab_size =
47
size_to_clusters(s,
48
- bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
49
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_sectors));
50
51
if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) {
52
return -EINVAL;
53
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
54
buf = g_malloc(s->cluster_size);
55
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
56
for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
57
- uint64_t count = MIN(bm_size - sector, sbc);
58
+ uint64_t count = MIN(bm_sectors - sector, sbc);
59
uint64_t entry = bitmap_table[i];
60
uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
61
62
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
63
int64_t sector;
64
uint64_t sbc;
65
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
66
+ uint64_t bm_sectors = DIV_ROUND_UP(bm_size, BDRV_SECTOR_SIZE);
67
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
68
uint8_t *buf = NULL;
69
BdrvDirtyBitmapIter *dbi;
70
uint64_t *tb;
71
uint64_t tb_size =
72
size_to_clusters(s,
73
- bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
74
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_sectors));
75
76
if (tb_size > BME_MAX_TABLE_SIZE ||
77
tb_size * s->cluster_size > BME_MAX_PHYS_SIZE)
78
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
79
dbi = bdrv_dirty_iter_new(bitmap, 0);
80
buf = g_malloc(s->cluster_size);
81
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
82
- assert(DIV_ROUND_UP(bm_size, sbc) == tb_size);
83
+ assert(DIV_ROUND_UP(bm_sectors, sbc) == tb_size);
84
85
while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
86
uint64_t cluster = sector / sbc;
87
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
88
int64_t off;
89
90
sector = cluster * sbc;
91
- end = MIN(bm_size, sector + sbc);
92
+ end = MIN(bm_sectors, sector + sbc);
93
write_size =
94
bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
95
assert(write_size <= s->cluster_size);
96
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
97
goto fail;
98
}
99
100
- if (end >= bm_size) {
101
+ if (end >= bm_sectors) {
102
break;
26
break;
103
}
27
}
104
28
29
- int64_t offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS;
30
- QEMUIOVector qiov;
31
if (is_write) {
32
qemu_iovec_init_external(&qiov, out_iov, out_num);
33
- ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0);
34
} else {
35
qemu_iovec_init_external(&qiov, in_iov, in_num);
36
+ }
37
+
38
+ if (unlikely(!vu_blk_sect_range_ok(vexp,
39
+ req->sector_num,
40
+ qiov.size))) {
41
+ req->in->status = VIRTIO_BLK_S_IOERR;
42
+ break;
43
+ }
44
+
45
+ offset = req->sector_num << VIRTIO_BLK_SECTOR_BITS;
46
+
47
+ if (is_write) {
48
+ ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0);
49
+ } else {
50
ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0);
51
}
52
if (ret >= 0) {
105
--
53
--
106
2.13.6
54
2.29.2
107
55
108
56
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
All callers to bdrv_dirty_iter_new() passed 0 for their initial
3
Rename bytes_covered_by_bitmap_cluster() to
4
starting point, drop that parameter.
4
bdrv_dirty_bitmap_serialization_coverage() and make it public.
5
It is needed as we are going to share it with bitmap loading in
6
parallels format.
5
7
6
Most callers to bdrv_set_dirty_iter() were scaling a byte offset to
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
a sector number; the exception qcow2-bitmap will be converted later
9
Reviewed-by: Eric Blake <eblake@redhat.com>
8
to use byte rather than sector iteration. Move the scaling to occur
10
Reviewed-by: Denis V. Lunev <den@openvz.org>
9
internally to dirty bitmap code instead, so that callers now pass
11
Message-Id: <20210224104707.88430-2-vsementsov@virtuozzo.com>
10
in bytes.
11
12
Signed-off-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: John Snow <jsnow@redhat.com>
14
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Fam Zheng <famz@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
13
---
18
include/block/dirty-bitmap.h | 5 ++---
14
include/block/dirty-bitmap.h | 2 ++
19
block/backup.c | 5 ++---
15
block/dirty-bitmap.c | 13 +++++++++++++
20
block/dirty-bitmap.c | 9 ++++-----
16
block/qcow2-bitmap.c | 16 ++--------------
21
block/mirror.c | 4 ++--
17
3 files changed, 17 insertions(+), 14 deletions(-)
22
block/qcow2-bitmap.c | 4 ++--
23
5 files changed, 12 insertions(+), 15 deletions(-)
24
18
25
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
19
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
26
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/dirty-bitmap.h
21
--- a/include/block/dirty-bitmap.h
28
+++ b/include/block/dirty-bitmap.h
22
+++ b/include/block/dirty-bitmap.h
29
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
23
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
30
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
31
int64_t cur_sector, int64_t nr_sectors);
32
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
33
-BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
34
- uint64_t first_sector);
35
+BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
36
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
37
38
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
24
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
39
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
25
uint64_t offset, uint64_t bytes);
40
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
26
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
41
int64_t cur_sector, int64_t nr_sectors);
27
+uint64_t bdrv_dirty_bitmap_serialization_coverage(int serialized_chunk_size,
42
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
28
+ const BdrvDirtyBitmap *bitmap);
43
-void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
29
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
44
+void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
30
uint8_t *buf, uint64_t offset,
45
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
31
uint64_t bytes);
46
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
47
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
48
diff --git a/block/backup.c b/block/backup.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/backup.c
51
+++ b/block/backup.c
52
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
53
54
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
55
clusters_per_iter = MAX((granularity / job->cluster_size), 1);
56
- dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0);
57
+ dbi = bdrv_dirty_iter_new(job->sync_bitmap);
58
59
/* Find the next dirty sector(s) */
60
while ((offset = bdrv_dirty_iter_next(dbi) * BDRV_SECTOR_SIZE) >= 0) {
61
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
62
/* If the bitmap granularity is smaller than the backup granularity,
63
* we need to advance the iterator pointer to the next cluster. */
64
if (granularity < job->cluster_size) {
65
- bdrv_set_dirty_iter(dbi,
66
- cluster * job->cluster_size / BDRV_SECTOR_SIZE);
67
+ bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
68
}
69
70
last_cluster = cluster - 1;
71
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
32
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
72
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
73
--- a/block/dirty-bitmap.c
34
--- a/block/dirty-bitmap.c
74
+++ b/block/dirty-bitmap.c
35
+++ b/block/dirty-bitmap.c
75
@@ -XXX,XX +XXX,XX @@ uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
36
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
76
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
37
return hbitmap_serialization_align(bitmap->bitmap);
77
}
38
}
78
39
79
-BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
40
+/* Return the disk size covered by a chunk of serialized bitmap data. */
80
- uint64_t first_sector)
41
+uint64_t bdrv_dirty_bitmap_serialization_coverage(int serialized_chunk_size,
81
+BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
42
+ const BdrvDirtyBitmap *bitmap)
82
{
43
+{
83
BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
44
+ uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
84
- hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector);
45
+ uint64_t limit = granularity * (serialized_chunk_size << 3);
85
+ hbitmap_iter_init(&iter->hbi, bitmap->bitmap, 0);
46
+
86
iter->bitmap = bitmap;
47
+ assert(QEMU_IS_ALIGNED(limit,
87
bitmap->active_iterators++;
48
+ bdrv_dirty_bitmap_serialization_align(bitmap)));
88
return iter;
49
+ return limit;
89
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
50
+}
90
/**
51
+
91
* Advance a BdrvDirtyBitmapIter to an arbitrary offset.
52
+
92
*/
53
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
93
-void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num)
54
uint8_t *buf, uint64_t offset,
94
+void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t offset)
55
uint64_t bytes)
95
{
96
- hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num);
97
+ hbitmap_iter_init(&iter->hbi, iter->hbi.hb, offset >> BDRV_SECTOR_BITS);
98
}
99
100
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
101
diff --git a/block/mirror.c b/block/mirror.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/block/mirror.c
104
+++ b/block/mirror.c
105
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
106
next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
107
if (next_dirty > next_offset || next_dirty < 0) {
108
/* The bitmap iterator's cache is stale, refresh it */
109
- bdrv_set_dirty_iter(s->dbi, next_offset >> BDRV_SECTOR_BITS);
110
+ bdrv_set_dirty_iter(s->dbi, next_offset);
111
next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
112
}
113
assert(next_dirty == next_offset);
114
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
115
}
116
117
assert(!s->dbi);
118
- s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
119
+ s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap);
120
for (;;) {
121
uint64_t delay_ns = 0;
122
int64_t cnt, delta;
123
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
56
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
124
index XXXXXXX..XXXXXXX 100644
57
index XXXXXXX..XXXXXXX 100644
125
--- a/block/qcow2-bitmap.c
58
--- a/block/qcow2-bitmap.c
126
+++ b/block/qcow2-bitmap.c
59
+++ b/block/qcow2-bitmap.c
60
@@ -XXX,XX +XXX,XX @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
61
return 0;
62
}
63
64
-/* Return the disk size covered by a single qcow2 cluster of bitmap data. */
65
-static uint64_t bytes_covered_by_bitmap_cluster(const BDRVQcow2State *s,
66
- const BdrvDirtyBitmap *bitmap)
67
-{
68
- uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
69
- uint64_t limit = granularity * (s->cluster_size << 3);
70
-
71
- assert(QEMU_IS_ALIGNED(limit,
72
- bdrv_dirty_bitmap_serialization_align(bitmap)));
73
- return limit;
74
-}
75
-
76
/* load_bitmap_data
77
* @bitmap_table entries must satisfy specification constraints.
78
* @bitmap must be cleared */
79
@@ -XXX,XX +XXX,XX @@ static int load_bitmap_data(BlockDriverState *bs,
80
}
81
82
buf = g_malloc(s->cluster_size);
83
- limit = bytes_covered_by_bitmap_cluster(s, bitmap);
84
+ limit = bdrv_dirty_bitmap_serialization_coverage(s->cluster_size, bitmap);
85
for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) {
86
uint64_t count = MIN(bm_size - offset, limit);
87
uint64_t entry = bitmap_table[i];
127
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
88
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
128
return NULL;
129
}
89
}
130
90
131
- dbi = bdrv_dirty_iter_new(bitmap, 0);
132
+ dbi = bdrv_dirty_iter_new(bitmap);
133
buf = g_malloc(s->cluster_size);
91
buf = g_malloc(s->cluster_size);
134
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
92
- limit = bytes_covered_by_bitmap_cluster(s, bitmap);
135
sbc = limit >> BDRV_SECTOR_BITS;
93
+ limit = bdrv_dirty_bitmap_serialization_coverage(s->cluster_size, bitmap);
136
@@ -XXX,XX +XXX,XX @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
94
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
137
break;
95
138
}
96
offset = 0;
139
140
- bdrv_set_dirty_iter(dbi, end);
141
+ bdrv_set_dirty_iter(dbi, end * BDRV_SECTOR_SIZE);
142
}
143
144
*bitmap_table_size = tb_size;
145
--
97
--
146
2.13.6
98
2.29.2
147
99
148
100
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Half the callers were already scaling bytes to sectors; the other
4
half can eventually be simplified to use byte iteration. Both
5
callers were already using the result as a bool, so make that
6
explicit. Making the change also makes it easier for a future
7
dirty-bitmap patch to offload scaling over to the internal hbitmap.
8
9
Remember, asking whether a byte is dirty is effectively asking
10
whether the entire granularity containing the byte is dirty, since
11
we only track dirtiness by granularity.
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Juan Quintela <quintela@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Fam Zheng <famz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
include/block/dirty-bitmap.h | 4 ++--
21
block/dirty-bitmap.c | 8 ++++----
22
block/mirror.c | 3 +--
23
migration/block.c | 3 ++-
24
4 files changed, 9 insertions(+), 9 deletions(-)
25
26
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/block/dirty-bitmap.h
29
+++ b/include/block/dirty-bitmap.h
30
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
31
/* Functions that require manual locking. */
32
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
33
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
34
-int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
35
- int64_t sector);
36
+bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
37
+ int64_t offset);
38
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
39
int64_t cur_sector, int64_t nr_sectors);
40
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
41
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/dirty-bitmap.c
44
+++ b/block/dirty-bitmap.c
45
@@ -XXX,XX +XXX,XX @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
46
}
47
48
/* Called within bdrv_dirty_bitmap_lock..unlock */
49
-int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
50
- int64_t sector)
51
+bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
52
+ int64_t offset)
53
{
54
if (bitmap) {
55
- return hbitmap_get(bitmap->bitmap, sector);
56
+ return hbitmap_get(bitmap->bitmap, offset >> BDRV_SECTOR_BITS);
57
} else {
58
- return 0;
59
+ return false;
60
}
61
}
62
63
diff --git a/block/mirror.c b/block/mirror.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block/mirror.c
66
+++ b/block/mirror.c
67
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
68
int64_t next_offset = offset + nb_chunks * s->granularity;
69
int64_t next_chunk = next_offset / s->granularity;
70
if (next_offset >= s->bdev_length ||
71
- !bdrv_get_dirty_locked(source, s->dirty_bitmap,
72
- next_offset >> BDRV_SECTOR_BITS)) {
73
+ !bdrv_get_dirty_locked(source, s->dirty_bitmap, next_offset)) {
74
break;
75
}
76
if (test_bit(next_chunk, s->in_flight_bitmap)) {
77
diff --git a/migration/block.c b/migration/block.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/migration/block.c
80
+++ b/migration/block.c
81
@@ -XXX,XX +XXX,XX @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
82
blk_mig_unlock();
83
}
84
bdrv_dirty_bitmap_lock(bmds->dirty_bitmap);
85
- if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap, sector)) {
86
+ if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap,
87
+ sector * BDRV_SECTOR_SIZE)) {
88
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
89
nr_sectors = total_sectors - sector;
90
} else {
91
--
92
2.13.6
93
94
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Some of the callers were already scaling bytes to sectors; others
4
can be easily converted to pass byte offsets, all in our shift
5
towards a consistent byte interface everywhere. Making the change
6
will also make it easier to write the hold-out callers to use byte
7
rather than sectors for their iterations; it also makes it easier
8
for a future dirty-bitmap patch to offload scaling over to the
9
internal hbitmap. Although all callers happen to pass
10
sector-aligned values, make the internal scaling robust to any
11
sub-sector requests.
12
13
Signed-off-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Fam Zheng <famz@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
include/block/dirty-bitmap.h | 8 ++++----
20
block/dirty-bitmap.c | 22 ++++++++++++++--------
21
block/mirror.c | 16 ++++++++--------
22
migration/block.c | 7 +++++--
23
4 files changed, 31 insertions(+), 22 deletions(-)
24
25
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/dirty-bitmap.h
28
+++ b/include/block/dirty-bitmap.h
29
@@ -XXX,XX +XXX,XX @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
30
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
31
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
32
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
33
- int64_t cur_sector, int64_t nr_sectors);
34
+ int64_t offset, int64_t bytes);
35
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
36
- int64_t cur_sector, int64_t nr_sectors);
37
+ int64_t offset, int64_t bytes);
38
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
39
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
40
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
41
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
42
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
43
int64_t offset);
44
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
45
- int64_t cur_sector, int64_t nr_sectors);
46
+ int64_t offset, int64_t bytes);
47
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
48
- int64_t cur_sector, int64_t nr_sectors);
49
+ int64_t offset, int64_t bytes);
50
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
51
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
52
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
53
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/dirty-bitmap.c
56
+++ b/block/dirty-bitmap.c
57
@@ -XXX,XX +XXX,XX @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
58
59
/* Called within bdrv_dirty_bitmap_lock..unlock */
60
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
61
- int64_t cur_sector, int64_t nr_sectors)
62
+ int64_t offset, int64_t bytes)
63
{
64
+ int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
65
+
66
assert(bdrv_dirty_bitmap_enabled(bitmap));
67
assert(!bdrv_dirty_bitmap_readonly(bitmap));
68
- hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
69
+ hbitmap_set(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
70
+ end_sector - (offset >> BDRV_SECTOR_BITS));
71
}
72
73
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
74
- int64_t cur_sector, int64_t nr_sectors)
75
+ int64_t offset, int64_t bytes)
76
{
77
bdrv_dirty_bitmap_lock(bitmap);
78
- bdrv_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
79
+ bdrv_set_dirty_bitmap_locked(bitmap, offset, bytes);
80
bdrv_dirty_bitmap_unlock(bitmap);
81
}
82
83
/* Called within bdrv_dirty_bitmap_lock..unlock */
84
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
85
- int64_t cur_sector, int64_t nr_sectors)
86
+ int64_t offset, int64_t bytes)
87
{
88
+ int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
89
+
90
assert(bdrv_dirty_bitmap_enabled(bitmap));
91
assert(!bdrv_dirty_bitmap_readonly(bitmap));
92
- hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
93
+ hbitmap_reset(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
94
+ end_sector - (offset >> BDRV_SECTOR_BITS));
95
}
96
97
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
98
- int64_t cur_sector, int64_t nr_sectors)
99
+ int64_t offset, int64_t bytes)
100
{
101
bdrv_dirty_bitmap_lock(bitmap);
102
- bdrv_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
103
+ bdrv_reset_dirty_bitmap_locked(bitmap, offset, bytes);
104
bdrv_dirty_bitmap_unlock(bitmap);
105
}
106
107
diff --git a/block/mirror.c b/block/mirror.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/mirror.c
110
+++ b/block/mirror.c
111
@@ -XXX,XX +XXX,XX @@ static void mirror_write_complete(void *opaque, int ret)
112
if (ret < 0) {
113
BlockErrorAction action;
114
115
- bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
116
- op->bytes >> BDRV_SECTOR_BITS);
117
+ bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
118
action = mirror_error_action(s, false, -ret);
119
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
120
s->ret = ret;
121
@@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret)
122
if (ret < 0) {
123
BlockErrorAction action;
124
125
- bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
126
- op->bytes >> BDRV_SECTOR_BITS);
127
+ bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
128
action = mirror_error_action(s, true, -ret);
129
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
130
s->ret = ret;
131
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
132
* calling bdrv_get_block_status_above could yield - if some blocks are
133
* marked dirty in this window, we need to know.
134
*/
135
- bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset >> BDRV_SECTOR_BITS,
136
- nb_chunks * sectors_per_chunk);
137
+ bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
138
+ nb_chunks * s->granularity);
139
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
140
141
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
143
144
if (base == NULL && !bdrv_has_zero_init(target_bs)) {
145
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
146
- bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, end);
147
+ bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
148
return 0;
149
}
150
151
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
152
n = count >> BDRV_SECTOR_BITS;
153
assert(n > 0);
154
if (ret == 1) {
155
- bdrv_set_dirty_bitmap(s->dirty_bitmap, sector_num, n);
156
+ bdrv_set_dirty_bitmap(s->dirty_bitmap,
157
+ sector_num * BDRV_SECTOR_SIZE,
158
+ n * BDRV_SECTOR_SIZE);
159
}
160
sector_num += n;
161
}
162
diff --git a/migration/block.c b/migration/block.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/migration/block.c
165
+++ b/migration/block.c
166
@@ -XXX,XX +XXX,XX @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
167
blk->aiocb = blk_aio_preadv(bb, cur_sector * BDRV_SECTOR_SIZE, &blk->qiov,
168
0, blk_mig_read_cb, blk);
169
170
- bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, cur_sector, nr_sectors);
171
+ bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, cur_sector * BDRV_SECTOR_SIZE,
172
+ nr_sectors * BDRV_SECTOR_SIZE);
173
aio_context_release(blk_get_aio_context(bmds->blk));
174
qemu_mutex_unlock_iothread();
175
176
@@ -XXX,XX +XXX,XX @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
177
} else {
178
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
179
}
180
- bdrv_reset_dirty_bitmap_locked(bmds->dirty_bitmap, sector, nr_sectors);
181
+ bdrv_reset_dirty_bitmap_locked(bmds->dirty_bitmap,
182
+ sector * BDRV_SECTOR_SIZE,
183
+ nr_sectors * BDRV_SECTOR_SIZE);
184
bdrv_dirty_bitmap_unlock(bmds->dirty_bitmap);
185
186
blk = g_new(BlkMigBlock, 1);
187
--
188
2.13.6
189
190
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
This is new code, but it is easier to read if it makes passes over
4
the image using bytes rather than sectors (and will get easier in
5
the future when bdrv_get_block_status is converted to byte-based).
6
7
Signed-off-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/qcow2.c | 22 ++++++++++------------
14
1 file changed, 10 insertions(+), 12 deletions(-)
15
16
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
21
*/
22
required = virtual_size;
23
} else {
24
- int cluster_sectors = cluster_size / BDRV_SECTOR_SIZE;
25
- int64_t sector_num;
26
+ int64_t offset;
27
int pnum = 0;
28
29
- for (sector_num = 0;
30
- sector_num < ssize / BDRV_SECTOR_SIZE;
31
- sector_num += pnum) {
32
- int nb_sectors = MIN(ssize / BDRV_SECTOR_SIZE - sector_num,
33
- BDRV_REQUEST_MAX_SECTORS);
34
+ for (offset = 0; offset < ssize;
35
+ offset += pnum * BDRV_SECTOR_SIZE) {
36
+ int nb_sectors = MIN(ssize - offset,
37
+ BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
38
BlockDriverState *file;
39
int64_t ret;
40
41
ret = bdrv_get_block_status_above(in_bs, NULL,
42
- sector_num, nb_sectors,
43
+ offset >> BDRV_SECTOR_BITS,
44
+ nb_sectors,
45
&pnum, &file);
46
if (ret < 0) {
47
error_setg_errno(&local_err, -ret,
48
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
49
} else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==
50
(BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
51
/* Extend pnum to end of cluster for next iteration */
52
- pnum = ROUND_UP(sector_num + pnum, cluster_sectors) -
53
- sector_num;
54
+ pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,
55
+ cluster_size) - offset) >> BDRV_SECTOR_BITS;
56
57
/* Count clusters we've seen */
58
- required += (sector_num % cluster_sectors + pnum) *
59
- BDRV_SECTOR_SIZE;
60
+ required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;
61
}
62
}
63
}
64
--
65
2.13.6
66
67
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Both callers already had bytes available, but were scaling to
4
sectors. Move the scaling to internal code. In the case of
5
bdrv_aligned_pwritev(), we are now passing the exact offset
6
rather than a rounded sector-aligned value, but that's okay
7
as long as dirty bitmap widens start/bytes to granularity
8
boundaries.
9
10
Signed-off-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
16
include/block/block_int.h | 2 +-
17
block/dirty-bitmap.c | 7 ++++---
18
block/io.c | 6 ++----
19
3 files changed, 7 insertions(+), 8 deletions(-)
20
21
diff --git a/include/block/block_int.h b/include/block/block_int.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/block/block_int.h
24
+++ b/include/block/block_int.h
25
@@ -XXX,XX +XXX,XX @@ void blk_dev_eject_request(BlockBackend *blk, bool force);
26
bool blk_dev_is_tray_open(BlockBackend *blk);
27
bool blk_dev_is_medium_locked(BlockBackend *blk);
28
29
-void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int64_t nr_sect);
30
+void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
31
bool bdrv_requests_pending(BlockDriverState *bs);
32
33
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
34
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/dirty-bitmap.c
37
+++ b/block/dirty-bitmap.c
38
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
39
hbitmap_deserialize_finish(bitmap->bitmap);
40
}
41
42
-void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
43
- int64_t nr_sectors)
44
+void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
45
{
46
BdrvDirtyBitmap *bitmap;
47
+ int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
48
49
if (QLIST_EMPTY(&bs->dirty_bitmaps)) {
50
return;
51
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
52
continue;
53
}
54
assert(!bdrv_dirty_bitmap_readonly(bitmap));
55
- hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
56
+ hbitmap_set(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
57
+ end_sector - (offset >> BDRV_SECTOR_BITS));
58
}
59
bdrv_dirty_bitmaps_unlock(bs);
60
}
61
diff --git a/block/io.c b/block/io.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/block/io.c
64
+++ b/block/io.c
65
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
66
bool waited;
67
int ret;
68
69
- int64_t start_sector = offset >> BDRV_SECTOR_BITS;
70
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
71
uint64_t bytes_remaining = bytes;
72
int max_transfer;
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
74
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
75
76
atomic_inc(&bs->write_gen);
77
- bdrv_set_dirty(bs, start_sector, end_sector - start_sector);
78
+ bdrv_set_dirty(bs, offset, bytes);
79
80
stat64_max(&bs->wr_highest_offset, offset + bytes);
81
82
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
83
ret = 0;
84
out:
85
atomic_inc(&bs->write_gen);
86
- bdrv_set_dirty(bs, req.offset >> BDRV_SECTOR_BITS,
87
- req.bytes >> BDRV_SECTOR_BITS);
88
+ bdrv_set_dirty(bs, req.offset, req.bytes);
89
tracked_request_end(&req);
90
bdrv_dec_in_flight(bs);
91
return ret;
92
--
93
2.13.6
94
95
diff view generated by jsdifflib
Deleted patch
1
From: Eric Blake <eblake@redhat.com>
2
1
3
Now that all callers are using byte-based interfaces, there's no
4
reason for our internal hbitmap to remain with sector-based
5
granularity. It also simplifies our internal scaling, since we
6
already know that hbitmap widens requests out to granularity
7
boundaries.
8
9
Signed-off-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Fam Zheng <famz@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/dirty-bitmap.c | 62 +++++++++++++++-------------------------------------
16
1 file changed, 18 insertions(+), 44 deletions(-)
17
18
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/dirty-bitmap.c
21
+++ b/block/dirty-bitmap.c
22
@@ -XXX,XX +XXX,XX @@
23
*/
24
struct BdrvDirtyBitmap {
25
QemuMutex *mutex;
26
- HBitmap *bitmap; /* Dirty sector bitmap implementation */
27
+ HBitmap *bitmap; /* Dirty bitmap implementation */
28
HBitmap *meta; /* Meta dirty bitmap */
29
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
30
char *name; /* Optional non-empty unique ID */
31
@@ -XXX,XX +XXX,XX @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
32
}
33
bitmap = g_new0(BdrvDirtyBitmap, 1);
34
bitmap->mutex = &bs->dirty_bitmap_mutex;
35
- /*
36
- * TODO - let hbitmap track full granularity. For now, it is tracking
37
- * only sector granularity, as a shortcut for our iterators.
38
- */
39
- bitmap->bitmap = hbitmap_alloc(DIV_ROUND_UP(bitmap_size, BDRV_SECTOR_SIZE),
40
- ctz32(granularity) - BDRV_SECTOR_BITS);
41
+ bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(granularity));
42
bitmap->size = bitmap_size;
43
bitmap->name = g_strdup(name);
44
bitmap->disabled = false;
45
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
46
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
47
assert(!bdrv_dirty_bitmap_frozen(bitmap));
48
assert(!bitmap->active_iterators);
49
- hbitmap_truncate(bitmap->bitmap, DIV_ROUND_UP(bytes, BDRV_SECTOR_SIZE));
50
+ hbitmap_truncate(bitmap->bitmap, bytes);
51
bitmap->size = bytes;
52
}
53
bdrv_dirty_bitmaps_unlock(bs);
54
@@ -XXX,XX +XXX,XX @@ bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
55
int64_t offset)
56
{
57
if (bitmap) {
58
- return hbitmap_get(bitmap->bitmap, offset >> BDRV_SECTOR_BITS);
59
+ return hbitmap_get(bitmap->bitmap, offset);
60
} else {
61
return false;
62
}
63
@@ -XXX,XX +XXX,XX @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
64
65
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
66
{
67
- return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
68
+ return 1U << hbitmap_granularity(bitmap->bitmap);
69
}
70
71
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
72
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
73
74
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
75
{
76
- int64_t ret = hbitmap_iter_next(&iter->hbi);
77
- return ret < 0 ? -1 : ret * BDRV_SECTOR_SIZE;
78
+ return hbitmap_iter_next(&iter->hbi);
79
}
80
81
/* Called within bdrv_dirty_bitmap_lock..unlock */
82
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
83
int64_t offset, int64_t bytes)
84
{
85
- int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
86
-
87
assert(bdrv_dirty_bitmap_enabled(bitmap));
88
assert(!bdrv_dirty_bitmap_readonly(bitmap));
89
- hbitmap_set(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
90
- end_sector - (offset >> BDRV_SECTOR_BITS));
91
+ hbitmap_set(bitmap->bitmap, offset, bytes);
92
}
93
94
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
95
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
96
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
97
int64_t offset, int64_t bytes)
98
{
99
- int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
100
-
101
assert(bdrv_dirty_bitmap_enabled(bitmap));
102
assert(!bdrv_dirty_bitmap_readonly(bitmap));
103
- hbitmap_reset(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
104
- end_sector - (offset >> BDRV_SECTOR_BITS));
105
+ hbitmap_reset(bitmap->bitmap, offset, bytes);
106
}
107
108
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
109
@@ -XXX,XX +XXX,XX @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
110
hbitmap_reset_all(bitmap->bitmap);
111
} else {
112
HBitmap *backup = bitmap->bitmap;
113
- bitmap->bitmap = hbitmap_alloc(DIV_ROUND_UP(bitmap->size,
114
- BDRV_SECTOR_SIZE),
115
+ bitmap->bitmap = hbitmap_alloc(bitmap->size,
116
hbitmap_granularity(backup));
117
*out = backup;
118
}
119
@@ -XXX,XX +XXX,XX @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
120
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
121
uint64_t offset, uint64_t bytes)
122
{
123
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
124
- return hbitmap_serialization_size(bitmap->bitmap,
125
- offset >> BDRV_SECTOR_BITS,
126
- bytes >> BDRV_SECTOR_BITS);
127
+ return hbitmap_serialization_size(bitmap->bitmap, offset, bytes);
128
}
129
130
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
131
{
132
- return hbitmap_serialization_align(bitmap->bitmap) * BDRV_SECTOR_SIZE;
133
+ return hbitmap_serialization_align(bitmap->bitmap);
134
}
135
136
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
137
uint8_t *buf, uint64_t offset,
138
uint64_t bytes)
139
{
140
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
141
- hbitmap_serialize_part(bitmap->bitmap, buf, offset >> BDRV_SECTOR_BITS,
142
- bytes >> BDRV_SECTOR_BITS);
143
+ hbitmap_serialize_part(bitmap->bitmap, buf, offset, bytes);
144
}
145
146
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
147
uint8_t *buf, uint64_t offset,
148
uint64_t bytes, bool finish)
149
{
150
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
151
- hbitmap_deserialize_part(bitmap->bitmap, buf, offset >> BDRV_SECTOR_BITS,
152
- bytes >> BDRV_SECTOR_BITS, finish);
153
+ hbitmap_deserialize_part(bitmap->bitmap, buf, offset, bytes, finish);
154
}
155
156
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
157
uint64_t offset, uint64_t bytes,
158
bool finish)
159
{
160
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
161
- hbitmap_deserialize_zeroes(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
162
- bytes >> BDRV_SECTOR_BITS, finish);
163
+ hbitmap_deserialize_zeroes(bitmap->bitmap, offset, bytes, finish);
164
}
165
166
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
167
uint64_t offset, uint64_t bytes,
168
bool finish)
169
{
170
- assert(QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE));
171
- hbitmap_deserialize_ones(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
172
- bytes >> BDRV_SECTOR_BITS, finish);
173
+ hbitmap_deserialize_ones(bitmap->bitmap, offset, bytes, finish);
174
}
175
176
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
177
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
178
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
179
{
180
BdrvDirtyBitmap *bitmap;
181
- int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
182
183
if (QLIST_EMPTY(&bs->dirty_bitmaps)) {
184
return;
185
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
186
continue;
187
}
188
assert(!bdrv_dirty_bitmap_readonly(bitmap));
189
- hbitmap_set(bitmap->bitmap, offset >> BDRV_SECTOR_BITS,
190
- end_sector - (offset >> BDRV_SECTOR_BITS));
191
+ hbitmap_set(bitmap->bitmap, offset, bytes);
192
}
193
bdrv_dirty_bitmaps_unlock(bs);
194
}
195
@@ -XXX,XX +XXX,XX @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
196
*/
197
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t offset)
198
{
199
- hbitmap_iter_init(&iter->hbi, iter->hbi.hb, offset >> BDRV_SECTOR_BITS);
200
+ hbitmap_iter_init(&iter->hbi, iter->hbi.hb, offset);
201
}
202
203
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
204
{
205
- return hbitmap_count(bitmap->bitmap) << BDRV_SECTOR_BITS;
206
+ return hbitmap_count(bitmap->bitmap);
207
}
208
209
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
210
--
211
2.13.6
212
213
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
This includes shell function, shell variables and command line options
4
(randomize.awk does not exist).
5
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
tests/qemu-iotests/check | 28 -----------------
11
tests/qemu-iotests/common | 23 --------------
12
tests/qemu-iotests/common.config | 26 ---------------
13
tests/qemu-iotests/common.rc | 68 ----------------------------------------
14
4 files changed, 145 deletions(-)
15
16
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/check
19
+++ b/tests/qemu-iotests/check
20
@@ -XXX,XX +XXX,XX @@ then
21
export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
22
fi
23
24
-# if ./qemu exists, it should be prioritized and will be chosen by common.config
25
if [[ -z "$QEMU_PROG" && ! -x './qemu' ]]
26
then
27
arch=$(uname -m 2> /dev/null)
28
@@ -XXX,XX +XXX,XX @@ _timestamp()
29
30
_wrapup()
31
{
32
- # for hangcheck ...
33
- # remove files that were used by hangcheck
34
- #
35
- [ -f "${TEST_DIR}"/check.pid ] && rm -rf "${TEST_DIR}"/check.pid
36
- [ -f "${TEST_DIR}"/check.sts ] && rm -rf "${TEST_DIR}"/check.sts
37
-
38
if $showme
39
then
40
:
41
@@ -XXX,XX +XXX,XX @@ END { if (NR > 0) {
42
43
trap "_wrapup; exit \$status" 0 1 2 3 15
44
45
-# for hangcheck ...
46
-# Save pid of check in a well known place, so that hangcheck can be sure it
47
-# has the right pid (getting the pid from ps output is not reliable enough).
48
-#
49
-rm -rf "${TEST_DIR}"/check.pid
50
-echo $$ > "${TEST_DIR}"/check.pid
51
-
52
-# for hangcheck ...
53
-# Save the status of check in a well known place, so that hangcheck can be
54
-# sure to know where check is up to (getting test number from ps output is
55
-# not reliable enough since the trace stuff has been introduced).
56
-#
57
-rm -rf "${TEST_DIR}"/check.sts
58
-echo "preamble" > "${TEST_DIR}"/check.sts
59
-
60
-# don't leave old full output behind on a clean run
61
-rm -f check.full
62
-
63
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
64
65
FULL_IMGFMT_DETAILS=`_full_imgfmt_details`
66
@@ -XXX,XX +XXX,XX @@ do
67
fi
68
rm -f core $seq.notrun
69
70
- # for hangcheck ...
71
- echo "$seq" > "${TEST_DIR}"/check.sts
72
-
73
start=`_wallclock`
74
$timestamp && printf %s " [$(date "+%T")]"
75
76
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
77
index XXXXXXX..XXXXXXX 100644
78
--- a/tests/qemu-iotests/common
79
+++ b/tests/qemu-iotests/common
80
@@ -XXX,XX +XXX,XX @@
81
# common procedures for QA scripts
82
#
83
84
-_setenvironment()
85
-{
86
- MSGVERB="text:action"
87
- export MSGVERB
88
-}
89
-
90
-rm -f "$OUTPUT_DIR/$iam.out"
91
-_setenvironment
92
-
93
-check=${check-true}
94
-
95
diff="diff -u"
96
verbose=false
97
debug=false
98
@@ -XXX,XX +XXX,XX @@ showme=false
99
sortme=false
100
expunge=true
101
have_test_arg=false
102
-randomize=false
103
cachemode=false
104
rm -f $tmp.list $tmp.tmp $tmp.sed
105
106
@@ -XXX,XX +XXX,XX @@ other options
107
-n show me, do not run tests
108
-o options -o options to pass to qemu-img create/convert
109
-T output timestamps
110
- -r randomize test order
111
-c mode cache mode
112
113
testlist options
114
@@ -XXX,XX +XXX,XX @@ testlist options
115
cachemode=true
116
xpand=false
117
;;
118
- -r) # randomize test order
119
- randomize=true
120
- xpand=false
121
- ;;
122
-
123
-T) # turn on timestamp output
124
timestamp=true
125
xpand=false
126
@@ -XXX,XX +XXX,XX @@ fi
127
list=`sort $tmp.list`
128
rm -f $tmp.list $tmp.tmp $tmp.sed
129
130
-if $randomize
131
-then
132
- list=`echo $list | awk -f randomize.awk`
133
-fi
134
-
135
[ "$QEMU" = "" ] && _fatal "qemu not found"
136
[ "$QEMU_IMG" = "" ] && _fatal "qemu-img not found"
137
[ "$QEMU_IO" = "" ] && _fatal "qemu-io not found"
138
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
139
index XXXXXXX..XXXXXXX 100644
140
--- a/tests/qemu-iotests/common.config
141
+++ b/tests/qemu-iotests/common.config
142
@@ -XXX,XX +XXX,XX @@
143
# You should have received a copy of the GNU General Public License
144
# along with this program. If not, see <http://www.gnu.org/licenses/>.
145
#
146
-#
147
-# setup and check for config parameters, and in particular
148
-#
149
-# EMAIL - email of the script runner.
150
-# TEST_DIR - scratch test directory
151
-#
152
-# - These can be added to $HOST_CONFIG_DIR (witch default to ./config)
153
-# below or a separate local configuration file can be used (using
154
-# the HOST_OPTIONS variable).
155
-# - This script is shared by the stress test system and the auto-qa
156
-# system (includes both regression test and benchmark components).
157
-# - this script shouldn't make any assertions about filesystem
158
-# validity or mountedness.
159
-#
160
-
161
# all tests should use a common language setting to prevent golden
162
# output mismatches.
163
export LANG=C
164
165
PATH=".:$PATH"
166
167
-HOST=`hostname -s 2> /dev/null`
168
HOSTOS=`uname -s`
169
170
-EMAIL=root@localhost # where auto-qa will send its status messages
171
-export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
172
-export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
173
export PWD=`pwd`
174
175
export _QEMU_HANDLE=0
176
@@ -XXX,XX +XXX,XX @@ _fatal()
177
export AWK_PROG="`set_prog_path awk`"
178
[ "$AWK_PROG" = "" ] && _fatal "awk not found"
179
180
-export SED_PROG="`set_prog_path sed`"
181
-[ "$SED_PROG" = "" ] && _fatal "sed not found"
182
-
183
-export PS_ALL_FLAGS="-ef"
184
-
185
if [ -z "$QEMU_PROG" ]; then
186
export QEMU_PROG="`set_prog_path qemu`"
187
fi
188
@@ -XXX,XX +XXX,XX @@ fi
189
190
export QEMU_DEFAULT_MACHINE="$default_machine"
191
192
-[ -f /etc/qemu-iotest.config ] && . /etc/qemu-iotest.config
193
-
194
if [ -z "$TEST_DIR" ]; then
195
TEST_DIR=`pwd`/scratch
196
fi
197
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
198
index XXXXXXX..XXXXXXX 100644
199
--- a/tests/qemu-iotests/common.rc
200
+++ b/tests/qemu-iotests/common.rc
201
@@ -XXX,XX +XXX,XX @@ _img_info()
202
done
203
}
204
205
-_get_pids_by_name()
206
-{
207
- if [ $# -ne 1 ]
208
- then
209
- echo "Usage: _get_pids_by_name process-name" 1>&2
210
- exit 1
211
- fi
212
-
213
- # Algorithm ... all ps(1) variants have a time of the form MM:SS or
214
- # HH:MM:SS before the psargs field, use this as the search anchor.
215
- #
216
- # Matches with $1 (process-name) occur if the first psarg is $1
217
- # or ends in /$1 ... the matching uses sed's regular expressions,
218
- # so passing a regex into $1 will work.
219
-
220
- ps $PS_ALL_FLAGS \
221
- | sed -n \
222
- -e 's/$/ /' \
223
- -e 's/[ ][ ]*/ /g' \
224
- -e 's/^ //' \
225
- -e 's/^[^ ]* //' \
226
- -e "/[0-9]:[0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \
227
- -e "/[0-9]:[0-9][0-9] *$1 /s/ .*//p"
228
-}
229
-
230
-# fqdn for localhost
231
-#
232
-_get_fqdn()
233
-{
234
- host=`hostname`
235
- $NSLOOKUP_PROG $host | $AWK_PROG '{ if ($1 == "Name:") print $2 }'
236
-}
237
-
238
-# check if run as root
239
-#
240
-_need_to_be_root()
241
-{
242
- id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
243
- if [ "$id" -ne 0 ]
244
- then
245
- echo "Arrgh ... you need to be root (not uid=$id) to run this test"
246
- exit 1
247
- fi
248
-}
249
-
250
# bail out, setting up .notrun file
251
#
252
_notrun()
253
@@ -XXX,XX +XXX,XX @@ _full_platform_details()
254
echo "$os/$platform $host $kernel"
255
}
256
257
-_link_out_file()
258
-{
259
- if [ -z "$1" ]; then
260
- echo Error must pass \$seq.
261
- exit
262
- fi
263
- rm -f $1
264
- if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
265
- ln -s $1.irix $1
266
- elif [ "`uname`" == "Linux" ]; then
267
- ln -s $1.linux $1
268
- else
269
- echo Error test $seq does not run on the operating system: `uname`
270
- exit
271
- fi
272
-}
273
-
274
-_die()
275
-{
276
- echo $@
277
- exit 1
278
-}
279
-
280
# make sure this script returns success
281
true
282
--
283
2.13.6
284
285
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
Some functions in common.rc are never used by the tests. Move
4
them out of that file and into common, which is already included
5
only by "check".
6
7
Code that actually *is* common to "check" and tests can be placed in
8
common.config.
9
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
tests/qemu-iotests/common | 25 ++++++++++++++++++++++++-
15
tests/qemu-iotests/common.config | 12 ++++++++++++
16
tests/qemu-iotests/common.rc | 40 ----------------------------------------
17
3 files changed, 36 insertions(+), 41 deletions(-)
18
19
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/common
22
+++ b/tests/qemu-iotests/common
23
@@ -XXX,XX +XXX,XX @@
24
# common procedures for QA scripts
25
#
26
27
+_full_imgfmt_details()
28
+{
29
+ if [ -n "$IMGOPTS" ]; then
30
+ echo "$IMGFMT ($IMGOPTS)"
31
+ else
32
+ echo "$IMGFMT"
33
+ fi
34
+}
35
+
36
+_full_platform_details()
37
+{
38
+ os=`uname -s`
39
+ host=`hostname -s`
40
+ kernel=`uname -r`
41
+ platform=`uname -m`
42
+ echo "$os/$platform $host $kernel"
43
+}
44
+
45
diff="diff -u"
46
verbose=false
47
debug=false
48
@@ -XXX,XX +XXX,XX @@ if [ "$IMGOPTSSYNTAX" != "true" ]; then
49
fi
50
51
# Set default options for qemu-img create -o if they were not specified
52
-_set_default_imgopts
53
+if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
54
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
55
+fi
56
+if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
57
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
58
+fi
59
60
if [ -s $tmp.list ]
61
then
62
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/common.config
65
+++ b/tests/qemu-iotests/common.config
66
@@ -XXX,XX +XXX,XX @@ export PWD=`pwd`
67
68
export _QEMU_HANDLE=0
69
70
+# make sure we have a standard umask
71
+umask 022
72
+
73
# $1 = prog to look for, $2* = default pathnames if not found in $PATH
74
set_prog_path()
75
{
76
@@ -XXX,XX +XXX,XX @@ set_prog_path()
77
return 1
78
}
79
80
+_optstr_add()
81
+{
82
+ if [ -n "$1" ]; then
83
+ echo "$1,$2"
84
+ else
85
+ echo "$2"
86
+ fi
87
+}
88
+
89
_fatal()
90
{
91
echo "$*"
92
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
93
index XXXXXXX..XXXXXXX 100644
94
--- a/tests/qemu-iotests/common.rc
95
+++ b/tests/qemu-iotests/common.rc
96
@@ -XXX,XX +XXX,XX @@ then
97
fi
98
fi
99
100
-# make sure we have a standard umask
101
-umask 022
102
-
103
if [ "$IMGOPTSSYNTAX" = "true" ]; then
104
DRIVER="driver=$IMGFMT"
105
if [ "$IMGFMT" = "luks" ]; then
106
@@ -XXX,XX +XXX,XX @@ else
107
fi
108
ORIG_TEST_IMG="$TEST_IMG"
109
110
-_optstr_add()
111
-{
112
- if [ -n "$1" ]; then
113
- echo "$1,$2"
114
- else
115
- echo "$2"
116
- fi
117
-}
118
-
119
-_set_default_imgopts()
120
-{
121
- if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
122
- IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
123
- fi
124
- if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
125
- IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
126
- fi
127
-}
128
-
129
_use_sample_img()
130
{
131
SAMPLE_IMG_FILE="${1%\.bz2}"
132
@@ -XXX,XX +XXX,XX @@ _require_command()
133
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
134
}
135
136
-_full_imgfmt_details()
137
-{
138
- if [ -n "$IMGOPTS" ]; then
139
- echo "$IMGFMT ($IMGOPTS)"
140
- else
141
- echo "$IMGFMT"
142
- fi
143
-}
144
-
145
-_full_platform_details()
146
-{
147
- os=`uname -s`
148
- host=`hostname -s`
149
- kernel=`uname -r`
150
- platform=`uname -m`
151
- echo "$os/$platform $host $kernel"
152
-}
153
-
154
# make sure this script returns success
155
true
156
--
157
2.13.6
158
159
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
It only provides functions used by the test programs.
4
5
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/check | 6 ------
10
tests/qemu-iotests/common.rc | 13 +++++--------
11
2 files changed, 5 insertions(+), 14 deletions(-)
12
13
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/check
16
+++ b/tests/qemu-iotests/check
17
@@ -XXX,XX +XXX,XX @@ then
18
_init_error "failed to source common.config"
19
fi
20
21
-# we need common.rc
22
-if ! . "$source_iotests/common.rc"
23
-then
24
- _init_error "failed to source common.rc"
25
-fi
26
-
27
# we need common
28
. "$source_iotests/common"
29
30
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
31
index XXXXXXX..XXXXXXX 100644
32
--- a/tests/qemu-iotests/common.rc
33
+++ b/tests/qemu-iotests/common.rc
34
@@ -XXX,XX +XXX,XX @@ poke_file()
35
printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
36
}
37
38
-# we need common.config
39
-if [ "$iam" != "check" ]
40
-then
41
- if ! . ./common.config
42
- then
43
- echo "$iam: failed to source common.config"
44
- exit 1
45
- fi
46
+
47
+if ! . ./common.config
48
+ then
49
+ echo "$iam: failed to source common.config"
50
+ exit 1
51
fi
52
53
_qemu_wrapper()
54
--
55
2.13.6
56
57
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
The variable is used in "common" but defined only after the file
4
is sourced.
5
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
tests/qemu-iotests/check | 2 --
11
tests/qemu-iotests/common | 2 ++
12
2 files changed, 2 insertions(+), 2 deletions(-)
13
14
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/check
17
+++ b/tests/qemu-iotests/check
18
@@ -XXX,XX +XXX,XX @@ fi
19
20
TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT
21
22
-tmp="${TEST_DIR}"/$$
23
-
24
_wallclock()
25
{
26
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
27
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
28
index XXXXXXX..XXXXXXX 100644
29
--- a/tests/qemu-iotests/common
30
+++ b/tests/qemu-iotests/common
31
@@ -XXX,XX +XXX,XX @@ sortme=false
32
expunge=true
33
have_test_arg=false
34
cachemode=false
35
+
36
+tmp="${TEST_DIR}"/$$
37
rm -f $tmp.list $tmp.tmp $tmp.sed
38
39
export IMGFMT=raw
40
--
41
2.13.6
42
43
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Backing may be zero after failed bdrv_append in mirror_start_job,
3
Actually L1 table entry offset is in 512 bytes sectors. Fix the spec.
4
which leads to SIGSEGV.
5
4
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20170929152255.5431-1-vsementsov@virtuozzo.com
6
Message-Id: <20210224104707.88430-3-vsementsov@virtuozzo.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Denis V. Lunev <den@openvz.org>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
9
---
10
block/mirror.c | 4 ++++
10
docs/interop/parallels.txt | 28 ++++++++++++++++------------
11
1 file changed, 4 insertions(+)
11
1 file changed, 16 insertions(+), 12 deletions(-)
12
12
13
diff --git a/block/mirror.c b/block/mirror.c
13
diff --git a/docs/interop/parallels.txt b/docs/interop/parallels.txt
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/mirror.c
15
--- a/docs/interop/parallels.txt
16
+++ b/block/mirror.c
16
+++ b/docs/interop/parallels.txt
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
17
@@ -XXX,XX +XXX,XX @@ of its data area are:
18
18
28 - 31: l1_size
19
static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
19
The number of entries in the L1 table of the bitmap.
20
{
20
21
+ if (bs->backing == NULL) {
21
- variable: l1_table (8 * l1_size bytes)
22
+ /* we can be here after failed bdrv_append in mirror_start_job */
22
- L1 offset table (in bytes)
23
+ return 0;
23
+ variable: L1 offset table (l1_table), size: 8 * l1_size bytes
24
+ }
24
25
return bdrv_co_flush(bs->backing->bs);
25
-A dirty bitmap is stored using a one-level structure for the mapping to host
26
}
26
-clusters - an L1 table.
27
27
+The dirty bitmap described by this feature extension is stored in a set of
28
+clusters inside the Parallels image file. The offsets of these clusters are
29
+saved in the L1 offset table specified by the feature extension. Each L1 table
30
+entry is a 64 bit integer as described below:
31
32
-Given an offset in bytes into the bitmap data, the offset in bytes into the
33
-image file can be obtained as follows:
34
+Given an offset in bytes into the bitmap data, corresponding L1 entry is
35
36
- offset = l1_table[offset / cluster_size] + (offset % cluster_size)
37
+ l1_table[offset / cluster_size]
38
39
-If an L1 table entry is 0, the corresponding cluster of the bitmap is assumed
40
-to be zero.
41
+If an L1 table entry is 0, all bits in the corresponding cluster of the bitmap
42
+are assumed to be 0.
43
44
-If an L1 table entry is 1, the corresponding cluster of the bitmap is assumed
45
-to have all bits set.
46
+If an L1 table entry is 1, all bits in the corresponding cluster of the bitmap
47
+are assumed to be 1.
48
49
-If an L1 table entry is not 0 or 1, it allocates a cluster from the data area.
50
+If an L1 table entry is not 0 or 1, it contains the corresponding cluster
51
+offset (in 512b sectors). Given an offset in bytes into the bitmap data the
52
+offset in bytes into the image file can be obtained as follows:
53
+
54
+ offset = l1_table[offset / cluster_size] * 512 + (offset % cluster_size)
28
--
55
--
29
2.13.6
56
2.29.2
30
57
31
58
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
While current encryption schemes all have a fixed sector size of
3
We are going to use it in more places, calculating
4
512 bytes, this is not guaranteed to be the case in future. Expose
4
"s->tracks << BDRV_SECTOR_BITS" doesn't look good.
5
the sector size in the APIs so the block layer can remove assumptions
6
about fixed 512 byte sectors.
7
5
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-Id: <20210224104707.88430-4-vsementsov@virtuozzo.com>
10
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
8
Reviewed-by: Denis V. Lunev <den@openvz.org>
11
Message-id: 20170927125340.12360-3-berrange@redhat.com
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
10
---
14
crypto/blockpriv.h | 1 +
11
block/parallels.h | 1 +
15
include/crypto/block.h | 15 +++++++++++++++
12
block/parallels.c | 8 ++++----
16
crypto/block-luks.c | 6 ++++--
13
2 files changed, 5 insertions(+), 4 deletions(-)
17
crypto/block-qcow.c | 1 +
18
crypto/block.c | 6 ++++++
19
5 files changed, 27 insertions(+), 2 deletions(-)
20
14
21
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
15
diff --git a/block/parallels.h b/block/parallels.h
22
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
23
--- a/crypto/blockpriv.h
17
--- a/block/parallels.h
24
+++ b/crypto/blockpriv.h
18
+++ b/block/parallels.h
25
@@ -XXX,XX +XXX,XX @@ struct QCryptoBlock {
19
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVParallelsState {
26
QCryptoHashAlgorithm kdfhash;
20
ParallelsPreallocMode prealloc_mode;
27
size_t niv;
21
28
uint64_t payload_offset; /* In bytes */
22
unsigned int tracks;
29
+ uint64_t sector_size; /* In bytes */
23
+ unsigned int cluster_size;
30
};
24
31
25
unsigned int off_multiplier;
32
struct QCryptoBlockDriver {
26
Error *migration_blocker;
33
diff --git a/include/crypto/block.h b/include/crypto/block.h
27
diff --git a/block/parallels.c b/block/parallels.c
34
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
35
--- a/include/crypto/block.h
29
--- a/block/parallels.c
36
+++ b/include/crypto/block.h
30
+++ b/block/parallels.c
37
@@ -XXX,XX +XXX,XX @@ QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
31
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
38
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
32
int ret;
39
33
uint32_t i;
40
/**
34
bool flush_bat = false;
41
+ * qcrypto_block_get_sector_size:
35
- int cluster_size = s->tracks << BDRV_SECTOR_BITS;
42
+ * @block: the block encryption object
36
43
+ *
37
size = bdrv_getlength(bs->file->bs);
44
+ * Get the size of sectors used for payload encryption. A new
38
if (size < 0) {
45
+ * IV is used at the start of each sector. The encryption
39
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
46
+ * sector size is not required to match the sector size of the
40
high_off = off;
47
+ * underlying storage. For example LUKS will always use a 512
41
}
48
+ * byte sector size, even if the volume is on a disk with 4k
42
49
+ * sectors.
43
- if (prev_off != 0 && (prev_off + cluster_size) != off) {
50
+ *
44
+ if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
51
+ * Returns: the sector in bytes
45
res->bfi.fragmented_clusters++;
52
+ */
46
}
53
+uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
47
prev_off = off;
54
+
48
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
55
+/**
56
* qcrypto_block_free:
57
* @block: the block encryption object
58
*
59
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/crypto/block-luks.c
62
+++ b/crypto/block-luks.c
63
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_open(QCryptoBlock *block,
64
}
49
}
65
}
50
}
66
51
67
+ block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
52
- res->image_end_offset = high_off + cluster_size;
68
block->payload_offset = luks->header.payload_offset *
53
+ res->image_end_offset = high_off + s->cluster_size;
69
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
54
if (size > res->image_end_offset) {
70
+ block->sector_size;
55
int64_t count;
71
56
- count = DIV_ROUND_UP(size - res->image_end_offset, cluster_size);
72
luks->cipher_alg = cipheralg;
57
+ count = DIV_ROUND_UP(size - res->image_end_offset, s->cluster_size);
73
luks->cipher_mode = ciphermode;
58
fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n",
74
@@ -XXX,XX +XXX,XX @@ qcrypto_block_luks_create(QCryptoBlock *block,
59
fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
75
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
60
size - res->image_end_offset);
76
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
61
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
77
62
ret = -EFBIG;
78
+ block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
79
block->payload_offset = luks->header.payload_offset *
80
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
81
+ block->sector_size;
82
83
/* Reserve header space to match payload offset */
84
initfunc(block, block->payload_offset, opaque, &local_err);
85
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/crypto/block-qcow.c
88
+++ b/crypto/block-qcow.c
89
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_init(QCryptoBlock *block,
90
goto fail;
63
goto fail;
91
}
64
}
92
65
+ s->cluster_size = s->tracks << BDRV_SECTOR_BITS;
93
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
66
94
block->payload_offset = 0;
67
s->bat_size = le32_to_cpu(ph.bat_entries);
95
68
if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
96
return 0;
97
diff --git a/crypto/block.c b/crypto/block.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/crypto/block.c
100
+++ b/crypto/block.c
101
@@ -XXX,XX +XXX,XX @@ uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
102
}
103
104
105
+uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
106
+{
107
+ return block->sector_size;
108
+}
109
+
110
+
111
void qcrypto_block_free(QCryptoBlock *block)
112
{
113
if (!block) {
114
--
69
--
115
2.13.6
70
2.29.2
116
71
117
72
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
"check" is full of qemu-iotests--specific details. Separating it
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
from "common" does not make much sense anymore.
4
Message-Id: <20210224104707.88430-5-vsementsov@virtuozzo.com>
5
5
Reviewed-by: Denis V. Lunev <den@openvz.org>
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
7
---
10
tests/qemu-iotests/check | 533 +++++++++++++++++++++++++++++++++++++++++++-
8
block/parallels.h | 6 +-
11
tests/qemu-iotests/common | 552 ----------------------------------------------
9
block/parallels-ext.c | 300 ++++++++++++++++++++++++++++++++++++++++++
12
2 files changed, 531 insertions(+), 554 deletions(-)
10
block/parallels.c | 18 +++
13
delete mode 100644 tests/qemu-iotests/common
11
block/meson.build | 3 +-
12
4 files changed, 325 insertions(+), 2 deletions(-)
13
create mode 100644 block/parallels-ext.c
14
14
15
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
15
diff --git a/block/parallels.h b/block/parallels.h
16
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/check
17
--- a/block/parallels.h
18
+++ b/tests/qemu-iotests/check
18
+++ b/block/parallels.h
19
@@ -XXX,XX +XXX,XX @@ then
19
@@ -XXX,XX +XXX,XX @@ typedef struct ParallelsHeader {
20
_init_error "failed to source common.config"
20
uint64_t nb_sectors;
21
fi
21
uint32_t inuse;
22
22
uint32_t data_off;
23
-# we need common
23
- char padding[12];
24
-. "$source_iotests/common"
24
+ uint32_t flags;
25
+_full_imgfmt_details()
25
+ uint64_t ext_off;
26
} QEMU_PACKED ParallelsHeader;
27
28
typedef enum ParallelsPreallocMode {
29
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVParallelsState {
30
Error *migration_blocker;
31
} BDRVParallelsState;
32
33
+int parallels_read_format_extension(BlockDriverState *bs,
34
+ int64_t ext_off, Error **errp);
35
+
36
#endif
37
diff --git a/block/parallels-ext.c b/block/parallels-ext.c
38
new file mode 100644
39
index XXXXXXX..XXXXXXX
40
--- /dev/null
41
+++ b/block/parallels-ext.c
42
@@ -XXX,XX +XXX,XX @@
43
+/*
44
+ * Support of Parallels Format Extension. It's a part of Parallels format
45
+ * driver.
46
+ *
47
+ * Copyright (c) 2021 Virtuozzo International GmbH
48
+ *
49
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
50
+ * of this software and associated documentation files (the "Software"), to deal
51
+ * in the Software without restriction, including without limitation the rights
52
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53
+ * copies of the Software, and to permit persons to whom the Software is
54
+ * furnished to do so, subject to the following conditions:
55
+ *
56
+ * The above copyright notice and this permission notice shall be included in
57
+ * all copies or substantial portions of the Software.
58
+ *
59
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
62
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
65
+ * THE SOFTWARE.
66
+ */
67
+
68
+#include "qemu/osdep.h"
69
+#include "qapi/error.h"
70
+#include "block/block_int.h"
71
+#include "parallels.h"
72
+#include "crypto/hash.h"
73
+#include "qemu/uuid.h"
74
+
75
+#define PARALLELS_FORMAT_EXTENSION_MAGIC 0xAB234CEF23DCEA87ULL
76
+
77
+#define PARALLELS_END_OF_FEATURES_MAGIC 0x0ULL
78
+#define PARALLELS_DIRTY_BITMAP_FEATURE_MAGIC 0x20385FAE252CB34AULL
79
+
80
+typedef struct ParallelsFormatExtensionHeader {
81
+ uint64_t magic; /* PARALLELS_FORMAT_EXTENSION_MAGIC */
82
+ uint8_t check_sum[16];
83
+} QEMU_PACKED ParallelsFormatExtensionHeader;
84
+
85
+typedef struct ParallelsFeatureHeader {
86
+ uint64_t magic;
87
+ uint64_t flags;
88
+ uint32_t data_size;
89
+ uint32_t _unused;
90
+} QEMU_PACKED ParallelsFeatureHeader;
91
+
92
+typedef struct ParallelsDirtyBitmapFeature {
93
+ uint64_t size;
94
+ uint8_t id[16];
95
+ uint32_t granularity;
96
+ uint32_t l1_size;
97
+ /* L1 table follows */
98
+} QEMU_PACKED ParallelsDirtyBitmapFeature;
99
+
100
+/* Given L1 table read bitmap data from the image and populate @bitmap */
101
+static int parallels_load_bitmap_data(BlockDriverState *bs,
102
+ const uint64_t *l1_table,
103
+ uint32_t l1_size,
104
+ BdrvDirtyBitmap *bitmap,
105
+ Error **errp)
26
+{
106
+{
27
+ if [ -n "$IMGOPTS" ]; then
107
+ BDRVParallelsState *s = bs->opaque;
28
+ echo "$IMGFMT ($IMGOPTS)"
108
+ int ret = 0;
29
+ else
109
+ uint64_t offset, limit;
30
+ echo "$IMGFMT"
110
+ uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
31
+ fi
111
+ uint8_t *buf = NULL;
112
+ uint64_t i, tab_size =
113
+ DIV_ROUND_UP(bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size),
114
+ s->cluster_size);
115
+
116
+ if (tab_size != l1_size) {
117
+ error_setg(errp, "Bitmap table size %" PRIu32 " does not correspond "
118
+ "to bitmap size and cluster size. Expected %" PRIu64,
119
+ l1_size, tab_size);
120
+ return -EINVAL;
121
+ }
122
+
123
+ buf = qemu_blockalign(bs, s->cluster_size);
124
+ limit = bdrv_dirty_bitmap_serialization_coverage(s->cluster_size, bitmap);
125
+ for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) {
126
+ uint64_t count = MIN(bm_size - offset, limit);
127
+ uint64_t entry = l1_table[i];
128
+
129
+ if (entry == 0) {
130
+ /* No need to deserialize zeros because @bitmap is cleared. */
131
+ continue;
132
+ }
133
+
134
+ if (entry == 1) {
135
+ bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count, false);
136
+ } else {
137
+ ret = bdrv_pread(bs->file, entry << BDRV_SECTOR_BITS, buf,
138
+ s->cluster_size);
139
+ if (ret < 0) {
140
+ error_setg_errno(errp, -ret,
141
+ "Failed to read bitmap data cluster");
142
+ goto finish;
143
+ }
144
+ bdrv_dirty_bitmap_deserialize_part(bitmap, buf, offset, count,
145
+ false);
146
+ }
147
+ }
148
+ ret = 0;
149
+
150
+ bdrv_dirty_bitmap_deserialize_finish(bitmap);
151
+
152
+finish:
153
+ qemu_vfree(buf);
154
+
155
+ return ret;
32
+}
156
+}
33
+
157
+
34
+_full_platform_details()
158
+/*
159
+ * @data buffer (of @data_size size) is the Dirty bitmaps feature which
160
+ * consists of ParallelsDirtyBitmapFeature followed by L1 table.
161
+ */
162
+static BdrvDirtyBitmap *parallels_load_bitmap(BlockDriverState *bs,
163
+ uint8_t *data,
164
+ size_t data_size,
165
+ Error **errp)
35
+{
166
+{
36
+ os=`uname -s`
167
+ int ret;
37
+ host=`hostname -s`
168
+ ParallelsDirtyBitmapFeature bf;
38
+ kernel=`uname -r`
169
+ g_autofree uint64_t *l1_table = NULL;
39
+ platform=`uname -m`
170
+ BdrvDirtyBitmap *bitmap;
40
+ echo "$os/$platform $host $kernel"
171
+ QemuUUID uuid;
172
+ char uuidstr[UUID_FMT_LEN + 1];
173
+ int i;
174
+
175
+ if (data_size < sizeof(bf)) {
176
+ error_setg(errp, "Too small Bitmap Feature area in Parallels Format "
177
+ "Extension: %zu bytes, expected at least %zu bytes",
178
+ data_size, sizeof(bf));
179
+ return NULL;
180
+ }
181
+ memcpy(&bf, data, sizeof(bf));
182
+ bf.size = le64_to_cpu(bf.size);
183
+ bf.granularity = le32_to_cpu(bf.granularity) << BDRV_SECTOR_BITS;
184
+ bf.l1_size = le32_to_cpu(bf.l1_size);
185
+ data += sizeof(bf);
186
+ data_size -= sizeof(bf);
187
+
188
+ if (bf.size != bs->total_sectors) {
189
+ error_setg(errp, "Bitmap size (in sectors) %" PRId64 " differs from "
190
+ "disk size in sectors %" PRId64, bf.size, bs->total_sectors);
191
+ return NULL;
192
+ }
193
+
194
+ if (bf.l1_size * sizeof(uint64_t) > data_size) {
195
+ error_setg(errp, "Bitmaps feature corrupted: l1 table exceeds "
196
+ "extension data_size");
197
+ return NULL;
198
+ }
199
+
200
+ memcpy(&uuid, bf.id, sizeof(uuid));
201
+ qemu_uuid_unparse(&uuid, uuidstr);
202
+ bitmap = bdrv_create_dirty_bitmap(bs, bf.granularity, uuidstr, errp);
203
+ if (!bitmap) {
204
+ return NULL;
205
+ }
206
+
207
+ l1_table = g_new(uint64_t, bf.l1_size);
208
+ for (i = 0; i < bf.l1_size; i++, data += sizeof(uint64_t)) {
209
+ l1_table[i] = ldq_le_p(data);
210
+ }
211
+
212
+ ret = parallels_load_bitmap_data(bs, l1_table, bf.l1_size, bitmap, errp);
213
+ if (ret < 0) {
214
+ bdrv_release_dirty_bitmap(bitmap);
215
+ return NULL;
216
+ }
217
+
218
+ /* We support format extension only for RO parallels images. */
219
+ assert(!(bs->open_flags & BDRV_O_RDWR));
220
+ bdrv_dirty_bitmap_set_readonly(bitmap, true);
221
+
222
+ return bitmap;
41
+}
223
+}
42
+
224
+
43
+# $1 = prog to look for
225
+static int parallels_parse_format_extension(BlockDriverState *bs,
44
+set_prog_path()
226
+ uint8_t *ext_cluster, Error **errp)
45
+{
227
+{
46
+ p=`command -v $1 2> /dev/null`
228
+ BDRVParallelsState *s = bs->opaque;
47
+ if [ -n "$p" -a -x "$p" ]; then
229
+ int ret;
48
+ realpath -- "$(type -p "$p")"
230
+ int remaining = s->cluster_size;
49
+ else
231
+ uint8_t *pos = ext_cluster;
50
+ return 1
232
+ ParallelsFormatExtensionHeader eh;
51
+ fi
233
+ g_autofree uint8_t *hash = NULL;
234
+ size_t hash_len = 0;
235
+ GSList *bitmaps = NULL, *el;
236
+
237
+ memcpy(&eh, pos, sizeof(eh));
238
+ eh.magic = le64_to_cpu(eh.magic);
239
+ pos += sizeof(eh);
240
+ remaining -= sizeof(eh);
241
+
242
+ if (eh.magic != PARALLELS_FORMAT_EXTENSION_MAGIC) {
243
+ error_setg(errp, "Wrong parallels Format Extension magic: 0x%" PRIx64
244
+ ", expected: 0x%llx", eh.magic,
245
+ PARALLELS_FORMAT_EXTENSION_MAGIC);
246
+ goto fail;
247
+ }
248
+
249
+ ret = qcrypto_hash_bytes(QCRYPTO_HASH_ALG_MD5, (char *)pos, remaining,
250
+ &hash, &hash_len, errp);
251
+ if (ret < 0) {
252
+ goto fail;
253
+ }
254
+
255
+ if (hash_len != sizeof(eh.check_sum) ||
256
+ memcmp(hash, eh.check_sum, sizeof(eh.check_sum)) != 0) {
257
+ error_setg(errp, "Wrong checksum in Format Extension header. Format "
258
+ "extension is corrupted.");
259
+ goto fail;
260
+ }
261
+
262
+ while (true) {
263
+ ParallelsFeatureHeader fh;
264
+ BdrvDirtyBitmap *bitmap;
265
+
266
+ if (remaining < sizeof(fh)) {
267
+ error_setg(errp, "Can not read feature header, as remaining bytes "
268
+ "(%d) in Format Extension is less than Feature header "
269
+ "size (%zu)", remaining, sizeof(fh));
270
+ goto fail;
271
+ }
272
+
273
+ memcpy(&fh, pos, sizeof(fh));
274
+ pos += sizeof(fh);
275
+ remaining -= sizeof(fh);
276
+
277
+ fh.magic = le64_to_cpu(fh.magic);
278
+ fh.flags = le64_to_cpu(fh.flags);
279
+ fh.data_size = le32_to_cpu(fh.data_size);
280
+
281
+ if (fh.flags) {
282
+ error_setg(errp, "Flags for extension feature are unsupported");
283
+ goto fail;
284
+ }
285
+
286
+ if (fh.data_size > remaining) {
287
+ error_setg(errp, "Feature data_size exceedes Format Extension "
288
+ "cluster");
289
+ goto fail;
290
+ }
291
+
292
+ switch (fh.magic) {
293
+ case PARALLELS_END_OF_FEATURES_MAGIC:
294
+ return 0;
295
+
296
+ case PARALLELS_DIRTY_BITMAP_FEATURE_MAGIC:
297
+ bitmap = parallels_load_bitmap(bs, pos, fh.data_size, errp);
298
+ if (!bitmap) {
299
+ goto fail;
300
+ }
301
+ bitmaps = g_slist_append(bitmaps, bitmap);
302
+ break;
303
+
304
+ default:
305
+ error_setg(errp, "Unknown feature: 0x%" PRIu64, fh.magic);
306
+ goto fail;
307
+ }
308
+
309
+ pos = ext_cluster + QEMU_ALIGN_UP(pos + fh.data_size - ext_cluster, 8);
310
+ }
311
+
312
+fail:
313
+ for (el = bitmaps; el; el = el->next) {
314
+ bdrv_release_dirty_bitmap(el->data);
315
+ }
316
+ g_slist_free(bitmaps);
317
+
318
+ return -EINVAL;
52
+}
319
+}
53
+
320
+
54
+if [ -z "$TEST_DIR" ]; then
321
+int parallels_read_format_extension(BlockDriverState *bs,
55
+ TEST_DIR=`pwd`/scratch
322
+ int64_t ext_off, Error **errp)
56
+fi
323
+{
57
+
324
+ BDRVParallelsState *s = bs->opaque;
58
+if [ ! -e "$TEST_DIR" ]; then
325
+ int ret;
59
+ mkdir "$TEST_DIR"
326
+ uint8_t *ext_cluster = qemu_blockalign(bs, s->cluster_size);
60
+fi
327
+
61
+
328
+ assert(ext_off > 0);
62
+diff="diff -u"
329
+
63
+verbose=false
330
+ ret = bdrv_pread(bs->file, ext_off, ext_cluster, s->cluster_size);
64
+debug=false
331
+ if (ret < 0) {
65
+group=false
332
+ error_setg_errno(errp, -ret, "Failed to read Format Extension cluster");
66
+xgroup=false
333
+ goto out;
67
+imgopts=false
334
+ }
68
+showme=false
335
+
69
+sortme=false
336
+ ret = parallels_parse_format_extension(bs, ext_cluster, errp);
70
+expunge=true
337
+
71
+have_test_arg=false
338
+out:
72
+cachemode=false
339
+ qemu_vfree(ext_cluster);
73
+
340
+
74
+tmp="${TEST_DIR}"/$$
341
+ return ret;
75
+rm -f $tmp.list $tmp.tmp $tmp.sed
342
+}
76
+
343
diff --git a/block/parallels.c b/block/parallels.c
77
+export IMGFMT=raw
344
index XXXXXXX..XXXXXXX 100644
78
+export IMGFMT_GENERIC=true
345
--- a/block/parallels.c
79
+export IMGPROTO=file
346
+++ b/block/parallels.c
80
+export IMGOPTS=""
81
+export CACHEMODE="writeback"
82
+export QEMU_IO_OPTIONS=""
83
+export QEMU_IO_OPTIONS_NO_FMT=""
84
+export CACHEMODE_IS_DEFAULT=true
85
+export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
86
+export VALGRIND_QEMU=
87
+export IMGKEYSECRET=
88
+export IMGOPTSSYNTAX=false
89
+
90
+for r
91
+do
92
+
93
+ if $group
94
+ then
95
+ # arg after -g
96
+ group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
97
+s/ .*//p
98
+}'`
99
+ if [ -z "$group_list" ]
100
+ then
101
+ echo "Group \"$r\" is empty or not defined?"
102
+ exit 1
103
+ fi
104
+ [ ! -s $tmp.list ] && touch $tmp.list
105
+ for t in $group_list
106
+ do
107
+ if grep -s "^$t\$" $tmp.list >/dev/null
108
+ then
109
+ :
110
+ else
111
+ echo "$t" >>$tmp.list
112
+ fi
113
+ done
114
+ group=false
115
+ continue
116
+
117
+ elif $xgroup
118
+ then
119
+ # arg after -x
120
+ # Populate $tmp.list with all tests
121
+ awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
122
+ group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
123
+s/ .*//p
124
+}'`
125
+ if [ -z "$group_list" ]
126
+ then
127
+ echo "Group \"$r\" is empty or not defined?"
128
+ exit 1
129
+ fi
130
+ numsed=0
131
+ rm -f $tmp.sed
132
+ for t in $group_list
133
+ do
134
+ if [ $numsed -gt 100 ]
135
+ then
136
+ sed -f $tmp.sed <$tmp.list >$tmp.tmp
137
+ mv $tmp.tmp $tmp.list
138
+ numsed=0
139
+ rm -f $tmp.sed
140
+ fi
141
+ echo "/^$t\$/d" >>$tmp.sed
142
+ numsed=`expr $numsed + 1`
143
+ done
144
+ sed -f $tmp.sed <$tmp.list >$tmp.tmp
145
+ mv $tmp.tmp $tmp.list
146
+ xgroup=false
147
+ continue
148
+
149
+ elif $imgopts
150
+ then
151
+ IMGOPTS="$r"
152
+ imgopts=false
153
+ continue
154
+ elif $cachemode
155
+ then
156
+ CACHEMODE="$r"
157
+ CACHEMODE_IS_DEFAULT=false
158
+ cachemode=false
159
+ continue
160
+ fi
161
+
162
+ xpand=true
163
+ case "$r"
164
+ in
165
+
166
+ -\? | -h | --help) # usage
167
+ echo "Usage: $0 [options] [testlist]"'
168
+
169
+common options
170
+ -v verbose
171
+ -d debug
172
+
173
+image format options
174
+ -raw test raw (default)
175
+ -bochs test bochs
176
+ -cloop test cloop
177
+ -parallels test parallels
178
+ -qcow test qcow
179
+ -qcow2 test qcow2
180
+ -qed test qed
181
+ -vdi test vdi
182
+ -vpc test vpc
183
+ -vhdx test vhdx
184
+ -vmdk test vmdk
185
+ -luks test luks
186
+
187
+image protocol options
188
+ -file test file (default)
189
+ -rbd test rbd
190
+ -sheepdog test sheepdog
191
+ -nbd test nbd
192
+ -ssh test ssh
193
+ -nfs test nfs
194
+ -vxhs test vxhs
195
+
196
+other options
197
+ -xdiff graphical mode diff
198
+ -nocache use O_DIRECT on backing file
199
+ -misalign misalign memory allocations
200
+ -n show me, do not run tests
201
+ -o options -o options to pass to qemu-img create/convert
202
+ -T output timestamps
203
+ -c mode cache mode
204
+
205
+testlist options
206
+ -g group[,group...] include tests from these groups
207
+ -x group[,group...] exclude tests from these groups
208
+ NNN include test NNN
209
+ NNN-NNN include test range (eg. 012-021)
210
+'
211
+ exit 0
212
+ ;;
213
+
214
+ -raw)
215
+ IMGFMT=raw
216
+ xpand=false
217
+ ;;
218
+
219
+ -bochs)
220
+ IMGFMT=bochs
221
+ IMGFMT_GENERIC=false
222
+ xpand=false
223
+ ;;
224
+
225
+ -cloop)
226
+ IMGFMT=cloop
227
+ IMGFMT_GENERIC=false
228
+ xpand=false
229
+ ;;
230
+
231
+ -parallels)
232
+ IMGFMT=parallels
233
+ IMGFMT_GENERIC=false
234
+ xpand=false
235
+ ;;
236
+
237
+ -qcow)
238
+ IMGFMT=qcow
239
+ xpand=false
240
+ ;;
241
+
242
+ -qcow2)
243
+ IMGFMT=qcow2
244
+ xpand=false
245
+ ;;
246
+
247
+ -luks)
248
+ IMGOPTSSYNTAX=true
249
+ IMGFMT=luks
250
+ IMGKEYSECRET=123456
251
+ xpand=false
252
+ ;;
253
+
254
+ -qed)
255
+ IMGFMT=qed
256
+ xpand=false
257
+ ;;
258
+
259
+ -vdi)
260
+ IMGFMT=vdi
261
+ xpand=false
262
+ ;;
263
+
264
+ -vmdk)
265
+ IMGFMT=vmdk
266
+ xpand=false
267
+ ;;
268
+
269
+ -vpc)
270
+ IMGFMT=vpc
271
+ xpand=false
272
+ ;;
273
+
274
+ -vhdx)
275
+ IMGFMT=vhdx
276
+ xpand=false
277
+ ;;
278
+
279
+ -file)
280
+ IMGPROTO=file
281
+ xpand=false
282
+ ;;
283
+
284
+ -rbd)
285
+ IMGPROTO=rbd
286
+ xpand=false
287
+ ;;
288
+
289
+ -sheepdog)
290
+ IMGPROTO=sheepdog
291
+ xpand=false
292
+ ;;
293
+
294
+ -nbd)
295
+ IMGPROTO=nbd
296
+ xpand=false
297
+ ;;
298
+
299
+ -vxhs)
300
+ IMGPROTO=vxhs
301
+ xpand=false
302
+ ;;
303
+
304
+ -ssh)
305
+ IMGPROTO=ssh
306
+ xpand=false
307
+ ;;
308
+
309
+ -nfs)
310
+ IMGPROTO=nfs
311
+ xpand=false
312
+ ;;
313
+
314
+ -nocache)
315
+ CACHEMODE="none"
316
+ CACHEMODE_IS_DEFAULT=false
317
+ xpand=false
318
+ ;;
319
+
320
+ -misalign)
321
+ QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign"
322
+ xpand=false
323
+ ;;
324
+
325
+ -valgrind)
326
+ VALGRIND_QEMU='y'
327
+ xpand=false
328
+ ;;
329
+
330
+ -g) # -g group ... pick from group file
331
+ group=true
332
+ xpand=false
333
+ ;;
334
+
335
+ -xdiff) # graphical diff mode
336
+ xpand=false
337
+
338
+ if [ ! -z "$DISPLAY" ]
339
+ then
340
+ command -v xdiff >/dev/null 2>&1 && diff=xdiff
341
+ command -v gdiff >/dev/null 2>&1 && diff=gdiff
342
+ command -v tkdiff >/dev/null 2>&1 && diff=tkdiff
343
+ command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
344
+ fi
345
+ ;;
346
+
347
+ -n) # show me, don't do it
348
+ showme=true
349
+ xpand=false
350
+ ;;
351
+ -o)
352
+ imgopts=true
353
+ xpand=false
354
+ ;;
355
+ -c)
356
+ cachemode=true
357
+ xpand=false
358
+ ;;
359
+ -T) # turn on timestamp output
360
+ timestamp=true
361
+ xpand=false
362
+ ;;
363
+
364
+ -v)
365
+ verbose=true
366
+ xpand=false
367
+ ;;
368
+ -d)
369
+ debug=true
370
+ xpand=false
371
+ ;;
372
+ -x) # -x group ... exclude from group file
373
+ xgroup=true
374
+ xpand=false
375
+ ;;
376
+ '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
377
+ echo "No tests?"
378
+ status=1
379
+ exit $status
380
+ ;;
381
+
382
+ [0-9]*-[0-9]*)
383
+ eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
384
+ ;;
385
+
386
+ [0-9]*-)
387
+ eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
388
+ end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'`
389
+ if [ -z "$end" ]
390
+ then
391
+ echo "No tests in range \"$r\"?"
392
+ status=1
393
+ exit $status
394
+ fi
395
+ ;;
396
+
397
+ *)
398
+ start=$r
399
+ end=$r
400
+ ;;
401
+
402
+ esac
403
+
404
+ # get rid of leading 0s as can be interpreted as octal
405
+ start=`echo $start | sed 's/^0*//'`
406
+ end=`echo $end | sed 's/^0*//'`
407
+
408
+ if $xpand
409
+ then
410
+ have_test_arg=true
411
+ awk </dev/null '
412
+BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
413
+ | while read id
414
+ do
415
+ if grep -s "^$id " "$source_iotests/group" >/dev/null
416
+ then
417
+ # in group file ... OK
418
+ echo $id >>$tmp.list
419
+ else
420
+ if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null
421
+ then
422
+ # expunged ... will be reported, but not run, later
423
+ echo $id >>$tmp.list
424
+ else
425
+ # oops
426
+ if [ "$start" == "$end" -a "$id" == "$end" ]
427
+ then
428
+ echo "$id - unknown test"
429
+ exit 1
430
+ else
431
+ echo "$id - unknown test, ignored"
432
+ fi
433
+ fi
434
+ fi
435
+ done || exit 1
436
+ fi
437
+
438
+done
439
+
440
+# Set qemu-io cache mode with $CACHEMODE we have
441
+QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
442
+
443
+QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
444
+if [ "$IMGOPTSSYNTAX" != "true" ]; then
445
+ QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
446
+fi
447
+
448
+# Set default options for qemu-img create -o if they were not specified
449
+if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
450
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
451
+fi
452
+if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
453
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
454
+fi
455
+
456
+if [ -z "$SAMPLE_IMG_DIR" ]; then
457
+ SAMPLE_IMG_DIR="$source_iotests/sample_images"
458
+fi
459
+
460
+export TEST_DIR
461
+export SAMPLE_IMG_DIR
462
+
463
+if [ -s $tmp.list ]
464
+then
465
+ # found some valid test numbers ... this is good
466
+ :
467
+else
468
+ if $have_test_arg
469
+ then
470
+ # had test numbers, but none in group file ... do nothing
471
+ touch $tmp.list
472
+ else
473
+ # no test numbers, do everything from group file
474
+ sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <"$source_iotests/group" >$tmp.list
475
+ fi
476
+fi
477
+
478
+# should be sort -n, but this did not work for Linux when this
479
+# was ported from IRIX
480
+#
481
+list=`sort $tmp.list`
482
+rm -f $tmp.list $tmp.tmp $tmp.sed
483
+
484
+if [ -z "$QEMU_PROG" ]
485
+then
486
+ if [ -x "$build_iotests/qemu" ]; then
487
+ export QEMU_PROG="$build_iotests/qemu"
488
+ elif [ -x "$build_root/$arch-softmmu/qemu-system-$arch" ]; then
489
+ export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
490
+ else
491
+ pushd "$build_root" > /dev/null
492
+ for binary in *-softmmu/qemu-system-*
493
+ do
494
+ if [ -x "$binary" ]
495
+ then
496
+ export QEMU_PROG="$build_root/$binary"
497
+ break
498
+ fi
499
+ done
500
+ popd > /dev/null
501
+ [ "$QEMU_PROG" = "" ] && _init_error "qemu not found"
502
+ fi
503
+fi
504
+export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
505
+
506
+if [ -z "$QEMU_IMG_PROG" ]; then
507
+ if [ -x "$build_iotests/qemu-img" ]; then
508
+ export QEMU_IMG_PROG="$build_iotests/qemu-img"
509
+ elif [ -x "$build_root/qemu-img" ]; then
510
+ export QEMU_IMG_PROG="$build_root/qemu-img"
511
+ else
512
+ _init_error "qemu-img not found"
513
+ fi
514
+fi
515
+export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
516
+
517
+if [ -z "$QEMU_IO_PROG" ]; then
518
+ if [ -x "$build_iotests/qemu-io" ]; then
519
+ export QEMU_IO_PROG="$build_iotests/qemu-io"
520
+ elif [ -x "$build_root/qemu-io" ]; then
521
+ export QEMU_IO_PROG="$build_root/qemu-io"
522
+ else
523
+ _init_error "qemu-io not found"
524
+ fi
525
+fi
526
+export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
527
+
528
+if [ -z $QEMU_NBD_PROG ]; then
529
+ if [ -x "$build_iotests/qemu-nbd" ]; then
530
+ export QEMU_NBD_PROG="$build_iotests/qemu-nbd"
531
+ elif [ -x "$build_root/qemu-nbd" ]; then
532
+ export QEMU_NBD_PROG="$build_root/qemu-nbd"
533
+ else
534
+ _init_error "qemu-nbd not found"
535
+ fi
536
+fi
537
+export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
538
+
539
+if [ -z "$QEMU_VXHS_PROG" ]; then
540
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
541
+fi
542
+
543
+if [ -x "$build_iotests/socket_scm_helper" ]
544
+then
545
+ export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
546
+fi
547
+
548
+default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
549
+default_alias_machine=$($QEMU_PROG -machine help | \
550
+ sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
551
+if [[ "$default_alias_machine" ]]; then
552
+ default_machine="$default_alias_machine"
553
+fi
554
+
555
+export QEMU_DEFAULT_MACHINE="$default_machine"
556
557
TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT
558
559
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
560
deleted file mode 100644
561
index XXXXXXX..XXXXXXX
562
--- a/tests/qemu-iotests/common
563
+++ /dev/null
564
@@ -XXX,XX +XXX,XX @@
347
@@ -XXX,XX +XXX,XX @@
565
-#!/bin/bash
348
*/
566
-#
349
567
-# Copyright (C) 2009 Red Hat, Inc.
350
#include "qemu/osdep.h"
568
-# Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
351
+#include "qemu/error-report.h"
569
-#
352
#include "qapi/error.h"
570
-# This program is free software; you can redistribute it and/or
353
#include "block/block_int.h"
571
-# modify it under the terms of the GNU General Public License as
354
#include "block/qdict.h"
572
-# published by the Free Software Foundation.
355
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
573
-#
356
goto fail_options;
574
-# This program is distributed in the hope that it would be useful,
357
}
575
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
358
576
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
359
+ if (ph.ext_off) {
577
-# GNU General Public License for more details.
360
+ if (flags & BDRV_O_RDWR) {
578
-#
361
+ /*
579
-# You should have received a copy of the GNU General Public License
362
+ * It's unsafe to open image RW if there is an extension (as we
580
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
363
+ * don't support it). But parallels driver in QEMU historically
581
-#
364
+ * ignores the extension, so print warning and don't care.
582
-#
365
+ */
583
-# common procedures for QA scripts
366
+ warn_report("Format Extension ignored in RW mode");
584
-#
367
+ } else {
585
-
368
+ ret = parallels_read_format_extension(
586
-_full_imgfmt_details()
369
+ bs, le64_to_cpu(ph.ext_off) << BDRV_SECTOR_BITS, errp);
587
-{
370
+ if (ret < 0) {
588
- if [ -n "$IMGOPTS" ]; then
371
+ goto fail;
589
- echo "$IMGFMT ($IMGOPTS)"
372
+ }
590
- else
373
+ }
591
- echo "$IMGFMT"
374
+ }
592
- fi
375
+
593
-}
376
if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_INACTIVE)) {
594
-
377
s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC);
595
-_full_platform_details()
378
ret = parallels_update_header(bs);
596
-{
379
diff --git a/block/meson.build b/block/meson.build
597
- os=`uname -s`
380
index XXXXXXX..XXXXXXX 100644
598
- host=`hostname -s`
381
--- a/block/meson.build
599
- kernel=`uname -r`
382
+++ b/block/meson.build
600
- platform=`uname -m`
383
@@ -XXX,XX +XXX,XX @@ block_ss.add(when: 'CONFIG_QED', if_true: files(
601
- echo "$os/$platform $host $kernel"
384
'qed-table.c',
602
-}
385
'qed.c',
603
-
386
))
604
-# $1 = prog to look for
387
-block_ss.add(when: [libxml2, 'CONFIG_PARALLELS'], if_true: files('parallels.c'))
605
-set_prog_path()
388
+block_ss.add(when: [libxml2, 'CONFIG_PARALLELS'],
606
-{
389
+ if_true: files('parallels.c', 'parallels-ext.c'))
607
- p=`command -v $1 2> /dev/null`
390
block_ss.add(when: 'CONFIG_WIN32', if_true: files('file-win32.c', 'win32-aio.c'))
608
- if [ -n "$p" -a -x "$p" ]; then
391
block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit])
609
- realpath -- "$(type -p "$p")"
392
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
610
- else
611
- return 1
612
- fi
613
-}
614
-
615
-if [ -z "$TEST_DIR" ]; then
616
- TEST_DIR=`pwd`/scratch
617
-fi
618
-
619
-if [ ! -e "$TEST_DIR" ]; then
620
- mkdir "$TEST_DIR"
621
-fi
622
-
623
-diff="diff -u"
624
-verbose=false
625
-debug=false
626
-group=false
627
-xgroup=false
628
-imgopts=false
629
-showme=false
630
-sortme=false
631
-expunge=true
632
-have_test_arg=false
633
-cachemode=false
634
-
635
-tmp="${TEST_DIR}"/$$
636
-rm -f $tmp.list $tmp.tmp $tmp.sed
637
-
638
-export IMGFMT=raw
639
-export IMGFMT_GENERIC=true
640
-export IMGPROTO=file
641
-export IMGOPTS=""
642
-export CACHEMODE="writeback"
643
-export QEMU_IO_OPTIONS=""
644
-export QEMU_IO_OPTIONS_NO_FMT=""
645
-export CACHEMODE_IS_DEFAULT=true
646
-export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
647
-export VALGRIND_QEMU=
648
-export IMGKEYSECRET=
649
-export IMGOPTSSYNTAX=false
650
-
651
-for r
652
-do
653
-
654
- if $group
655
- then
656
- # arg after -g
657
- group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
658
-s/ .*//p
659
-}'`
660
- if [ -z "$group_list" ]
661
- then
662
- echo "Group \"$r\" is empty or not defined?"
663
- exit 1
664
- fi
665
- [ ! -s $tmp.list ] && touch $tmp.list
666
- for t in $group_list
667
- do
668
- if grep -s "^$t\$" $tmp.list >/dev/null
669
- then
670
- :
671
- else
672
- echo "$t" >>$tmp.list
673
- fi
674
- done
675
- group=false
676
- continue
677
-
678
- elif $xgroup
679
- then
680
- # arg after -x
681
- # Populate $tmp.list with all tests
682
- awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
683
- group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
684
-s/ .*//p
685
-}'`
686
- if [ -z "$group_list" ]
687
- then
688
- echo "Group \"$r\" is empty or not defined?"
689
- exit 1
690
- fi
691
- numsed=0
692
- rm -f $tmp.sed
693
- for t in $group_list
694
- do
695
- if [ $numsed -gt 100 ]
696
- then
697
- sed -f $tmp.sed <$tmp.list >$tmp.tmp
698
- mv $tmp.tmp $tmp.list
699
- numsed=0
700
- rm -f $tmp.sed
701
- fi
702
- echo "/^$t\$/d" >>$tmp.sed
703
- numsed=`expr $numsed + 1`
704
- done
705
- sed -f $tmp.sed <$tmp.list >$tmp.tmp
706
- mv $tmp.tmp $tmp.list
707
- xgroup=false
708
- continue
709
-
710
- elif $imgopts
711
- then
712
- IMGOPTS="$r"
713
- imgopts=false
714
- continue
715
- elif $cachemode
716
- then
717
- CACHEMODE="$r"
718
- CACHEMODE_IS_DEFAULT=false
719
- cachemode=false
720
- continue
721
- fi
722
-
723
- xpand=true
724
- case "$r"
725
- in
726
-
727
- -\? | -h | --help) # usage
728
- echo "Usage: $0 [options] [testlist]"'
729
-
730
-common options
731
- -v verbose
732
- -d debug
733
-
734
-image format options
735
- -raw test raw (default)
736
- -bochs test bochs
737
- -cloop test cloop
738
- -parallels test parallels
739
- -qcow test qcow
740
- -qcow2 test qcow2
741
- -qed test qed
742
- -vdi test vdi
743
- -vpc test vpc
744
- -vhdx test vhdx
745
- -vmdk test vmdk
746
- -luks test luks
747
-
748
-image protocol options
749
- -file test file (default)
750
- -rbd test rbd
751
- -sheepdog test sheepdog
752
- -nbd test nbd
753
- -ssh test ssh
754
- -nfs test nfs
755
- -vxhs test vxhs
756
-
757
-other options
758
- -xdiff graphical mode diff
759
- -nocache use O_DIRECT on backing file
760
- -misalign misalign memory allocations
761
- -n show me, do not run tests
762
- -o options -o options to pass to qemu-img create/convert
763
- -T output timestamps
764
- -c mode cache mode
765
-
766
-testlist options
767
- -g group[,group...] include tests from these groups
768
- -x group[,group...] exclude tests from these groups
769
- NNN include test NNN
770
- NNN-NNN include test range (eg. 012-021)
771
-'
772
- exit 0
773
- ;;
774
-
775
- -raw)
776
- IMGFMT=raw
777
- xpand=false
778
- ;;
779
-
780
- -bochs)
781
- IMGFMT=bochs
782
- IMGFMT_GENERIC=false
783
- xpand=false
784
- ;;
785
-
786
- -cloop)
787
- IMGFMT=cloop
788
- IMGFMT_GENERIC=false
789
- xpand=false
790
- ;;
791
-
792
- -parallels)
793
- IMGFMT=parallels
794
- IMGFMT_GENERIC=false
795
- xpand=false
796
- ;;
797
-
798
- -qcow)
799
- IMGFMT=qcow
800
- xpand=false
801
- ;;
802
-
803
- -qcow2)
804
- IMGFMT=qcow2
805
- xpand=false
806
- ;;
807
-
808
- -luks)
809
- IMGOPTSSYNTAX=true
810
- IMGFMT=luks
811
- IMGKEYSECRET=123456
812
- xpand=false
813
- ;;
814
-
815
- -qed)
816
- IMGFMT=qed
817
- xpand=false
818
- ;;
819
-
820
- -vdi)
821
- IMGFMT=vdi
822
- xpand=false
823
- ;;
824
-
825
- -vmdk)
826
- IMGFMT=vmdk
827
- xpand=false
828
- ;;
829
-
830
- -vpc)
831
- IMGFMT=vpc
832
- xpand=false
833
- ;;
834
-
835
- -vhdx)
836
- IMGFMT=vhdx
837
- xpand=false
838
- ;;
839
-
840
- -file)
841
- IMGPROTO=file
842
- xpand=false
843
- ;;
844
-
845
- -rbd)
846
- IMGPROTO=rbd
847
- xpand=false
848
- ;;
849
-
850
- -sheepdog)
851
- IMGPROTO=sheepdog
852
- xpand=false
853
- ;;
854
-
855
- -nbd)
856
- IMGPROTO=nbd
857
- xpand=false
858
- ;;
859
-
860
- -vxhs)
861
- IMGPROTO=vxhs
862
- xpand=false
863
- ;;
864
-
865
- -ssh)
866
- IMGPROTO=ssh
867
- xpand=false
868
- ;;
869
-
870
- -nfs)
871
- IMGPROTO=nfs
872
- xpand=false
873
- ;;
874
-
875
- -nocache)
876
- CACHEMODE="none"
877
- CACHEMODE_IS_DEFAULT=false
878
- xpand=false
879
- ;;
880
-
881
- -misalign)
882
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign"
883
- xpand=false
884
- ;;
885
-
886
- -valgrind)
887
- VALGRIND_QEMU='y'
888
- xpand=false
889
- ;;
890
-
891
- -g) # -g group ... pick from group file
892
- group=true
893
- xpand=false
894
- ;;
895
-
896
- -xdiff) # graphical diff mode
897
- xpand=false
898
-
899
- if [ ! -z "$DISPLAY" ]
900
- then
901
- command -v xdiff >/dev/null 2>&1 && diff=xdiff
902
- command -v gdiff >/dev/null 2>&1 && diff=gdiff
903
- command -v tkdiff >/dev/null 2>&1 && diff=tkdiff
904
- command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
905
- fi
906
- ;;
907
-
908
- -n) # show me, don't do it
909
- showme=true
910
- xpand=false
911
- ;;
912
- -o)
913
- imgopts=true
914
- xpand=false
915
- ;;
916
- -c)
917
- cachemode=true
918
- xpand=false
919
- ;;
920
- -T) # turn on timestamp output
921
- timestamp=true
922
- xpand=false
923
- ;;
924
-
925
- -v)
926
- verbose=true
927
- xpand=false
928
- ;;
929
- -d)
930
- debug=true
931
- xpand=false
932
- ;;
933
- -x) # -x group ... exclude from group file
934
- xgroup=true
935
- xpand=false
936
- ;;
937
- '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
938
- echo "No tests?"
939
- status=1
940
- exit $status
941
- ;;
942
-
943
- [0-9]*-[0-9]*)
944
- eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
945
- ;;
946
-
947
- [0-9]*-)
948
- eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
949
- end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'`
950
- if [ -z "$end" ]
951
- then
952
- echo "No tests in range \"$r\"?"
953
- status=1
954
- exit $status
955
- fi
956
- ;;
957
-
958
- *)
959
- start=$r
960
- end=$r
961
- ;;
962
-
963
- esac
964
-
965
- # get rid of leading 0s as can be interpreted as octal
966
- start=`echo $start | sed 's/^0*//'`
967
- end=`echo $end | sed 's/^0*//'`
968
-
969
- if $xpand
970
- then
971
- have_test_arg=true
972
- awk </dev/null '
973
-BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
974
- | while read id
975
- do
976
- if grep -s "^$id " "$source_iotests/group" >/dev/null
977
- then
978
- # in group file ... OK
979
- echo $id >>$tmp.list
980
- else
981
- if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null
982
- then
983
- # expunged ... will be reported, but not run, later
984
- echo $id >>$tmp.list
985
- else
986
- # oops
987
- if [ "$start" == "$end" -a "$id" == "$end" ]
988
- then
989
- echo "$id - unknown test"
990
- exit 1
991
- else
992
- echo "$id - unknown test, ignored"
993
- fi
994
- fi
995
- fi
996
- done || exit 1
997
- fi
998
-
999
-done
1000
-
1001
-# Set qemu-io cache mode with $CACHEMODE we have
1002
-QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
1003
-
1004
-QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
1005
-if [ "$IMGOPTSSYNTAX" != "true" ]; then
1006
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
1007
-fi
1008
-
1009
-# Set default options for qemu-img create -o if they were not specified
1010
-if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
1011
- IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
1012
-fi
1013
-if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
1014
- IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
1015
-fi
1016
-
1017
-if [ -z "$SAMPLE_IMG_DIR" ]; then
1018
- SAMPLE_IMG_DIR="$source_iotests/sample_images"
1019
-fi
1020
-
1021
-export TEST_DIR
1022
-export SAMPLE_IMG_DIR
1023
-
1024
-if [ -s $tmp.list ]
1025
-then
1026
- # found some valid test numbers ... this is good
1027
- :
1028
-else
1029
- if $have_test_arg
1030
- then
1031
- # had test numbers, but none in group file ... do nothing
1032
- touch $tmp.list
1033
- else
1034
- # no test numbers, do everything from group file
1035
- sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <"$source_iotests/group" >$tmp.list
1036
- fi
1037
-fi
1038
-
1039
-# should be sort -n, but this did not work for Linux when this
1040
-# was ported from IRIX
1041
-#
1042
-list=`sort $tmp.list`
1043
-rm -f $tmp.list $tmp.tmp $tmp.sed
1044
-
1045
-if [ -z "$QEMU_PROG" ]
1046
-then
1047
- if [ -x "$build_iotests/qemu" ]; then
1048
- export QEMU_PROG="$build_iotests/qemu"
1049
- elif [ -x "$build_root/$arch-softmmu/qemu-system-$arch" ]; then
1050
- export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
1051
- else
1052
- pushd "$build_root" > /dev/null
1053
- for binary in *-softmmu/qemu-system-*
1054
- do
1055
- if [ -x "$binary" ]
1056
- then
1057
- export QEMU_PROG="$build_root/$binary"
1058
- break
1059
- fi
1060
- done
1061
- popd > /dev/null
1062
- [ "$QEMU_PROG" = "" ] && _init_error "qemu not found"
1063
- fi
1064
-fi
1065
-export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
1066
-
1067
-if [ -z "$QEMU_IMG_PROG" ]; then
1068
- if [ -x "$build_iotests/qemu-img" ]; then
1069
- export QEMU_IMG_PROG="$build_iotests/qemu-img"
1070
- elif [ -x "$build_root/qemu-img" ]; then
1071
- export QEMU_IMG_PROG="$build_root/qemu-img"
1072
- else
1073
- _init_error "qemu-img not found"
1074
- fi
1075
-fi
1076
-export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
1077
-
1078
-if [ -z "$QEMU_IO_PROG" ]; then
1079
- if [ -x "$build_iotests/qemu-io" ]; then
1080
- export QEMU_IO_PROG="$build_iotests/qemu-io"
1081
- elif [ -x "$build_root/qemu-io" ]; then
1082
- export QEMU_IO_PROG="$build_root/qemu-io"
1083
- else
1084
- _init_error "qemu-io not found"
1085
- fi
1086
-fi
1087
-export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
1088
-
1089
-if [ -z $QEMU_NBD_PROG ]; then
1090
- if [ -x "$build_iotests/qemu-nbd" ]; then
1091
- export QEMU_NBD_PROG="$build_iotests/qemu-nbd"
1092
- elif [ -x "$build_root/qemu-nbd" ]; then
1093
- export QEMU_NBD_PROG="$build_root/qemu-nbd"
1094
- else
1095
- _init_error "qemu-nbd not found"
1096
- fi
1097
-fi
1098
-export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
1099
-
1100
-if [ -z "$QEMU_VXHS_PROG" ]; then
1101
- export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
1102
-fi
1103
-
1104
-if [ -x "$build_iotests/socket_scm_helper" ]
1105
-then
1106
- export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
1107
-fi
1108
-
1109
-default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
1110
-default_alias_machine=$($QEMU_PROG -machine help | \
1111
- sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
1112
-if [[ "$default_alias_machine" ]]; then
1113
- default_machine="$default_alias_machine"
1114
-fi
1115
-
1116
-export QEMU_DEFAULT_MACHINE="$default_machine"
1117
--
393
--
1118
2.13.6
394
2.29.2
1119
395
1120
396
diff view generated by jsdifflib
Deleted patch
1
QMP responses to certain commands can become quite long, which doesn't
2
only make reading them hard, but also means that the maximum line length
3
in patch emails can be exceeded. Allow tests to switch to QMP pretty
4
printing, which results in more, but shorter lines.
5
1
6
We also need to make sure to keep indentation in the response for this
7
to work as expected.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
12
tests/qemu-iotests/common.qemu | 14 +++++++++++---
13
1 file changed, 11 insertions(+), 3 deletions(-)
14
15
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
16
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/common.qemu
18
+++ b/tests/qemu-iotests/common.qemu
19
@@ -XXX,XX +XXX,XX @@ function _timed_wait_for()
20
shift
21
22
QEMU_STATUS[$h]=0
23
- while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
24
+ while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
25
do
26
if [ -z "${silent}" ]; then
27
echo "${resp}" | _filter_testdir | _filter_qemu \
28
| _filter_qemu_io | _filter_qmp | _filter_hmp
29
fi
30
- grep -q "${*}" < <(echo ${resp})
31
+ grep -q "${*}" < <(echo "${resp}")
32
if [ $? -eq 0 ]; then
33
return
34
fi
35
@@ -XXX,XX +XXX,XX @@ function _send_qemu_cmd()
36
# $qemu_comm_method: set this variable to 'monitor' (case insensitive)
37
# to use the QEMU HMP monitor for communication.
38
# Otherwise, the default of QMP is used.
39
+# $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing.
40
# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr.
41
# If this variable is empty, stderr will be redirected to stdout.
42
# Returns:
43
@@ -XXX,XX +XXX,XX @@ function _launch_qemu()
44
comm="-monitor stdio"
45
else
46
local qemu_comm_method="qmp"
47
- comm="-monitor none -qmp stdio"
48
+ if [ "$qmp_pretty" = "y" ]; then
49
+ comm="-monitor none -qmp-pretty stdio"
50
+ else
51
+ comm="-monitor none -qmp stdio"
52
+ fi
53
fi
54
55
fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE}
56
@@ -XXX,XX +XXX,XX @@ function _launch_qemu()
57
then
58
# Don't print response, since it has version information in it
59
silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities"
60
+ if [ "$qmp_pretty" = "y" ]; then
61
+ silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}"
62
+ fi
63
fi
64
QEMU_HANDLE=${_QEMU_HANDLE}
65
let _QEMU_HANDLE++
66
--
67
2.13.6
68
69
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Make it possible to inject errors on writes performed during a
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
read operation due to copy-on-read semantics.
4
Message-Id: <20210224104707.88430-6-vsementsov@virtuozzo.com>
5
5
Reviewed-by: Denis V. Lunev <den@openvz.org>
6
Signed-off-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
7
---
13
qapi/block-core.json | 5 ++++-
8
tests/qemu-iotests/iotests.py | 10 ++++++++++
14
block/io.c | 1 +
9
1 file changed, 10 insertions(+)
15
2 files changed, 5 insertions(+), 1 deletion(-)
16
10
17
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
18
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/block-core.json
13
--- a/tests/qemu-iotests/iotests.py
20
+++ b/qapi/block-core.json
14
+++ b/tests/qemu-iotests/iotests.py
21
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@
22
#
16
#
23
# @l1_shrink_free_l2_clusters: discard the l2 tables. (since 2.11)
17
24
#
18
import atexit
25
+# @cor_write: a write due to copy-on-read (since 2.11)
19
+import bz2
26
+#
20
from collections import OrderedDict
27
# Since: 2.9
21
import faulthandler
28
##
22
import io
29
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
30
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
31
'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
24
import logging
32
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
25
import os
33
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
26
import re
34
- 'l1_shrink_write_table', 'l1_shrink_free_l2_clusters' ] }
27
+import shutil
35
+ 'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
28
import signal
36
+ 'cor_write'] }
29
import struct
37
30
import subprocess
38
##
31
@@ -XXX,XX +XXX,XX @@
39
# @BlkdebugInjectErrorOptions:
32
os.environ.get('IMGKEYSECRET', '')
40
diff --git a/block/io.c b/block/io.c
33
luks_default_key_secret_opt = 'key-secret=keysec0'
41
index XXXXXXX..XXXXXXX 100644
34
42
--- a/block/io.c
35
+sample_img_dir = os.environ['SAMPLE_IMG_DIR']
43
+++ b/block/io.c
36
+
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
37
+
45
goto err;
38
+def unarchive_sample_image(sample, fname):
46
}
39
+ sample_fname = os.path.join(sample_img_dir, sample + '.bz2')
47
40
+ with bz2.open(sample_fname) as f_in, open(fname, 'wb') as f_out:
48
+ bdrv_debug_event(bs, BLKDBG_COR_WRITE);
41
+ shutil.copyfileobj(f_in, f_out)
49
if (drv->bdrv_co_pwrite_zeroes &&
42
+
50
buffer_is_zero(bounce_buffer, iov.iov_len)) {
43
51
/* FIXME: Should we (perhaps conditionally) be setting
44
def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
45
connect_stderr: bool = True) -> Tuple[str, int]:
52
--
46
--
53
2.13.6
47
2.29.2
54
48
55
49
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Test support for reading bitmap from parallels image format.
4
parallels-with-bitmap.bz2 is generated on Virtuozzo by
5
parallels-with-bitmap.sh
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20210224104707.88430-7-vsementsov@virtuozzo.com>
9
Reviewed-by: Denis V. Lunev <den@openvz.org>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
11
---
3
tests/qemu-iotests/191 | 153 +++++++++
12
.../sample_images/parallels-with-bitmap.bz2 | Bin 0 -> 203 bytes
4
tests/qemu-iotests/191.out | 827 +++++++++++++++++++++++++++++++++++++++++++++
13
.../sample_images/parallels-with-bitmap.sh | 51 ++++++++++++++++
5
tests/qemu-iotests/group | 1 +
14
.../qemu-iotests/tests/parallels-read-bitmap | 55 ++++++++++++++++++
6
3 files changed, 981 insertions(+)
15
.../tests/parallels-read-bitmap.out | 6 ++
7
create mode 100755 tests/qemu-iotests/191
16
4 files changed, 112 insertions(+)
8
create mode 100644 tests/qemu-iotests/191.out
17
create mode 100644 tests/qemu-iotests/sample_images/parallels-with-bitmap.bz2
18
create mode 100755 tests/qemu-iotests/sample_images/parallels-with-bitmap.sh
19
create mode 100755 tests/qemu-iotests/tests/parallels-read-bitmap
20
create mode 100644 tests/qemu-iotests/tests/parallels-read-bitmap.out
9
21
10
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
22
diff --git a/tests/qemu-iotests/sample_images/parallels-with-bitmap.bz2 b/tests/qemu-iotests/sample_images/parallels-with-bitmap.bz2
23
new file mode 100644
24
index XXXXXXX..XXXXXXX
25
GIT binary patch
26
literal 203
27
zcmV;+05tzXT4*^jL0KkKS@=;0bpT+Hf7|^?Km<xfFyKQJ7=Y^F-%vt;00~Ysa6|-=
28
zk&7Szk`SoS002EkfMftPG<ipnsiCK}K_sNmm}me3FiZr%Oaf_u5F8kD;mB_~cxD-r
29
z5P$(X{&Tq5C`<xK02D?NNdN+t$~z$m00O|zFh^ynq*yaCtkn+NZzWom<#OEoF`?zb
30
zv(i3x^K~wt!aLPcRBP+PckUsIh6*LgjYSh0`}#7hMC9NR5D)+W0d&8Mxgwk>NPH-R
31
Fx`3oHQ9u9y
32
33
literal 0
34
HcmV?d00001
35
36
diff --git a/tests/qemu-iotests/sample_images/parallels-with-bitmap.sh b/tests/qemu-iotests/sample_images/parallels-with-bitmap.sh
11
new file mode 100755
37
new file mode 100755
12
index XXXXXXX..XXXXXXX
38
index XXXXXXX..XXXXXXX
13
--- /dev/null
39
--- /dev/null
14
+++ b/tests/qemu-iotests/191
40
+++ b/tests/qemu-iotests/sample_images/parallels-with-bitmap.sh
15
@@ -XXX,XX +XXX,XX @@
41
@@ -XXX,XX +XXX,XX @@
16
+#!/bin/bash
42
+#!/bin/bash
17
+#
43
+#
18
+# Test commit block job where top has two parents
44
+# Test parallels load bitmap
19
+#
45
+#
20
+# Copyright (C) 2017 Red Hat, Inc.
46
+# Copyright (c) 2021 Virtuozzo International GmbH.
21
+#
47
+#
22
+# This program is free software; you can redistribute it and/or modify
48
+# This program is free software; you can redistribute it and/or modify
23
+# it under the terms of the GNU General Public License as published by
49
+# it under the terms of the GNU General Public License as published by
24
+# the Free Software Foundation; either version 2 of the License, or
50
+# the Free Software Foundation; either version 2 of the License, or
25
+# (at your option) any later version.
51
+# (at your option) any later version.
...
...
31
+#
57
+#
32
+# You should have received a copy of the GNU General Public License
58
+# You should have received a copy of the GNU General Public License
33
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
59
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
34
+#
60
+#
35
+
61
+
36
+# creator
62
+CT=parallels-with-bitmap-ct
37
+owner=kwolf@redhat.com
63
+DIR=$PWD/parallels-with-bitmap-dir
64
+IMG=$DIR/root.hds
65
+XML=$DIR/DiskDescriptor.xml
66
+TARGET=parallels-with-bitmap.bz2
38
+
67
+
39
+seq=`basename $0`
68
+rm -rf $DIR
40
+echo "QA output created by $seq"
41
+
69
+
42
+here=`pwd`
70
+prlctl create $CT --vmtype ct
43
+status=1 # failure is the default!
71
+prlctl set $CT --device-add hdd --image $DIR --recreate --size 2G
44
+
72
+
45
+MIG_SOCKET="${TEST_DIR}/migrate"
73
+# cleanup the image
74
+qemu-img create -f parallels $IMG 64G
46
+
75
+
47
+_cleanup()
76
+# create bitmap
48
+{
77
+prlctl backup $CT
49
+ rm -f "${TEST_IMG}.mid"
50
+ rm -f "${TEST_IMG}.ovl2"
51
+ rm -f "${TEST_IMG}.ovl3"
52
+ _cleanup_test_img
53
+ _cleanup_qemu
54
+}
55
+trap "_cleanup; exit \$status" 0 1 2 3 15
56
+
78
+
57
+# get standard environment, filters and checks
79
+prlctl set $CT --device-del hdd1
58
+. ./common.rc
80
+prlctl destroy $CT
59
+. ./common.filter
60
+. ./common.qemu
61
+
81
+
62
+_supported_fmt qcow2
82
+dev=$(ploop mount $XML | sed -n 's/^Adding delta dev=\(\/dev\/ploop[0-9]\+\).*/\1/p')
63
+_unsupported_imgopts compat=0.10
83
+dd if=/dev/zero of=$dev bs=64K seek=5 count=2 oflag=direct
64
+_supported_proto file
84
+dd if=/dev/zero of=$dev bs=64K seek=30 count=1 oflag=direct
65
+_supported_os Linux
85
+dd if=/dev/zero of=$dev bs=64K seek=10 count=3 oflag=direct
86
+ploop umount $XML # bitmap name will be in the output
66
+
87
+
67
+size=64M
88
+bzip2 -z $IMG
68
+
89
+
69
+echo
90
+mv $IMG.bz2 $TARGET
70
+echo === Preparing and starting VM ===
71
+echo
72
+
91
+
73
+TEST_IMG="${TEST_IMG}.base" _make_test_img $size
92
+rm -rf $DIR
74
+TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
93
diff --git a/tests/qemu-iotests/tests/parallels-read-bitmap b/tests/qemu-iotests/tests/parallels-read-bitmap
75
+_make_test_img -b "${TEST_IMG}.mid"
94
new file mode 100755
76
+TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
95
index XXXXXXX..XXXXXXX
96
--- /dev/null
97
+++ b/tests/qemu-iotests/tests/parallels-read-bitmap
98
@@ -XXX,XX +XXX,XX @@
99
+#!/usr/bin/env python3
100
+#
101
+# Test parallels load bitmap
102
+#
103
+# Copyright (c) 2021 Virtuozzo International GmbH.
104
+#
105
+# This program is free software; you can redistribute it and/or modify
106
+# it under the terms of the GNU General Public License as published by
107
+# the Free Software Foundation; either version 2 of the License, or
108
+# (at your option) any later version.
109
+#
110
+# This program is distributed in the hope that it will be useful,
111
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
112
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
113
+# GNU General Public License for more details.
114
+#
115
+# You should have received a copy of the GNU General Public License
116
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
117
+#
77
+
118
+
78
+$QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io
119
+import json
120
+import iotests
121
+from iotests import qemu_nbd_popen, qemu_img_pipe, log, file_path
79
+
122
+
80
+qemu_comm_method="qmp"
123
+iotests.script_initialize(supported_fmts=['parallels'])
81
+qmp_pretty="y"
82
+
124
+
83
+_launch_qemu \
125
+nbd_sock = file_path('nbd-sock', base_dir=iotests.sock_dir)
84
+ -blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.base,node-name=base" \
126
+disk = iotests.file_path('disk')
85
+ -blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.mid,node-name=mid,backing=base" \
127
+bitmap = 'e4f2eed0-37fe-4539-b50b-85d2e7fd235f'
86
+ -blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG},node-name=top,backing=mid" \
128
+nbd_opts = f'driver=nbd,server.type=unix,server.path={nbd_sock}' \
87
+ -blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.ovl2,node-name=top2,backing=mid"
129
+ f',x-dirty-bitmap=qemu:dirty-bitmap:{bitmap}'
88
+h=$QEMU_HANDLE
89
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" '^}'
90
+
91
+echo
92
+echo === Perform commit job ===
93
+echo
94
+
95
+_send_qemu_cmd $h \
96
+ "{ 'execute': 'block-commit',
97
+ 'arguments': { 'job-id': 'commit0',
98
+ 'device': 'top',
99
+ 'base':'$TEST_IMG.base',
100
+ 'top': '$TEST_IMG.mid' } }" \
101
+ "BLOCK_JOB_COMPLETED"
102
+_send_qemu_cmd $h "" "^}"
103
+
104
+echo
105
+echo === Check that both top and top2 point to base now ===
106
+echo
107
+
108
+_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
109
+ _filter_generated_node_ids
110
+
111
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
112
+wait=1 _cleanup_qemu
113
+
114
+_img_info
115
+TEST_IMG="$TEST_IMG.ovl2" _img_info
116
+
130
+
117
+
131
+
118
+echo
132
+iotests.unarchive_sample_image('parallels-with-bitmap', disk)
119
+echo === Preparing and starting VM with -drive ===
120
+echo
121
+
133
+
122
+TEST_IMG="${TEST_IMG}.base" _make_test_img $size
123
+TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
124
+_make_test_img -b "${TEST_IMG}.mid"
125
+TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
126
+TEST_IMG="${TEST_IMG}.ovl3" _make_test_img -b "${TEST_IMG}.ovl2"
127
+
134
+
128
+$QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io
135
+with qemu_nbd_popen('--read-only', f'--socket={nbd_sock}',
136
+ f'--bitmap={bitmap}', '-f', iotests.imgfmt, disk):
137
+ out = qemu_img_pipe('map', '--output=json', '--image-opts', nbd_opts)
138
+ chunks = json.loads(out)
139
+ cluster = 64 * 1024
129
+
140
+
130
+qemu_comm_method="qmp"
141
+ log('dirty clusters (cluster size is 64K):')
131
+qmp_pretty="y"
142
+ for c in chunks:
143
+ assert c['start'] % cluster == 0
144
+ assert c['length'] % cluster == 0
145
+ if c['data']:
146
+ continue
132
+
147
+
133
+_launch_qemu \
148
+ a = c['start'] // cluster
134
+ -drive "driver=${IMGFMT},file=${TEST_IMG},node-name=top,backing.node-name=mid" \
149
+ b = (c['start'] + c['length']) // cluster
135
+ -drive "driver=${IMGFMT},file=${TEST_IMG}.ovl3,node-name=top2,backing.backing=mid"
150
+ if b - a > 1:
136
+h=$QEMU_HANDLE
151
+ log(f'{a}-{b-1}')
137
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" '^}'
152
+ else:
138
+
153
+ log(a)
139
+echo
154
diff --git a/tests/qemu-iotests/tests/parallels-read-bitmap.out b/tests/qemu-iotests/tests/parallels-read-bitmap.out
140
+echo === Perform commit job ===
141
+echo
142
+
143
+_send_qemu_cmd $h \
144
+ "{ 'execute': 'block-commit',
145
+ 'arguments': { 'job-id': 'commit0',
146
+ 'device': 'top',
147
+ 'base':'$TEST_IMG.base',
148
+ 'top': '$TEST_IMG.mid' } }" \
149
+ "BLOCK_JOB_COMPLETED"
150
+_send_qemu_cmd $h "" "^}"
151
+
152
+echo
153
+echo === Check that both top and top2 point to base now ===
154
+echo
155
+
156
+_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
157
+ _filter_generated_node_ids
158
+
159
+_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
160
+wait=1 _cleanup_qemu
161
+
162
+_img_info
163
+TEST_IMG="$TEST_IMG.ovl2" _img_info
164
+
165
+# success, all done
166
+echo "*** done"
167
+rm -f $seq.full
168
+status=0
169
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
170
new file mode 100644
155
new file mode 100644
171
index XXXXXXX..XXXXXXX
156
index XXXXXXX..XXXXXXX
172
--- /dev/null
157
--- /dev/null
173
+++ b/tests/qemu-iotests/191.out
158
+++ b/tests/qemu-iotests/tests/parallels-read-bitmap.out
174
@@ -XXX,XX +XXX,XX @@
159
@@ -XXX,XX +XXX,XX @@
175
+QA output created by 191
160
+Start NBD server
176
+
161
+dirty clusters (cluster size is 64K):
177
+=== Preparing and starting VM ===
162
+5-6
178
+
163
+10-12
179
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
164
+30
180
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
165
+Kill NBD server
181
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
182
+Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
183
+wrote 65536/65536 bytes at offset 1048576
184
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
185
+{
186
+ "return": {
187
+ }
188
+}
189
+
190
+=== Perform commit job ===
191
+
192
+{
193
+ "return": {
194
+ }
195
+}
196
+{
197
+ "timestamp": {
198
+ "seconds": TIMESTAMP,
199
+ "microseconds": TIMESTAMP
200
+ },
201
+ "event": "BLOCK_JOB_COMPLETED",
202
+ "data": {
203
+ "device": "commit0",
204
+ "len": 67108864,
205
+ "offset": 67108864,
206
+ "speed": 0,
207
+ "type": "commit"
208
+ }
209
+}
210
+
211
+=== Check that both top and top2 point to base now ===
212
+
213
+{
214
+ "return": [
215
+ {
216
+ "iops_rd": 0,
217
+ "detect_zeroes": "off",
218
+ "image": {
219
+ "backing-image": {
220
+ "virtual-size": 67108864,
221
+ "filename": "TEST_DIR/t.qcow2.base",
222
+ "cluster-size": 65536,
223
+ "format": "qcow2",
224
+ "actual-size": 397312,
225
+ "format-specific": {
226
+ "type": "qcow2",
227
+ "data": {
228
+ "compat": "1.1",
229
+ "lazy-refcounts": false,
230
+ "refcount-bits": 16,
231
+ "corrupt": false
232
+ }
233
+ },
234
+ "dirty-flag": false
235
+ },
236
+ "backing-filename-format": "qcow2",
237
+ "virtual-size": 67108864,
238
+ "filename": "TEST_DIR/t.qcow2.ovl2",
239
+ "cluster-size": 65536,
240
+ "format": "qcow2",
241
+ "actual-size": 200704,
242
+ "format-specific": {
243
+ "type": "qcow2",
244
+ "data": {
245
+ "compat": "1.1",
246
+ "lazy-refcounts": false,
247
+ "refcount-bits": 16,
248
+ "corrupt": false
249
+ }
250
+ },
251
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
252
+ "backing-filename": "TEST_DIR/t.qcow2.base",
253
+ "dirty-flag": false
254
+ },
255
+ "iops_wr": 0,
256
+ "ro": false,
257
+ "node-name": "top2",
258
+ "backing_file_depth": 1,
259
+ "drv": "qcow2",
260
+ "iops": 0,
261
+ "bps_wr": 0,
262
+ "write_threshold": 0,
263
+ "backing_file": "TEST_DIR/t.qcow2.base",
264
+ "encrypted": false,
265
+ "bps": 0,
266
+ "bps_rd": 0,
267
+ "cache": {
268
+ "no-flush": false,
269
+ "direct": false,
270
+ "writeback": true
271
+ },
272
+ "file": "TEST_DIR/t.qcow2.ovl2",
273
+ "encryption_key_missing": false
274
+ },
275
+ {
276
+ "iops_rd": 0,
277
+ "detect_zeroes": "off",
278
+ "image": {
279
+ "virtual-size": 197120,
280
+ "filename": "TEST_DIR/t.qcow2.ovl2",
281
+ "format": "file",
282
+ "actual-size": 200704,
283
+ "dirty-flag": false
284
+ },
285
+ "iops_wr": 0,
286
+ "ro": false,
287
+ "node-name": "NODE_NAME",
288
+ "backing_file_depth": 0,
289
+ "drv": "file",
290
+ "iops": 0,
291
+ "bps_wr": 0,
292
+ "write_threshold": 0,
293
+ "encrypted": false,
294
+ "bps": 0,
295
+ "bps_rd": 0,
296
+ "cache": {
297
+ "no-flush": false,
298
+ "direct": false,
299
+ "writeback": true
300
+ },
301
+ "file": "TEST_DIR/t.qcow2.ovl2",
302
+ "encryption_key_missing": false
303
+ },
304
+ {
305
+ "iops_rd": 0,
306
+ "detect_zeroes": "off",
307
+ "image": {
308
+ "backing-image": {
309
+ "virtual-size": 67108864,
310
+ "filename": "TEST_DIR/t.qcow2.base",
311
+ "cluster-size": 65536,
312
+ "format": "qcow2",
313
+ "actual-size": 397312,
314
+ "format-specific": {
315
+ "type": "qcow2",
316
+ "data": {
317
+ "compat": "1.1",
318
+ "lazy-refcounts": false,
319
+ "refcount-bits": 16,
320
+ "corrupt": false
321
+ }
322
+ },
323
+ "dirty-flag": false
324
+ },
325
+ "backing-filename-format": "qcow2",
326
+ "virtual-size": 67108864,
327
+ "filename": "TEST_DIR/t.qcow2",
328
+ "cluster-size": 65536,
329
+ "format": "qcow2",
330
+ "actual-size": 200704,
331
+ "format-specific": {
332
+ "type": "qcow2",
333
+ "data": {
334
+ "compat": "1.1",
335
+ "lazy-refcounts": false,
336
+ "refcount-bits": 16,
337
+ "corrupt": false
338
+ }
339
+ },
340
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
341
+ "backing-filename": "TEST_DIR/t.qcow2.base",
342
+ "dirty-flag": false
343
+ },
344
+ "iops_wr": 0,
345
+ "ro": false,
346
+ "node-name": "top",
347
+ "backing_file_depth": 1,
348
+ "drv": "qcow2",
349
+ "iops": 0,
350
+ "bps_wr": 0,
351
+ "write_threshold": 0,
352
+ "backing_file": "TEST_DIR/t.qcow2.base",
353
+ "encrypted": false,
354
+ "bps": 0,
355
+ "bps_rd": 0,
356
+ "cache": {
357
+ "no-flush": false,
358
+ "direct": false,
359
+ "writeback": true
360
+ },
361
+ "file": "TEST_DIR/t.qcow2",
362
+ "encryption_key_missing": false
363
+ },
364
+ {
365
+ "iops_rd": 0,
366
+ "detect_zeroes": "off",
367
+ "image": {
368
+ "virtual-size": 197120,
369
+ "filename": "TEST_DIR/t.qcow2",
370
+ "format": "file",
371
+ "actual-size": 200704,
372
+ "dirty-flag": false
373
+ },
374
+ "iops_wr": 0,
375
+ "ro": false,
376
+ "node-name": "NODE_NAME",
377
+ "backing_file_depth": 0,
378
+ "drv": "file",
379
+ "iops": 0,
380
+ "bps_wr": 0,
381
+ "write_threshold": 0,
382
+ "encrypted": false,
383
+ "bps": 0,
384
+ "bps_rd": 0,
385
+ "cache": {
386
+ "no-flush": false,
387
+ "direct": false,
388
+ "writeback": true
389
+ },
390
+ "file": "TEST_DIR/t.qcow2",
391
+ "encryption_key_missing": false
392
+ },
393
+ {
394
+ "iops_rd": 0,
395
+ "detect_zeroes": "off",
396
+ "image": {
397
+ "backing-image": {
398
+ "virtual-size": 67108864,
399
+ "filename": "TEST_DIR/t.qcow2.base",
400
+ "cluster-size": 65536,
401
+ "format": "qcow2",
402
+ "actual-size": 397312,
403
+ "format-specific": {
404
+ "type": "qcow2",
405
+ "data": {
406
+ "compat": "1.1",
407
+ "lazy-refcounts": false,
408
+ "refcount-bits": 16,
409
+ "corrupt": false
410
+ }
411
+ },
412
+ "dirty-flag": false
413
+ },
414
+ "backing-filename-format": "qcow2",
415
+ "virtual-size": 67108864,
416
+ "filename": "TEST_DIR/t.qcow2.mid",
417
+ "cluster-size": 65536,
418
+ "format": "qcow2",
419
+ "actual-size": 397312,
420
+ "format-specific": {
421
+ "type": "qcow2",
422
+ "data": {
423
+ "compat": "1.1",
424
+ "lazy-refcounts": false,
425
+ "refcount-bits": 16,
426
+ "corrupt": false
427
+ }
428
+ },
429
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
430
+ "backing-filename": "TEST_DIR/t.qcow2.base",
431
+ "dirty-flag": false
432
+ },
433
+ "iops_wr": 0,
434
+ "ro": false,
435
+ "node-name": "mid",
436
+ "backing_file_depth": 1,
437
+ "drv": "qcow2",
438
+ "iops": 0,
439
+ "bps_wr": 0,
440
+ "write_threshold": 0,
441
+ "backing_file": "TEST_DIR/t.qcow2.base",
442
+ "encrypted": false,
443
+ "bps": 0,
444
+ "bps_rd": 0,
445
+ "cache": {
446
+ "no-flush": false,
447
+ "direct": false,
448
+ "writeback": true
449
+ },
450
+ "file": "TEST_DIR/t.qcow2.mid",
451
+ "encryption_key_missing": false
452
+ },
453
+ {
454
+ "iops_rd": 0,
455
+ "detect_zeroes": "off",
456
+ "image": {
457
+ "virtual-size": 393216,
458
+ "filename": "TEST_DIR/t.qcow2.mid",
459
+ "format": "file",
460
+ "actual-size": 397312,
461
+ "dirty-flag": false
462
+ },
463
+ "iops_wr": 0,
464
+ "ro": false,
465
+ "node-name": "NODE_NAME",
466
+ "backing_file_depth": 0,
467
+ "drv": "file",
468
+ "iops": 0,
469
+ "bps_wr": 0,
470
+ "write_threshold": 0,
471
+ "encrypted": false,
472
+ "bps": 0,
473
+ "bps_rd": 0,
474
+ "cache": {
475
+ "no-flush": false,
476
+ "direct": false,
477
+ "writeback": true
478
+ },
479
+ "file": "TEST_DIR/t.qcow2.mid",
480
+ "encryption_key_missing": false
481
+ },
482
+ {
483
+ "iops_rd": 0,
484
+ "detect_zeroes": "off",
485
+ "image": {
486
+ "virtual-size": 67108864,
487
+ "filename": "TEST_DIR/t.qcow2.base",
488
+ "cluster-size": 65536,
489
+ "format": "qcow2",
490
+ "actual-size": 397312,
491
+ "format-specific": {
492
+ "type": "qcow2",
493
+ "data": {
494
+ "compat": "1.1",
495
+ "lazy-refcounts": false,
496
+ "refcount-bits": 16,
497
+ "corrupt": false
498
+ }
499
+ },
500
+ "dirty-flag": false
501
+ },
502
+ "iops_wr": 0,
503
+ "ro": false,
504
+ "node-name": "base",
505
+ "backing_file_depth": 0,
506
+ "drv": "qcow2",
507
+ "iops": 0,
508
+ "bps_wr": 0,
509
+ "write_threshold": 0,
510
+ "encrypted": false,
511
+ "bps": 0,
512
+ "bps_rd": 0,
513
+ "cache": {
514
+ "no-flush": false,
515
+ "direct": false,
516
+ "writeback": true
517
+ },
518
+ "file": "TEST_DIR/t.qcow2.base",
519
+ "encryption_key_missing": false
520
+ },
521
+ {
522
+ "iops_rd": 0,
523
+ "detect_zeroes": "off",
524
+ "image": {
525
+ "virtual-size": 393216,
526
+ "filename": "TEST_DIR/t.qcow2.base",
527
+ "format": "file",
528
+ "actual-size": 397312,
529
+ "dirty-flag": false
530
+ },
531
+ "iops_wr": 0,
532
+ "ro": false,
533
+ "node-name": "NODE_NAME",
534
+ "backing_file_depth": 0,
535
+ "drv": "file",
536
+ "iops": 0,
537
+ "bps_wr": 0,
538
+ "write_threshold": 0,
539
+ "encrypted": false,
540
+ "bps": 0,
541
+ "bps_rd": 0,
542
+ "cache": {
543
+ "no-flush": false,
544
+ "direct": false,
545
+ "writeback": true
546
+ },
547
+ "file": "TEST_DIR/t.qcow2.base",
548
+ "encryption_key_missing": false
549
+ }
550
+ ]
551
+}
552
+{
553
+ "return": {
554
+ }
555
+}
556
+{
557
+ "timestamp": {
558
+ "seconds": TIMESTAMP,
559
+ "microseconds": TIMESTAMP
560
+ },
561
+ "event": "SHUTDOWN",
562
+ "data": {
563
+ "guest": false
564
+ }
565
+}
566
+image: TEST_DIR/t.IMGFMT
567
+file format: IMGFMT
568
+virtual size: 64M (67108864 bytes)
569
+cluster_size: 65536
570
+backing file: TEST_DIR/t.IMGFMT.base
571
+backing file format: IMGFMT
572
+image: TEST_DIR/t.IMGFMT.ovl2
573
+file format: IMGFMT
574
+virtual size: 64M (67108864 bytes)
575
+cluster_size: 65536
576
+backing file: TEST_DIR/t.IMGFMT.base
577
+backing file format: IMGFMT
578
+
579
+=== Preparing and starting VM with -drive ===
580
+
581
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
582
+Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
583
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
584
+Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
585
+Formatting 'TEST_DIR/t.IMGFMT.ovl3', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.ovl2
586
+wrote 65536/65536 bytes at offset 1048576
587
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
588
+{
589
+ "return": {
590
+ }
591
+}
592
+
593
+=== Perform commit job ===
594
+
595
+{
596
+ "return": {
597
+ }
598
+}
599
+{
600
+ "timestamp": {
601
+ "seconds": TIMESTAMP,
602
+ "microseconds": TIMESTAMP
603
+ },
604
+ "event": "BLOCK_JOB_COMPLETED",
605
+ "data": {
606
+ "device": "commit0",
607
+ "len": 67108864,
608
+ "offset": 67108864,
609
+ "speed": 0,
610
+ "type": "commit"
611
+ }
612
+}
613
+
614
+=== Check that both top and top2 point to base now ===
615
+
616
+{
617
+ "return": [
618
+ {
619
+ "iops_rd": 0,
620
+ "detect_zeroes": "off",
621
+ "image": {
622
+ "backing-image": {
623
+ "virtual-size": 67108864,
624
+ "filename": "TEST_DIR/t.qcow2.base",
625
+ "cluster-size": 65536,
626
+ "format": "qcow2",
627
+ "actual-size": 397312,
628
+ "format-specific": {
629
+ "type": "qcow2",
630
+ "data": {
631
+ "compat": "1.1",
632
+ "lazy-refcounts": false,
633
+ "refcount-bits": 16,
634
+ "corrupt": false
635
+ }
636
+ },
637
+ "dirty-flag": false
638
+ },
639
+ "backing-filename-format": "qcow2",
640
+ "virtual-size": 67108864,
641
+ "filename": "TEST_DIR/t.qcow2.ovl2",
642
+ "cluster-size": 65536,
643
+ "format": "qcow2",
644
+ "actual-size": 200704,
645
+ "format-specific": {
646
+ "type": "qcow2",
647
+ "data": {
648
+ "compat": "1.1",
649
+ "lazy-refcounts": false,
650
+ "refcount-bits": 16,
651
+ "corrupt": false
652
+ }
653
+ },
654
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
655
+ "backing-filename": "TEST_DIR/t.qcow2.base",
656
+ "dirty-flag": false
657
+ },
658
+ "iops_wr": 0,
659
+ "ro": true,
660
+ "node-name": "NODE_NAME",
661
+ "backing_file_depth": 1,
662
+ "drv": "qcow2",
663
+ "iops": 0,
664
+ "bps_wr": 0,
665
+ "write_threshold": 0,
666
+ "backing_file": "TEST_DIR/t.qcow2.base",
667
+ "encrypted": false,
668
+ "bps": 0,
669
+ "bps_rd": 0,
670
+ "cache": {
671
+ "no-flush": false,
672
+ "direct": false,
673
+ "writeback": true
674
+ },
675
+ "file": "TEST_DIR/t.qcow2.ovl2",
676
+ "encryption_key_missing": false
677
+ },
678
+ {
679
+ "iops_rd": 0,
680
+ "detect_zeroes": "off",
681
+ "image": {
682
+ "virtual-size": 197120,
683
+ "filename": "TEST_DIR/t.qcow2.ovl2",
684
+ "format": "file",
685
+ "actual-size": 200704,
686
+ "dirty-flag": false
687
+ },
688
+ "iops_wr": 0,
689
+ "ro": true,
690
+ "node-name": "NODE_NAME",
691
+ "backing_file_depth": 0,
692
+ "drv": "file",
693
+ "iops": 0,
694
+ "bps_wr": 0,
695
+ "write_threshold": 0,
696
+ "encrypted": false,
697
+ "bps": 0,
698
+ "bps_rd": 0,
699
+ "cache": {
700
+ "no-flush": false,
701
+ "direct": false,
702
+ "writeback": true
703
+ },
704
+ "file": "TEST_DIR/t.qcow2.ovl2",
705
+ "encryption_key_missing": false
706
+ },
707
+ {
708
+ "iops_rd": 0,
709
+ "detect_zeroes": "off",
710
+ "image": {
711
+ "backing-image": {
712
+ "backing-image": {
713
+ "virtual-size": 67108864,
714
+ "filename": "TEST_DIR/t.qcow2.base",
715
+ "cluster-size": 65536,
716
+ "format": "qcow2",
717
+ "actual-size": 397312,
718
+ "format-specific": {
719
+ "type": "qcow2",
720
+ "data": {
721
+ "compat": "1.1",
722
+ "lazy-refcounts": false,
723
+ "refcount-bits": 16,
724
+ "corrupt": false
725
+ }
726
+ },
727
+ "dirty-flag": false
728
+ },
729
+ "backing-filename-format": "qcow2",
730
+ "virtual-size": 67108864,
731
+ "filename": "TEST_DIR/t.qcow2.ovl2",
732
+ "cluster-size": 65536,
733
+ "format": "qcow2",
734
+ "actual-size": 200704,
735
+ "format-specific": {
736
+ "type": "qcow2",
737
+ "data": {
738
+ "compat": "1.1",
739
+ "lazy-refcounts": false,
740
+ "refcount-bits": 16,
741
+ "corrupt": false
742
+ }
743
+ },
744
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
745
+ "backing-filename": "TEST_DIR/t.qcow2.base",
746
+ "dirty-flag": false
747
+ },
748
+ "backing-filename-format": "qcow2",
749
+ "virtual-size": 67108864,
750
+ "filename": "TEST_DIR/t.qcow2.ovl3",
751
+ "cluster-size": 65536,
752
+ "format": "qcow2",
753
+ "actual-size": 200704,
754
+ "format-specific": {
755
+ "type": "qcow2",
756
+ "data": {
757
+ "compat": "1.1",
758
+ "lazy-refcounts": false,
759
+ "refcount-bits": 16,
760
+ "corrupt": false
761
+ }
762
+ },
763
+ "full-backing-filename": "TEST_DIR/t.qcow2.ovl2",
764
+ "backing-filename": "TEST_DIR/t.qcow2.ovl2",
765
+ "dirty-flag": false
766
+ },
767
+ "iops_wr": 0,
768
+ "ro": false,
769
+ "node-name": "top2",
770
+ "backing_file_depth": 2,
771
+ "drv": "qcow2",
772
+ "iops": 0,
773
+ "bps_wr": 0,
774
+ "write_threshold": 0,
775
+ "backing_file": "TEST_DIR/t.qcow2.ovl2",
776
+ "encrypted": false,
777
+ "bps": 0,
778
+ "bps_rd": 0,
779
+ "cache": {
780
+ "no-flush": false,
781
+ "direct": false,
782
+ "writeback": true
783
+ },
784
+ "file": "TEST_DIR/t.qcow2.ovl3",
785
+ "encryption_key_missing": false
786
+ },
787
+ {
788
+ "iops_rd": 0,
789
+ "detect_zeroes": "off",
790
+ "image": {
791
+ "virtual-size": 197120,
792
+ "filename": "TEST_DIR/t.qcow2.ovl3",
793
+ "format": "file",
794
+ "actual-size": 200704,
795
+ "dirty-flag": false
796
+ },
797
+ "iops_wr": 0,
798
+ "ro": false,
799
+ "node-name": "NODE_NAME",
800
+ "backing_file_depth": 0,
801
+ "drv": "file",
802
+ "iops": 0,
803
+ "bps_wr": 0,
804
+ "write_threshold": 0,
805
+ "encrypted": false,
806
+ "bps": 0,
807
+ "bps_rd": 0,
808
+ "cache": {
809
+ "no-flush": false,
810
+ "direct": false,
811
+ "writeback": true
812
+ },
813
+ "file": "TEST_DIR/t.qcow2.ovl3",
814
+ "encryption_key_missing": false
815
+ },
816
+ {
817
+ "iops_rd": 0,
818
+ "detect_zeroes": "off",
819
+ "image": {
820
+ "virtual-size": 67108864,
821
+ "filename": "TEST_DIR/t.qcow2.base",
822
+ "cluster-size": 65536,
823
+ "format": "qcow2",
824
+ "actual-size": 397312,
825
+ "format-specific": {
826
+ "type": "qcow2",
827
+ "data": {
828
+ "compat": "1.1",
829
+ "lazy-refcounts": false,
830
+ "refcount-bits": 16,
831
+ "corrupt": false
832
+ }
833
+ },
834
+ "dirty-flag": false
835
+ },
836
+ "iops_wr": 0,
837
+ "ro": true,
838
+ "node-name": "NODE_NAME",
839
+ "backing_file_depth": 0,
840
+ "drv": "qcow2",
841
+ "iops": 0,
842
+ "bps_wr": 0,
843
+ "write_threshold": 0,
844
+ "encrypted": false,
845
+ "bps": 0,
846
+ "bps_rd": 0,
847
+ "cache": {
848
+ "no-flush": false,
849
+ "direct": false,
850
+ "writeback": true
851
+ },
852
+ "file": "TEST_DIR/t.qcow2.base",
853
+ "encryption_key_missing": false
854
+ },
855
+ {
856
+ "iops_rd": 0,
857
+ "detect_zeroes": "off",
858
+ "image": {
859
+ "virtual-size": 393216,
860
+ "filename": "TEST_DIR/t.qcow2.base",
861
+ "format": "file",
862
+ "actual-size": 397312,
863
+ "dirty-flag": false
864
+ },
865
+ "iops_wr": 0,
866
+ "ro": true,
867
+ "node-name": "NODE_NAME",
868
+ "backing_file_depth": 0,
869
+ "drv": "file",
870
+ "iops": 0,
871
+ "bps_wr": 0,
872
+ "write_threshold": 0,
873
+ "encrypted": false,
874
+ "bps": 0,
875
+ "bps_rd": 0,
876
+ "cache": {
877
+ "no-flush": false,
878
+ "direct": false,
879
+ "writeback": true
880
+ },
881
+ "file": "TEST_DIR/t.qcow2.base",
882
+ "encryption_key_missing": false
883
+ },
884
+ {
885
+ "iops_rd": 0,
886
+ "detect_zeroes": "off",
887
+ "image": {
888
+ "backing-image": {
889
+ "virtual-size": 67108864,
890
+ "filename": "TEST_DIR/t.qcow2.base",
891
+ "cluster-size": 65536,
892
+ "format": "qcow2",
893
+ "actual-size": 397312,
894
+ "format-specific": {
895
+ "type": "qcow2",
896
+ "data": {
897
+ "compat": "1.1",
898
+ "lazy-refcounts": false,
899
+ "refcount-bits": 16,
900
+ "corrupt": false
901
+ }
902
+ },
903
+ "dirty-flag": false
904
+ },
905
+ "backing-filename-format": "qcow2",
906
+ "virtual-size": 67108864,
907
+ "filename": "TEST_DIR/t.qcow2",
908
+ "cluster-size": 65536,
909
+ "format": "qcow2",
910
+ "actual-size": 200704,
911
+ "format-specific": {
912
+ "type": "qcow2",
913
+ "data": {
914
+ "compat": "1.1",
915
+ "lazy-refcounts": false,
916
+ "refcount-bits": 16,
917
+ "corrupt": false
918
+ }
919
+ },
920
+ "full-backing-filename": "TEST_DIR/t.qcow2.base",
921
+ "backing-filename": "TEST_DIR/t.qcow2.base",
922
+ "dirty-flag": false
923
+ },
924
+ "iops_wr": 0,
925
+ "ro": false,
926
+ "node-name": "top",
927
+ "backing_file_depth": 1,
928
+ "drv": "qcow2",
929
+ "iops": 0,
930
+ "bps_wr": 0,
931
+ "write_threshold": 0,
932
+ "backing_file": "TEST_DIR/t.qcow2.base",
933
+ "encrypted": false,
934
+ "bps": 0,
935
+ "bps_rd": 0,
936
+ "cache": {
937
+ "no-flush": false,
938
+ "direct": false,
939
+ "writeback": true
940
+ },
941
+ "file": "TEST_DIR/t.qcow2",
942
+ "encryption_key_missing": false
943
+ },
944
+ {
945
+ "iops_rd": 0,
946
+ "detect_zeroes": "off",
947
+ "image": {
948
+ "virtual-size": 197120,
949
+ "filename": "TEST_DIR/t.qcow2",
950
+ "format": "file",
951
+ "actual-size": 200704,
952
+ "dirty-flag": false
953
+ },
954
+ "iops_wr": 0,
955
+ "ro": false,
956
+ "node-name": "NODE_NAME",
957
+ "backing_file_depth": 0,
958
+ "drv": "file",
959
+ "iops": 0,
960
+ "bps_wr": 0,
961
+ "write_threshold": 0,
962
+ "encrypted": false,
963
+ "bps": 0,
964
+ "bps_rd": 0,
965
+ "cache": {
966
+ "no-flush": false,
967
+ "direct": false,
968
+ "writeback": true
969
+ },
970
+ "file": "TEST_DIR/t.qcow2",
971
+ "encryption_key_missing": false
972
+ }
973
+ ]
974
+}
975
+{
976
+ "return": {
977
+ }
978
+}
979
+{
980
+ "timestamp": {
981
+ "seconds": TIMESTAMP,
982
+ "microseconds": TIMESTAMP
983
+ },
984
+ "event": "SHUTDOWN",
985
+ "data": {
986
+ "guest": false
987
+ }
988
+}
989
+image: TEST_DIR/t.IMGFMT
990
+file format: IMGFMT
991
+virtual size: 64M (67108864 bytes)
992
+cluster_size: 65536
993
+backing file: TEST_DIR/t.IMGFMT.base
994
+backing file format: IMGFMT
995
+image: TEST_DIR/t.IMGFMT.ovl2
996
+file format: IMGFMT
997
+virtual size: 64M (67108864 bytes)
998
+cluster_size: 65536
999
+backing file: TEST_DIR/t.IMGFMT.base
1000
+backing file format: IMGFMT
1001
+*** done
1002
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
1003
index XXXXXXX..XXXXXXX 100644
1004
--- a/tests/qemu-iotests/group
1005
+++ b/tests/qemu-iotests/group
1006
@@ -XXX,XX +XXX,XX @@
1007
188 rw auto quick
1008
189 rw auto
1009
190 rw auto quick
1010
+191 rw auto
1011
192 rw auto quick
1012
194 rw auto migration quick
1013
195 rw auto quick
1014
--
166
--
1015
2.13.6
167
2.29.2
1016
168
1017
169
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Backing may be zero after failed bdrv_attach_child in
3
Add new parallels-ext.c and myself as co-maintainer.
4
bdrv_set_backing_hd, which leads to SIGSEGV.
5
4
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20170928120300.58164-1-vsementsov@virtuozzo.com
6
Message-Id: <20210304095151.19358-1-vsementsov@virtuozzo.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
7
Reviewed-by: Denis V. Lunev <den@openvz.org>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
9
---
11
block/mirror.c | 5 +++++
10
MAINTAINERS | 3 +++
12
1 file changed, 5 insertions(+)
11
1 file changed, 3 insertions(+)
13
12
14
diff --git a/block/mirror.c b/block/mirror.c
13
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/block/mirror.c
15
--- a/MAINTAINERS
17
+++ b/block/mirror.c
16
+++ b/MAINTAINERS
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
17
@@ -XXX,XX +XXX,XX @@ F: block/dmg.c
19
18
parallels
20
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
19
M: Stefan Hajnoczi <stefanha@redhat.com>
21
{
20
M: Denis V. Lunev <den@openvz.org>
22
+ if (bs->backing == NULL) {
21
+M: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
+ /* we can be here after failed bdrv_attach_child in
22
L: qemu-block@nongnu.org
24
+ * bdrv_set_backing_hd */
23
S: Supported
25
+ return;
24
F: block/parallels.c
26
+ }
25
+F: block/parallels-ext.c
27
bdrv_refresh_filename(bs->backing->bs);
26
F: docs/interop/parallels.txt
28
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
27
+T: git https://src.openvz.org/scm/~vsementsov/qemu.git parallels
29
bs->backing->bs->filename);
28
29
qed
30
M: Stefan Hajnoczi <stefanha@redhat.com>
30
--
31
--
31
2.13.6
32
2.29.2
32
33
33
34
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
The 'name' option for NBD exports is optional. Add a note that the
2
default for the option is the node name (people could otherwise expect
3
that it's the empty string like for qemu-nbd).
2
4
3
Executing qemu with a terminal as stdin will temporarily alter stty
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
settings on that terminal (for example, disabling echo), because of
6
Message-Id: <20210305094856.18964-1-kwolf@redhat.com>
5
how we run both the monitor and any multiplexing with guest input.
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Normally, qemu restores the original settings on exit; but if an
7
iotest triggers qemu to abort in the middle, we can be left with
8
the altered terminal setup. This can make life very annoying when
9
debugging an iotest failure (not everyone remembers the trick of
10
blind-typing 'stty sane' without echo, and some people prefer
11
terminal settings that are slightly different than the defaults
12
picked by 'stty sane').
13
14
It is possible to avoid qemu corrupting the terminal by not passing
15
a terminal to qemu's stdin in the first place (as in, use
16
'./check ... </dev/null'), but that's extra typing to have to
17
remember. But running 'exec </dev/null' in the harness seems like
18
it might be too heavy of a hammer. So I instead went the the
19
solution of saving and restoring the stty settings, only when the
20
harness detects that it is run interactively.
21
22
I tested this patch by forcing an allocation failure (I can't
23
guarantee that this particular limit will work on all setups, but
24
it shows the idea):
25
$ (ulimit -S -v 500000; ./check -qcow2 1)
26
27
Signed-off-by: Eric Blake <eblake@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
9
---
30
tests/qemu-iotests/check | 10 ++++++++++
10
docs/tools/qemu-storage-daemon.rst | 5 +++--
31
1 file changed, 10 insertions(+)
11
1 file changed, 3 insertions(+), 2 deletions(-)
32
12
33
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
13
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
34
index XXXXXXX..XXXXXXX 100755
14
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/check
15
--- a/docs/tools/qemu-storage-daemon.rst
36
+++ b/tests/qemu-iotests/check
16
+++ b/docs/tools/qemu-storage-daemon.rst
37
@@ -XXX,XX +XXX,XX @@ export VALGRIND_QEMU=
17
@@ -XXX,XX +XXX,XX @@ Standard options:
38
export IMGKEYSECRET=
18
requests for modifying data (the default is off).
39
export IMGOPTSSYNTAX=false
19
40
20
The ``nbd`` export type requires ``--nbd-server`` (see below). ``name`` is
41
+# Save current tty settings, since an aborting qemu call may leave things
21
- the NBD export name. ``bitmap`` is the name of a dirty bitmap reachable from
42
+# screwed up
22
- the block node, so the NBD client can use NBD_OPT_SET_META_CONTEXT with the
43
+STTY_RESTORE=
23
+ the NBD export name (if not specified, it defaults to the given
44
+if test -t 0; then
24
+ ``node-name``). ``bitmap`` is the name of a dirty bitmap reachable from the
45
+ STTY_RESTORE=$(stty -g)
25
+ block node, so the NBD client can use NBD_OPT_SET_META_CONTEXT with the
46
+fi
26
metadata context name "qemu:dirty-bitmap:BITMAP" to inspect the bitmap.
47
+
27
48
for r
28
The ``vhost-user-blk`` export type takes a vhost-user socket address on which
49
do
50
51
@@ -XXX,XX +XXX,XX @@ END { if (NR > 0) {
52
needwrap=false
53
fi
54
55
+ if test -n "$STTY_RESTORE"; then
56
+ stty $STTY_RESTORE
57
+ fi
58
rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time
59
rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts
60
rm -f $tmp.*
61
--
29
--
62
2.13.6
30
2.29.2
63
31
64
32
diff view generated by jsdifflib
Deleted patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
1
3
Using 16KB bounce buffers creates a significant performance
4
penalty for I/O to encrypted volumes on storage which high
5
I/O latency (rotating rust & network drives), because it
6
triggers lots of fairly small I/O operations.
7
8
On tests with rotating rust, and cache=none|directsync,
9
write speed increased from 2MiB/s to 32MiB/s, on a par
10
with that achieved by the in-kernel luks driver. With
11
other cache modes the in-kernel driver is still notably
12
faster because it is able to report completion of the
13
I/O request before any encryption is done, while the
14
in-QEMU driver must encrypt the data before completion.
15
16
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
17
Message-id: 20170927125340.12360-2-berrange@redhat.com
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Reviewed-by: Max Reitz <mreitz@redhat.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
---
22
block/crypto.c | 28 +++++++++++++++-------------
23
1 file changed, 15 insertions(+), 13 deletions(-)
24
25
diff --git a/block/crypto.c b/block/crypto.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block/crypto.c
28
+++ b/block/crypto.c
29
@@ -XXX,XX +XXX,XX @@ static void block_crypto_close(BlockDriverState *bs)
30
}
31
32
33
-#define BLOCK_CRYPTO_MAX_SECTORS 32
34
+/*
35
+ * 1 MB bounce buffer gives good performance / memory tradeoff
36
+ * when using cache=none|directsync.
37
+ */
38
+#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
39
40
static coroutine_fn int
41
block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
42
@@ -XXX,XX +XXX,XX @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
43
44
qemu_iovec_init(&hd_qiov, qiov->niov);
45
46
- /* Bounce buffer so we have a linear mem region for
47
- * entire sector. XXX optimize so we avoid bounce
48
- * buffer in case that qiov->niov == 1
49
+ /* Bounce buffer because we don't wish to expose cipher text
50
+ * in qiov which points to guest memory.
51
*/
52
cipher_data =
53
- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
54
+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
55
qiov->size));
56
if (cipher_data == NULL) {
57
ret = -ENOMEM;
58
@@ -XXX,XX +XXX,XX @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
59
while (remaining_sectors) {
60
cur_nr_sectors = remaining_sectors;
61
62
- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
63
- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
64
+ if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) {
65
+ cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512);
66
}
67
68
qemu_iovec_reset(&hd_qiov);
69
@@ -XXX,XX +XXX,XX @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
70
71
qemu_iovec_init(&hd_qiov, qiov->niov);
72
73
- /* Bounce buffer so we have a linear mem region for
74
- * entire sector. XXX optimize so we avoid bounce
75
- * buffer in case that qiov->niov == 1
76
+ /* Bounce buffer because we're not permitted to touch
77
+ * contents of qiov - it points to guest memory.
78
*/
79
cipher_data =
80
- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
81
+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
82
qiov->size));
83
if (cipher_data == NULL) {
84
ret = -ENOMEM;
85
@@ -XXX,XX +XXX,XX @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
86
while (remaining_sectors) {
87
cur_nr_sectors = remaining_sectors;
88
89
- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
90
- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
91
+ if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) {
92
+ cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512);
93
}
94
95
qemu_iovec_to_buf(qiov, bytes_done,
96
--
97
2.13.6
98
99
diff view generated by jsdifflib
Deleted patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
1
3
The crypto APIs report the offset of the data payload as an uint64_t
4
type, but the block driver is casting to size_t or ssize_t which will
5
potentially truncate.
6
7
Most of the block APIs use int64_t for offsets meanwhile, so even if
8
using uint64_t in the crypto block driver we are still at risk of
9
truncation.
10
11
Change the block crypto driver to use uint64_t, but add asserts that
12
the value is less than INT64_MAX.
13
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
17
Message-id: 20170927125340.12360-4-berrange@redhat.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
block/crypto.c | 13 +++++++++----
21
1 file changed, 9 insertions(+), 4 deletions(-)
22
23
diff --git a/block/crypto.c b/block/crypto.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/crypto.c
26
+++ b/block/crypto.c
27
@@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
28
PreallocMode prealloc, Error **errp)
29
{
30
BlockCrypto *crypto = bs->opaque;
31
- size_t payload_offset =
32
+ uint64_t payload_offset =
33
qcrypto_block_get_payload_offset(crypto->block);
34
+ assert(payload_offset < (INT64_MAX - offset));
35
36
offset += payload_offset;
37
38
@@ -XXX,XX +XXX,XX @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
39
uint8_t *cipher_data = NULL;
40
QEMUIOVector hd_qiov;
41
int ret = 0;
42
- size_t payload_offset =
43
+ uint64_t payload_offset =
44
qcrypto_block_get_payload_offset(crypto->block) / 512;
45
+ assert(payload_offset < (INT64_MAX / 512));
46
47
qemu_iovec_init(&hd_qiov, qiov->niov);
48
49
@@ -XXX,XX +XXX,XX @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
50
uint8_t *cipher_data = NULL;
51
QEMUIOVector hd_qiov;
52
int ret = 0;
53
- size_t payload_offset =
54
+ uint64_t payload_offset =
55
qcrypto_block_get_payload_offset(crypto->block) / 512;
56
+ assert(payload_offset < (INT64_MAX / 512));
57
58
qemu_iovec_init(&hd_qiov, qiov->niov);
59
60
@@ -XXX,XX +XXX,XX @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
61
BlockCrypto *crypto = bs->opaque;
62
int64_t len = bdrv_getlength(bs->file->bs);
63
64
- ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
65
+ uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
66
+ assert(offset < INT64_MAX);
67
+ assert(offset < len);
68
69
len -= offset;
70
71
--
72
2.13.6
73
74
diff view generated by jsdifflib
Deleted patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
1
3
Make the crypto driver implement the bdrv_co_preadv|pwritev
4
callbacks, and also use bdrv_co_preadv|pwritev for I/O
5
with the protocol driver beneath. This replaces sector based
6
I/O with byte based I/O, and allows us to stop assuming the
7
physical sector size matches the encryption sector size.
8
9
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
10
Message-id: 20170927125340.12360-5-berrange@redhat.com
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/crypto.c | 106 +++++++++++++++++++++++++++++----------------------------
16
1 file changed, 54 insertions(+), 52 deletions(-)
17
18
diff --git a/block/crypto.c b/block/crypto.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/crypto.c
21
+++ b/block/crypto.c
22
@@ -XXX,XX +XXX,XX @@ static void block_crypto_close(BlockDriverState *bs)
23
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
24
25
static coroutine_fn int
26
-block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
27
- int remaining_sectors, QEMUIOVector *qiov)
28
+block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
29
+ QEMUIOVector *qiov, int flags)
30
{
31
BlockCrypto *crypto = bs->opaque;
32
- int cur_nr_sectors; /* number of sectors in current iteration */
33
+ uint64_t cur_bytes; /* number of bytes in current iteration */
34
uint64_t bytes_done = 0;
35
uint8_t *cipher_data = NULL;
36
QEMUIOVector hd_qiov;
37
int ret = 0;
38
- uint64_t payload_offset =
39
- qcrypto_block_get_payload_offset(crypto->block) / 512;
40
- assert(payload_offset < (INT64_MAX / 512));
41
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
42
+ uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
43
+ uint64_t sector_num = offset / sector_size;
44
+
45
+ assert(!flags);
46
+ assert(payload_offset < INT64_MAX);
47
+ assert(QEMU_IS_ALIGNED(offset, sector_size));
48
+ assert(QEMU_IS_ALIGNED(bytes, sector_size));
49
50
qemu_iovec_init(&hd_qiov, qiov->niov);
51
52
@@ -XXX,XX +XXX,XX @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
53
goto cleanup;
54
}
55
56
- while (remaining_sectors) {
57
- cur_nr_sectors = remaining_sectors;
58
-
59
- if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) {
60
- cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512);
61
- }
62
+ while (bytes) {
63
+ cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
64
65
qemu_iovec_reset(&hd_qiov);
66
- qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
67
+ qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
68
69
- ret = bdrv_co_readv(bs->file,
70
- payload_offset + sector_num,
71
- cur_nr_sectors, &hd_qiov);
72
+ ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
73
+ cur_bytes, &hd_qiov, 0);
74
if (ret < 0) {
75
goto cleanup;
76
}
77
78
- if (qcrypto_block_decrypt(crypto->block,
79
- sector_num,
80
- cipher_data, cur_nr_sectors * 512,
81
- NULL) < 0) {
82
+ if (qcrypto_block_decrypt(crypto->block, sector_num, cipher_data,
83
+ cur_bytes, NULL) < 0) {
84
ret = -EIO;
85
goto cleanup;
86
}
87
88
- qemu_iovec_from_buf(qiov, bytes_done,
89
- cipher_data, cur_nr_sectors * 512);
90
+ qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
91
92
- remaining_sectors -= cur_nr_sectors;
93
- sector_num += cur_nr_sectors;
94
- bytes_done += cur_nr_sectors * 512;
95
+ sector_num += cur_bytes / sector_size;
96
+ bytes -= cur_bytes;
97
+ bytes_done += cur_bytes;
98
}
99
100
cleanup:
101
@@ -XXX,XX +XXX,XX @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
102
103
104
static coroutine_fn int
105
-block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
106
- int remaining_sectors, QEMUIOVector *qiov)
107
+block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
108
+ QEMUIOVector *qiov, int flags)
109
{
110
BlockCrypto *crypto = bs->opaque;
111
- int cur_nr_sectors; /* number of sectors in current iteration */
112
+ uint64_t cur_bytes; /* number of bytes in current iteration */
113
uint64_t bytes_done = 0;
114
uint8_t *cipher_data = NULL;
115
QEMUIOVector hd_qiov;
116
int ret = 0;
117
- uint64_t payload_offset =
118
- qcrypto_block_get_payload_offset(crypto->block) / 512;
119
- assert(payload_offset < (INT64_MAX / 512));
120
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
121
+ uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
122
+ uint64_t sector_num = offset / sector_size;
123
+
124
+ assert(!flags);
125
+ assert(payload_offset < INT64_MAX);
126
+ assert(QEMU_IS_ALIGNED(offset, sector_size));
127
+ assert(QEMU_IS_ALIGNED(bytes, sector_size));
128
129
qemu_iovec_init(&hd_qiov, qiov->niov);
130
131
@@ -XXX,XX +XXX,XX @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
132
goto cleanup;
133
}
134
135
- while (remaining_sectors) {
136
- cur_nr_sectors = remaining_sectors;
137
+ while (bytes) {
138
+ cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
139
140
- if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) {
141
- cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512);
142
- }
143
-
144
- qemu_iovec_to_buf(qiov, bytes_done,
145
- cipher_data, cur_nr_sectors * 512);
146
+ qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
147
148
- if (qcrypto_block_encrypt(crypto->block,
149
- sector_num,
150
- cipher_data, cur_nr_sectors * 512,
151
- NULL) < 0) {
152
+ if (qcrypto_block_encrypt(crypto->block, sector_num, cipher_data,
153
+ cur_bytes, NULL) < 0) {
154
ret = -EIO;
155
goto cleanup;
156
}
157
158
qemu_iovec_reset(&hd_qiov);
159
- qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
160
+ qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
161
162
- ret = bdrv_co_writev(bs->file,
163
- payload_offset + sector_num,
164
- cur_nr_sectors, &hd_qiov);
165
+ ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
166
+ cur_bytes, &hd_qiov, 0);
167
if (ret < 0) {
168
goto cleanup;
169
}
170
171
- remaining_sectors -= cur_nr_sectors;
172
- sector_num += cur_nr_sectors;
173
- bytes_done += cur_nr_sectors * 512;
174
+ sector_num += cur_bytes / sector_size;
175
+ bytes -= cur_bytes;
176
+ bytes_done += cur_bytes;
177
}
178
179
cleanup:
180
@@ -XXX,XX +XXX,XX @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
181
return ret;
182
}
183
184
+static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
185
+{
186
+ BlockCrypto *crypto = bs->opaque;
187
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
188
+ bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
189
+}
190
+
191
192
static int64_t block_crypto_getlength(BlockDriverState *bs)
193
{
194
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
195
.bdrv_truncate = block_crypto_truncate,
196
.create_opts = &block_crypto_create_opts_luks,
197
198
- .bdrv_co_readv = block_crypto_co_readv,
199
- .bdrv_co_writev = block_crypto_co_writev,
200
+ .bdrv_refresh_limits = block_crypto_refresh_limits,
201
+ .bdrv_co_preadv = block_crypto_co_preadv,
202
+ .bdrv_co_pwritev = block_crypto_co_pwritev,
203
.bdrv_getlength = block_crypto_getlength,
204
.bdrv_get_info = block_crypto_get_info_luks,
205
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
206
--
207
2.13.6
208
209
diff view generated by jsdifflib
Deleted patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
1
3
Instead of sector offset, take the bytes offset when encrypting
4
or decrypting data.
5
6
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
7
Message-id: 20170927125340.12360-6-berrange@redhat.com
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
crypto/blockpriv.h | 4 ++--
13
include/crypto/block.h | 14 ++++++++------
14
block/crypto.c | 12 ++++--------
15
block/qcow.c | 11 +++++++----
16
block/qcow2-cluster.c | 8 +++-----
17
block/qcow2.c | 4 ++--
18
crypto/block-luks.c | 12 ++++++++----
19
crypto/block-qcow.c | 12 ++++++++----
20
crypto/block.c | 20 ++++++++++++++------
21
9 files changed, 56 insertions(+), 41 deletions(-)
22
23
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/crypto/blockpriv.h
26
+++ b/crypto/blockpriv.h
27
@@ -XXX,XX +XXX,XX @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
28
size_t niv,
29
QCryptoIVGen *ivgen,
30
int sectorsize,
31
- uint64_t startsector,
32
+ uint64_t offset,
33
uint8_t *buf,
34
size_t len,
35
Error **errp);
36
@@ -XXX,XX +XXX,XX @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
37
size_t niv,
38
QCryptoIVGen *ivgen,
39
int sectorsize,
40
- uint64_t startsector,
41
+ uint64_t offset,
42
uint8_t *buf,
43
size_t len,
44
Error **errp);
45
diff --git a/include/crypto/block.h b/include/crypto/block.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/include/crypto/block.h
48
+++ b/include/crypto/block.h
49
@@ -XXX,XX +XXX,XX @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
50
/**
51
* @qcrypto_block_decrypt:
52
* @block: the block encryption object
53
- * @startsector: the sector from which @buf was read
54
+ * @offset: the position at which @iov was read
55
* @buf: the buffer to decrypt
56
* @len: the length of @buf in bytes
57
* @errp: pointer to a NULL-initialized error object
58
*
59
* Decrypt @len bytes of cipher text in @buf, writing
60
- * plain text back into @buf
61
+ * plain text back into @buf. @len and @offset must be
62
+ * a multiple of the encryption format sector size.
63
*
64
* Returns 0 on success, -1 on failure
65
*/
66
int qcrypto_block_decrypt(QCryptoBlock *block,
67
- uint64_t startsector,
68
+ uint64_t offset,
69
uint8_t *buf,
70
size_t len,
71
Error **errp);
72
@@ -XXX,XX +XXX,XX @@ int qcrypto_block_decrypt(QCryptoBlock *block,
73
/**
74
* @qcrypto_block_encrypt:
75
* @block: the block encryption object
76
- * @startsector: the sector to which @buf will be written
77
+ * @offset: the position at which @iov will be written
78
* @buf: the buffer to decrypt
79
* @len: the length of @buf in bytes
80
* @errp: pointer to a NULL-initialized error object
81
*
82
* Encrypt @len bytes of plain text in @buf, writing
83
- * cipher text back into @buf
84
+ * cipher text back into @buf. @len and @offset must be
85
+ * a multiple of the encryption format sector size.
86
*
87
* Returns 0 on success, -1 on failure
88
*/
89
int qcrypto_block_encrypt(QCryptoBlock *block,
90
- uint64_t startsector,
91
+ uint64_t offset,
92
uint8_t *buf,
93
size_t len,
94
Error **errp);
95
diff --git a/block/crypto.c b/block/crypto.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/block/crypto.c
98
+++ b/block/crypto.c
99
@@ -XXX,XX +XXX,XX @@ block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
100
int ret = 0;
101
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
102
uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
103
- uint64_t sector_num = offset / sector_size;
104
105
assert(!flags);
106
assert(payload_offset < INT64_MAX);
107
@@ -XXX,XX +XXX,XX @@ block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
108
goto cleanup;
109
}
110
111
- if (qcrypto_block_decrypt(crypto->block, sector_num, cipher_data,
112
- cur_bytes, NULL) < 0) {
113
+ if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
114
+ cipher_data, cur_bytes, NULL) < 0) {
115
ret = -EIO;
116
goto cleanup;
117
}
118
119
qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
120
121
- sector_num += cur_bytes / sector_size;
122
bytes -= cur_bytes;
123
bytes_done += cur_bytes;
124
}
125
@@ -XXX,XX +XXX,XX @@ block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
126
int ret = 0;
127
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
128
uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
129
- uint64_t sector_num = offset / sector_size;
130
131
assert(!flags);
132
assert(payload_offset < INT64_MAX);
133
@@ -XXX,XX +XXX,XX @@ block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
134
135
qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
136
137
- if (qcrypto_block_encrypt(crypto->block, sector_num, cipher_data,
138
- cur_bytes, NULL) < 0) {
139
+ if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
140
+ cipher_data, cur_bytes, NULL) < 0) {
141
ret = -EIO;
142
goto cleanup;
143
}
144
@@ -XXX,XX +XXX,XX @@ block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
145
goto cleanup;
146
}
147
148
- sector_num += cur_bytes / sector_size;
149
bytes -= cur_bytes;
150
bytes_done += cur_bytes;
151
}
152
diff --git a/block/qcow.c b/block/qcow.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/block/qcow.c
155
+++ b/block/qcow.c
156
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
157
for(i = 0; i < s->cluster_sectors; i++) {
158
if (i < n_start || i >= n_end) {
159
memset(s->cluster_data, 0x00, 512);
160
- if (qcrypto_block_encrypt(s->crypto, start_sect + i,
161
+ if (qcrypto_block_encrypt(s->crypto,
162
+ (start_sect + i) *
163
+ BDRV_SECTOR_SIZE,
164
s->cluster_data,
165
BDRV_SECTOR_SIZE,
166
NULL) < 0) {
167
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
168
}
169
if (bs->encrypted) {
170
assert(s->crypto);
171
- if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
172
+ if (qcrypto_block_decrypt(s->crypto,
173
+ sector_num * BDRV_SECTOR_SIZE, buf,
174
n * BDRV_SECTOR_SIZE, NULL) < 0) {
175
ret = -EIO;
176
break;
177
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
178
}
179
if (bs->encrypted) {
180
assert(s->crypto);
181
- if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
182
- n * BDRV_SECTOR_SIZE, NULL) < 0) {
183
+ if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
184
+ buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
185
ret = -EIO;
186
break;
187
}
188
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
189
index XXXXXXX..XXXXXXX 100644
190
--- a/block/qcow2-cluster.c
191
+++ b/block/qcow2-cluster.c
192
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
193
{
194
if (bytes && bs->encrypted) {
195
BDRVQcow2State *s = bs->opaque;
196
- int64_t sector = (s->crypt_physical_offset ?
197
+ int64_t offset = (s->crypt_physical_offset ?
198
(cluster_offset + offset_in_cluster) :
199
- (src_cluster_offset + offset_in_cluster))
200
- >> BDRV_SECTOR_BITS;
201
+ (src_cluster_offset + offset_in_cluster));
202
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
203
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
204
assert(s->crypto);
205
- if (qcrypto_block_encrypt(s->crypto, sector, buffer,
206
- bytes, NULL) < 0) {
207
+ if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
208
return false;
209
}
210
}
211
diff --git a/block/qcow2.c b/block/qcow2.c
212
index XXXXXXX..XXXXXXX 100644
213
--- a/block/qcow2.c
214
+++ b/block/qcow2.c
215
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
216
if (qcrypto_block_decrypt(s->crypto,
217
(s->crypt_physical_offset ?
218
cluster_offset + offset_in_cluster :
219
- offset) >> BDRV_SECTOR_BITS,
220
+ offset),
221
cluster_data,
222
cur_bytes,
223
NULL) < 0) {
224
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
225
if (qcrypto_block_encrypt(s->crypto,
226
(s->crypt_physical_offset ?
227
cluster_offset + offset_in_cluster :
228
- offset) >> BDRV_SECTOR_BITS,
229
+ offset),
230
cluster_data,
231
cur_bytes, NULL) < 0) {
232
ret = -EIO;
233
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
234
index XXXXXXX..XXXXXXX 100644
235
--- a/crypto/block-luks.c
236
+++ b/crypto/block-luks.c
237
@@ -XXX,XX +XXX,XX @@ static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
238
239
static int
240
qcrypto_block_luks_decrypt(QCryptoBlock *block,
241
- uint64_t startsector,
242
+ uint64_t offset,
243
uint8_t *buf,
244
size_t len,
245
Error **errp)
246
{
247
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
248
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
249
return qcrypto_block_decrypt_helper(block->cipher,
250
block->niv, block->ivgen,
251
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
252
- startsector, buf, len, errp);
253
+ offset, buf, len, errp);
254
}
255
256
257
static int
258
qcrypto_block_luks_encrypt(QCryptoBlock *block,
259
- uint64_t startsector,
260
+ uint64_t offset,
261
uint8_t *buf,
262
size_t len,
263
Error **errp)
264
{
265
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
266
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
267
return qcrypto_block_encrypt_helper(block->cipher,
268
block->niv, block->ivgen,
269
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
270
- startsector, buf, len, errp);
271
+ offset, buf, len, errp);
272
}
273
274
275
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
276
index XXXXXXX..XXXXXXX 100644
277
--- a/crypto/block-qcow.c
278
+++ b/crypto/block-qcow.c
279
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_cleanup(QCryptoBlock *block)
280
281
static int
282
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
283
- uint64_t startsector,
284
+ uint64_t offset,
285
uint8_t *buf,
286
size_t len,
287
Error **errp)
288
{
289
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
290
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
291
return qcrypto_block_decrypt_helper(block->cipher,
292
block->niv, block->ivgen,
293
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
294
- startsector, buf, len, errp);
295
+ offset, buf, len, errp);
296
}
297
298
299
static int
300
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
301
- uint64_t startsector,
302
+ uint64_t offset,
303
uint8_t *buf,
304
size_t len,
305
Error **errp)
306
{
307
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
308
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
309
return qcrypto_block_encrypt_helper(block->cipher,
310
block->niv, block->ivgen,
311
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
312
- startsector, buf, len, errp);
313
+ offset, buf, len, errp);
314
}
315
316
317
diff --git a/crypto/block.c b/crypto/block.c
318
index XXXXXXX..XXXXXXX 100644
319
--- a/crypto/block.c
320
+++ b/crypto/block.c
321
@@ -XXX,XX +XXX,XX @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
322
323
324
int qcrypto_block_decrypt(QCryptoBlock *block,
325
- uint64_t startsector,
326
+ uint64_t offset,
327
uint8_t *buf,
328
size_t len,
329
Error **errp)
330
{
331
- return block->driver->decrypt(block, startsector, buf, len, errp);
332
+ return block->driver->decrypt(block, offset, buf, len, errp);
333
}
334
335
336
int qcrypto_block_encrypt(QCryptoBlock *block,
337
- uint64_t startsector,
338
+ uint64_t offset,
339
uint8_t *buf,
340
size_t len,
341
Error **errp)
342
{
343
- return block->driver->encrypt(block, startsector, buf, len, errp);
344
+ return block->driver->encrypt(block, offset, buf, len, errp);
345
}
346
347
348
@@ -XXX,XX +XXX,XX @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
349
size_t niv,
350
QCryptoIVGen *ivgen,
351
int sectorsize,
352
- uint64_t startsector,
353
+ uint64_t offset,
354
uint8_t *buf,
355
size_t len,
356
Error **errp)
357
{
358
uint8_t *iv;
359
int ret = -1;
360
+ uint64_t startsector = offset / sectorsize;
361
+
362
+ assert(QEMU_IS_ALIGNED(offset, sectorsize));
363
+ assert(QEMU_IS_ALIGNED(len, sectorsize));
364
365
iv = niv ? g_new0(uint8_t, niv) : NULL;
366
367
@@ -XXX,XX +XXX,XX @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
368
size_t niv,
369
QCryptoIVGen *ivgen,
370
int sectorsize,
371
- uint64_t startsector,
372
+ uint64_t offset,
373
uint8_t *buf,
374
size_t len,
375
Error **errp)
376
{
377
uint8_t *iv;
378
int ret = -1;
379
+ uint64_t startsector = offset / sectorsize;
380
+
381
+ assert(QEMU_IS_ALIGNED(offset, sectorsize));
382
+ assert(QEMU_IS_ALIGNED(len, sectorsize));
383
384
iv = niv ? g_new0(uint8_t, niv) : NULL;
385
386
--
387
2.13.6
388
389
diff view generated by jsdifflib
Deleted patch
1
From: "Daniel P. Berrange" <berrange@redhat.com>
2
1
3
The BDRV_REQ_FUA flag can trivially be allowed in the crypt driver
4
as a passthrough to the underlying block driver.
5
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
9
Message-id: 20170927125340.12360-7-berrange@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/crypto.c | 7 +++++--
13
1 file changed, 5 insertions(+), 2 deletions(-)
14
15
diff --git a/block/crypto.c b/block/crypto.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/crypto.c
18
+++ b/block/crypto.c
19
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
20
return -EINVAL;
21
}
22
23
+ bs->supported_write_flags = BDRV_REQ_FUA &
24
+ bs->file->bs->supported_write_flags;
25
+
26
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
27
qemu_opts_absorb_qdict(opts, options, &local_err);
28
if (local_err) {
29
@@ -XXX,XX +XXX,XX @@ block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
30
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
31
uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
32
33
- assert(!flags);
34
+ assert(!(flags & ~BDRV_REQ_FUA));
35
assert(payload_offset < INT64_MAX);
36
assert(QEMU_IS_ALIGNED(offset, sector_size));
37
assert(QEMU_IS_ALIGNED(bytes, sector_size));
38
@@ -XXX,XX +XXX,XX @@ block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
39
qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
40
41
ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
42
- cur_bytes, &hd_qiov, 0);
43
+ cur_bytes, &hd_qiov, flags);
44
if (ret < 0) {
45
goto cleanup;
46
}
47
--
48
2.13.6
49
50
diff view generated by jsdifflib
Deleted patch
1
From: Pavel Butsykin <pbutsykin@virtuozzo.com>
2
1
3
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: John Snow <jsnow@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20170929121613.25997-2-pbutsykin@virtuozzo.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/qcow2.c | 4 ++--
11
1 file changed, 2 insertions(+), 2 deletions(-)
12
13
diff --git a/block/qcow2.c b/block/qcow2.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/qcow2.c
16
+++ b/block/qcow2.c
17
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
18
if (old_file_size < 0) {
19
error_setg_errno(errp, -old_file_size,
20
"Failed to inquire current file length");
21
- return ret;
22
+ return old_file_size;
23
}
24
25
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
26
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
27
if (allocation_start < 0) {
28
error_setg_errno(errp, -allocation_start,
29
"Failed to resize refcount structures");
30
- return -allocation_start;
31
+ return allocation_start;
32
}
33
34
clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
35
--
36
2.13.6
37
38
diff view generated by jsdifflib
Deleted patch
1
From: Pavel Butsykin <pbutsykin@virtuozzo.com>
2
1
3
Now after shrinking the image, at the end of the image file, there might be a
4
tail that probably will never be used. So we can find the last used cluster and
5
cut the tail.
6
7
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Message-id: 20170929121613.25997-3-pbutsykin@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2.h | 1 +
13
block/qcow2-refcount.c | 22 ++++++++++++++++++++++
14
block/qcow2.c | 23 +++++++++++++++++++++++
15
3 files changed, 46 insertions(+)
16
17
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2.h
20
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
22
BlockDriverAmendStatusCB *status_cb,
23
void *cb_opaque, Error **errp);
24
int qcow2_shrink_reftable(BlockDriverState *bs);
25
+int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
26
27
/* qcow2-cluster.c functions */
28
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
29
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-refcount.c
32
+++ b/block/qcow2-refcount.c
33
@@ -XXX,XX +XXX,XX @@ out:
34
g_free(reftable_tmp);
35
return ret;
36
}
37
+
38
+int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
39
+{
40
+ BDRVQcow2State *s = bs->opaque;
41
+ int64_t i;
42
+
43
+ for (i = size_to_clusters(s, size) - 1; i >= 0; i--) {
44
+ uint64_t refcount;
45
+ int ret = qcow2_get_refcount(bs, i, &refcount);
46
+ if (ret < 0) {
47
+ fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
48
+ i, strerror(-ret));
49
+ return ret;
50
+ }
51
+ if (refcount > 0) {
52
+ return i;
53
+ }
54
+ }
55
+ qcow2_signal_corruption(bs, true, -1, -1,
56
+ "There are no references in the refcount table.");
57
+ return -EIO;
58
+}
59
diff --git a/block/qcow2.c b/block/qcow2.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/qcow2.c
62
+++ b/block/qcow2.c
63
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
64
new_l1_size = size_to_l1(s, offset);
65
66
if (offset < old_length) {
67
+ int64_t last_cluster, old_file_size;
68
if (prealloc != PREALLOC_MODE_OFF) {
69
error_setg(errp,
70
"Preallocation can't be used for shrinking an image");
71
@@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
72
"Failed to discard unused refblocks");
73
return ret;
74
}
75
+
76
+ old_file_size = bdrv_getlength(bs->file->bs);
77
+ if (old_file_size < 0) {
78
+ error_setg_errno(errp, -old_file_size,
79
+ "Failed to inquire current file length");
80
+ return old_file_size;
81
+ }
82
+ last_cluster = qcow2_get_last_cluster(bs, old_file_size);
83
+ if (last_cluster < 0) {
84
+ error_setg_errno(errp, -last_cluster,
85
+ "Failed to find the last cluster");
86
+ return last_cluster;
87
+ }
88
+ if ((last_cluster + 1) * s->cluster_size < old_file_size) {
89
+ ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
90
+ PREALLOC_MODE_OFF, NULL);
91
+ if (ret < 0) {
92
+ warn_report("Failed to truncate the tail of the image: %s",
93
+ strerror(-ret));
94
+ ret = 0;
95
+ }
96
+ }
97
} else {
98
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
99
if (ret < 0) {
100
--
101
2.13.6
102
103
diff view generated by jsdifflib