1
The following changes since commit 248b23735645f7cbb503d9be6f5bf825f2a603ab:
1
The following changes since commit f17783e706ab9c7b3a2b69cf48e4f0ba40664f54:
2
2
3
Update version for v2.10.0-rc4 release (2017-08-24 17:34:26 +0100)
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20191220' into staging (2020-01-03 18:50:33 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-01-06
8
8
9
for you to fetch changes up to 3e4c705212abfe8c9882a00beb2d1466a8a53cec:
9
for you to fetch changes up to 503ca1262bab2c11c533a4816d1ff4297d4f58a6:
10
10
11
qcow2: allocate cluster_cache/cluster_data on demand (2017-08-30 18:02:10 +0100)
11
backup-top: Begin drain earlier (2020-01-06 14:26:23 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
15
- Minor fixes and tests from the freeze period (too minor to be included
16
in 4.2)
17
- Allow many bash iotests to test qcow2's external data file feature
18
- Add compress filter driver
19
- Fix Python iotests after 6f6e1698a6
20
- Fix for the backup job
14
21
15
----------------------------------------------------------------
22
----------------------------------------------------------------
16
23
Andrey Shinkevich (3):
17
Alberto Garcia (8):
24
block: introduce compress filter driver
18
throttle: Fix wrong variable name in the header documentation
25
qcow2: Allow writing compressed data of multiple clusters
19
throttle: Update the throttle_fix_bucket() documentation
26
tests/qemu-iotests: add case to write compressed data of multiple
20
throttle: Make throttle_is_valid() a bit less verbose
27
clusters
21
throttle: Remove throttle_fix_bucket() / throttle_unfix_bucket()
28
22
throttle: Make LeakyBucket.avg and LeakyBucket.max integer types
29
Max Reitz (28):
23
throttle: Make burst_length 64bit and add range checks
30
block: Add bdrv_qapi_perm_to_blk_perm()
24
throttle: Test the valid range of config values
31
block: Use bdrv_qapi_perm_to_blk_perm()
25
misc: Remove unused Error variables
32
blkdebug: Allow taking/unsharing permissions
26
33
iotests: Add @error to wait_until_completed
27
Dan Aloni (1):
34
iotests: Add test for failing mirror complete
28
nvme: Fix get/set number of queues feature, again
35
iotests: s/qocw2/qcow2/
29
36
iotests/qcow2.py: Add dump-header-exts
30
Eduardo Habkost (1):
37
iotests/qcow2.py: Split feature fields into bits
31
oslib-posix: Print errors before aborting on qemu_alloc_stack()
38
iotests: Add _filter_json_filename
32
39
iotests: Filter refcount_order in 036
33
Fred Rolland (1):
40
iotests: Replace IMGOPTS by _unsupported_imgopts
34
qemu-doc: Add UUID support in initiator name
41
iotests: Drop compat=1.1 in 050
35
42
iotests: Let _make_test_img parse its parameters
36
Stefan Hajnoczi (4):
43
iotests: Add -o and --no-opts to _make_test_img
37
scripts: add argparse module for Python 2.6 compatibility
44
iotests: Inject space into -ocompat=0.10 in 051
38
docker.py: Python 2.6 argparse compatibility
45
iotests: Replace IMGOPTS= by -o
39
tests: migration/guestperf Python 2.6 argparse compatibility
46
iotests: Replace IMGOPTS='' by --no-opts
40
qcow2: allocate cluster_cache/cluster_data on demand
47
iotests: Drop IMGOPTS use in 267
41
48
iotests: Avoid qemu-img create
42
include/qemu/throttle.h | 8 +-
49
iotests: Use _rm_test_img for deleting test images
43
block/qcow.c | 12 +-
50
iotests: Avoid cp/mv of test images
44
block/qcow2-cluster.c | 17 +
51
iotests: Make 091 work with data_file
45
block/qcow2.c | 20 +-
52
iotests: Make 110 work with data_file
46
dump.c | 4 +-
53
iotests: Make 137 work with data_file
47
hw/block/nvme.c | 4 +-
54
iotests: Make 198 work with data_file
48
tests/test-throttle.c | 80 +-
55
iotests: Disable data_file where it cannot be used
49
util/oslib-posix.c | 2 +
56
iotests: Allow check -o data_file
50
util/throttle.c | 86 +-
57
backup-top: Begin drain earlier
51
COPYING.PYTHON | 270 ++++
58
52
qemu-doc.texi | 5 +-
59
PanNengyuan (1):
53
scripts/argparse.py | 2406 ++++++++++++++++++++++++++++++++++++
60
throttle-groups: fix memory leak in throttle_group_set_limit:
54
tests/docker/docker.py | 4 +-
61
55
tests/migration/guestperf/shell.py | 8 +-
62
Philippe Mathieu-Daudé (1):
56
14 files changed, 2831 insertions(+), 95 deletions(-)
63
tests/qemu-iotests: Update tests to recent desugarized -accel option
57
create mode 100644 COPYING.PYTHON
64
58
create mode 100644 scripts/argparse.py
65
Vladimir Sementsov-Ogievskiy (1):
66
qcow2-bitmaps: fix qcow2_can_store_new_dirty_bitmap
67
68
block.c | 47 +++++----
69
block/Makefile.objs | 1 +
70
block/backup-top.c | 4 +-
71
block/blkdebug.c | 93 ++++++++++++++++-
72
block/filter-compress.c | 168 +++++++++++++++++++++++++++++++
73
block/qcow2-bitmap.c | 41 ++++----
74
block/qcow2.c | 102 ++++++++++++++-----
75
block/throttle-groups.c | 4 +-
76
include/block/block.h | 1 +
77
qapi/block-core.json | 24 ++++-
78
tests/qemu-iotests/007 | 5 +-
79
tests/qemu-iotests/014 | 2 +
80
tests/qemu-iotests/015 | 5 +-
81
tests/qemu-iotests/019 | 6 +-
82
tests/qemu-iotests/020 | 6 +-
83
tests/qemu-iotests/024 | 10 +-
84
tests/qemu-iotests/026 | 5 +-
85
tests/qemu-iotests/028 | 2 +-
86
tests/qemu-iotests/029 | 7 +-
87
tests/qemu-iotests/031 | 9 +-
88
tests/qemu-iotests/031.out | 36 +++----
89
tests/qemu-iotests/036 | 15 +--
90
tests/qemu-iotests/036.out | 66 ++----------
91
tests/qemu-iotests/039 | 27 ++---
92
tests/qemu-iotests/039.out | 22 ++--
93
tests/qemu-iotests/041 | 44 ++++++++
94
tests/qemu-iotests/041.out | 4 +-
95
tests/qemu-iotests/043 | 4 +-
96
tests/qemu-iotests/046 | 2 +
97
tests/qemu-iotests/048 | 4 +-
98
tests/qemu-iotests/050 | 8 +-
99
tests/qemu-iotests/051 | 7 +-
100
tests/qemu-iotests/053 | 4 +-
101
tests/qemu-iotests/058 | 7 +-
102
tests/qemu-iotests/059 | 20 ++--
103
tests/qemu-iotests/060 | 14 +--
104
tests/qemu-iotests/060.out | 20 ++--
105
tests/qemu-iotests/061 | 63 ++++++------
106
tests/qemu-iotests/061.out | 72 ++++++-------
107
tests/qemu-iotests/062 | 5 +-
108
tests/qemu-iotests/063 | 18 ++--
109
tests/qemu-iotests/063.out | 3 +-
110
tests/qemu-iotests/066 | 7 +-
111
tests/qemu-iotests/067 | 6 +-
112
tests/qemu-iotests/068 | 6 +-
113
tests/qemu-iotests/069 | 2 +-
114
tests/qemu-iotests/071 | 7 +-
115
tests/qemu-iotests/073 | 4 +
116
tests/qemu-iotests/074 | 4 +-
117
tests/qemu-iotests/079 | 3 +-
118
tests/qemu-iotests/080 | 7 +-
119
tests/qemu-iotests/081 | 6 +-
120
tests/qemu-iotests/085 | 18 ++--
121
tests/qemu-iotests/085.out | 8 +-
122
tests/qemu-iotests/088 | 2 +-
123
tests/qemu-iotests/090 | 2 +
124
tests/qemu-iotests/091 | 2 +-
125
tests/qemu-iotests/091.out | 2 -
126
tests/qemu-iotests/092 | 2 +-
127
tests/qemu-iotests/094 | 4 +-
128
tests/qemu-iotests/095 | 5 +-
129
tests/qemu-iotests/098 | 6 +-
130
tests/qemu-iotests/099 | 10 +-
131
tests/qemu-iotests/103 | 5 +-
132
tests/qemu-iotests/106 | 2 +-
133
tests/qemu-iotests/108 | 10 +-
134
tests/qemu-iotests/109 | 4 +-
135
tests/qemu-iotests/110 | 11 +-
136
tests/qemu-iotests/110.out | 4 +-
137
tests/qemu-iotests/111 | 3 +-
138
tests/qemu-iotests/112 | 37 +++----
139
tests/qemu-iotests/114 | 2 +
140
tests/qemu-iotests/115 | 3 +-
141
tests/qemu-iotests/121 | 9 +-
142
tests/qemu-iotests/122 | 6 +-
143
tests/qemu-iotests/123 | 4 +-
144
tests/qemu-iotests/125 | 2 +-
145
tests/qemu-iotests/137 | 17 +++-
146
tests/qemu-iotests/137.out | 6 +-
147
tests/qemu-iotests/138 | 8 +-
148
tests/qemu-iotests/141 | 4 +-
149
tests/qemu-iotests/142 | 2 +-
150
tests/qemu-iotests/144 | 4 +-
151
tests/qemu-iotests/153 | 12 +--
152
tests/qemu-iotests/156 | 10 +-
153
tests/qemu-iotests/159 | 2 +-
154
tests/qemu-iotests/160 | 3 +-
155
tests/qemu-iotests/161 | 4 +-
156
tests/qemu-iotests/170 | 2 +-
157
tests/qemu-iotests/172 | 6 +-
158
tests/qemu-iotests/173 | 3 +-
159
tests/qemu-iotests/174 | 2 +-
160
tests/qemu-iotests/175 | 2 +-
161
tests/qemu-iotests/176 | 7 +-
162
tests/qemu-iotests/178 | 6 +-
163
tests/qemu-iotests/182 | 2 +-
164
tests/qemu-iotests/183 | 2 +-
165
tests/qemu-iotests/185 | 4 +-
166
tests/qemu-iotests/187 | 6 +-
167
tests/qemu-iotests/190 | 4 +-
168
tests/qemu-iotests/191 | 11 +-
169
tests/qemu-iotests/195 | 2 +-
170
tests/qemu-iotests/197 | 6 +-
171
tests/qemu-iotests/198 | 6 +-
172
tests/qemu-iotests/198.out | 4 +-
173
tests/qemu-iotests/200 | 7 +-
174
tests/qemu-iotests/201 | 6 +-
175
tests/qemu-iotests/214 | 46 ++++++++-
176
tests/qemu-iotests/214.out | 14 +++
177
tests/qemu-iotests/215 | 6 +-
178
tests/qemu-iotests/217 | 3 +-
179
tests/qemu-iotests/220 | 5 +-
180
tests/qemu-iotests/225 | 2 +-
181
tests/qemu-iotests/229 | 3 +-
182
tests/qemu-iotests/232 | 4 +-
183
tests/qemu-iotests/235 | 2 +-
184
tests/qemu-iotests/243 | 10 +-
185
tests/qemu-iotests/244 | 15 +--
186
tests/qemu-iotests/247 | 4 +-
187
tests/qemu-iotests/249 | 4 +-
188
tests/qemu-iotests/250 | 5 +-
189
tests/qemu-iotests/252 | 2 +-
190
tests/qemu-iotests/261 | 5 +-
191
tests/qemu-iotests/265 | 2 +-
192
tests/qemu-iotests/267 | 17 ++--
193
tests/qemu-iotests/273 | 3 +
194
tests/qemu-iotests/check | 6 +-
195
tests/qemu-iotests/common.filter | 47 ++++++++-
196
tests/qemu-iotests/common.rc | 63 ++++++++++--
197
tests/qemu-iotests/iotests.py | 18 ++--
198
tests/qemu-iotests/qcow2.py | 23 ++++-
199
131 files changed, 1139 insertions(+), 552 deletions(-)
200
create mode 100644 block/filter-compress.c
59
201
60
--
202
--
61
2.13.5
203
2.24.1
62
204
63
205
diff view generated by jsdifflib
New patch
1
We need some way to correlate QAPI BlockPermission values with
2
BLK_PERM_* flags. We could:
1
3
4
(1) have the same order in the QAPI definition as the the BLK_PERM_*
5
flags are in LSb-first order. However, then there is no guarantee
6
that they actually match (e.g. when someone modifies the QAPI schema
7
without thinking of the BLK_PERM_* definitions).
8
We could add static assertions, but these would break what’s good
9
about this solution, namely its simplicity.
10
11
(2) define the BLK_PERM_* flags based on the BlockPermission values.
12
But this way whenever someone were to modify the QAPI order
13
(perfectly sensible in theory), the BLK_PERM_* values would change.
14
Because these values are used for file locking, this might break
15
file locking between different qemu versions.
16
17
Therefore, go the slightly more cumbersome way: Add a function to
18
translate from the QAPI constants to the BLK_PERM_* flags.
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Message-id: 20191108123455.39445-2-mreitz@redhat.com
22
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
block.c | 18 ++++++++++++++++++
26
include/block/block.h | 1 +
27
2 files changed, 19 insertions(+)
28
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
32
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
34
*nshared = shared;
35
}
36
37
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
38
+{
39
+ static const uint64_t permissions[] = {
40
+ [BLOCK_PERMISSION_CONSISTENT_READ] = BLK_PERM_CONSISTENT_READ,
41
+ [BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
42
+ [BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
43
+ [BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
44
+ [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
45
+ };
46
+
47
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX);
48
+ QEMU_BUILD_BUG_ON(1UL << ARRAY_SIZE(permissions) != BLK_PERM_ALL + 1);
49
+
50
+ assert(qapi_perm < BLOCK_PERMISSION__MAX);
51
+
52
+ return permissions[qapi_perm];
53
+}
54
+
55
static void bdrv_replace_child_noperm(BdrvChild *child,
56
BlockDriverState *new_bs)
57
{
58
diff --git a/include/block/block.h b/include/block/block.h
59
index XXXXXXX..XXXXXXX 100644
60
--- a/include/block/block.h
61
+++ b/include/block/block.h
62
@@ -XXX,XX +XXX,XX @@ enum {
63
};
64
65
char *bdrv_perm_names(uint64_t perm);
66
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
67
68
/* disk I/O throttling */
69
void bdrv_init(void);
70
--
71
2.24.1
72
73
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
We can save some LoC in xdbg_graph_add_edge() by using
2
bdrv_qapi_perm_to_blk_perm().
2
3
3
Use a pointer to the bucket instead of repeating cfg->buckets[i] all
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
the time. This makes the code more concise and will help us expand the
5
Message-id: 20191108123455.39445-3-mreitz@redhat.com
5
checks later and save a few line breaks.
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
block.c | 29 ++++++++---------------------
10
1 file changed, 8 insertions(+), 21 deletions(-)
6
11
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
diff --git a/block.c b/block.c
8
Message-id: 763ffc40a26b17d54cf93f5a999e4656049fcf0c.1503580370.git.berto@igalia.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
util/throttle.c | 15 +++++++--------
12
1 file changed, 7 insertions(+), 8 deletions(-)
13
14
diff --git a/util/throttle.c b/util/throttle.c
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
16
--- a/util/throttle.c
14
--- a/block.c
17
+++ b/util/throttle.c
15
+++ b/block.c
18
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
16
@@ -XXX,XX +XXX,XX @@ static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
17
static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
18
const BdrvChild *child)
19
{
20
- typedef struct {
21
- unsigned int flag;
22
- BlockPermission num;
23
- } PermissionMap;
24
-
25
- static const PermissionMap permissions[] = {
26
- { BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
27
- { BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
28
- { BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
29
- { BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
30
- { BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
31
- { 0, 0 }
32
- };
33
- const PermissionMap *p;
34
+ BlockPermission qapi_perm;
35
XDbgBlockGraphEdge *edge;
36
37
- QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);
38
-
39
edge = g_new0(XDbgBlockGraphEdge, 1);
40
41
edge->parent = xdbg_graph_node_num(gr, parent);
42
edge->child = xdbg_graph_node_num(gr, child->bs);
43
edge->name = g_strdup(child->name);
44
45
- for (p = permissions; p->flag; p++) {
46
- if (p->flag & child->perm) {
47
- QAPI_LIST_ADD(edge->perm, p->num);
48
+ for (qapi_perm = 0; qapi_perm < BLOCK_PERMISSION__MAX; qapi_perm++) {
49
+ uint64_t flag = bdrv_qapi_perm_to_blk_perm(qapi_perm);
50
+
51
+ if (flag & child->perm) {
52
+ QAPI_LIST_ADD(edge->perm, qapi_perm);
53
}
54
- if (p->flag & child->shared_perm) {
55
- QAPI_LIST_ADD(edge->shared_perm, p->num);
56
+ if (flag & child->shared_perm) {
57
+ QAPI_LIST_ADD(edge->shared_perm, qapi_perm);
58
}
19
}
59
}
20
60
21
for (i = 0; i < BUCKETS_COUNT; i++) {
22
- if (cfg->buckets[i].avg < 0 ||
23
- cfg->buckets[i].max < 0 ||
24
- cfg->buckets[i].avg > THROTTLE_VALUE_MAX ||
25
- cfg->buckets[i].max > THROTTLE_VALUE_MAX) {
26
+ LeakyBucket *bkt = &cfg->buckets[i];
27
+ if (bkt->avg < 0 || bkt->max < 0 ||
28
+ bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
29
error_setg(errp, "bps/iops/max values must be within [0, %lld]",
30
THROTTLE_VALUE_MAX);
31
return false;
32
}
33
34
- if (!cfg->buckets[i].burst_length) {
35
+ if (!bkt->burst_length) {
36
error_setg(errp, "the burst length cannot be 0");
37
return false;
38
}
39
40
- if (cfg->buckets[i].burst_length > 1 && !cfg->buckets[i].max) {
41
+ if (bkt->burst_length > 1 && !bkt->max) {
42
error_setg(errp, "burst length set without burst rate");
43
return false;
44
}
45
46
- if (cfg->buckets[i].max && !cfg->buckets[i].avg) {
47
+ if (bkt->max && !bkt->avg) {
48
error_setg(errp, "bps_max/iops_max require corresponding"
49
" bps/iops values");
50
return false;
51
}
52
53
- if (cfg->buckets[i].max && cfg->buckets[i].max < cfg->buckets[i].avg) {
54
+ if (bkt->max && bkt->max < bkt->avg) {
55
error_setg(errp, "bps_max/iops_max cannot be lower than bps/iops");
56
return false;
57
}
58
--
61
--
59
2.13.5
62
2.24.1
60
63
61
64
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Sometimes it is useful to be able to add a node to the block graph that
2
takes or unshare a certain set of permissions for debugging purposes.
3
This patch adds this capability to blkdebug.
2
4
3
The throttling code can change internally the value of bkt->max if it
5
(Note that you cannot make blkdebug release or share permissions that it
4
hasn't been set by the user. The problem with this is that if we want
6
needs to take or cannot share, because this might result in assertion
5
to retrieve the original value we have to undo this change first. This
7
failures in the block layer. But if the blkdebug node has no parents,
6
is ugly and unnecessary: this patch removes the throttle_fix_bucket()
8
it will not take any permissions and share everything by default, so you
7
and throttle_unfix_bucket() functions completely and moves the logic
9
can then freely choose what permissions to take and share.)
8
to throttle_compute_wait().
9
10
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
12
Message-id: 20191108123455.39445-4-mreitz@redhat.com
12
Message-id: 5b0b9e1ac6eb208d709eddc7b09e7669a523bff3.1503580370.git.berto@igalia.com
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
---
15
util/throttle.c | 62 +++++++++++++++++++++------------------------------------
16
block/blkdebug.c | 93 +++++++++++++++++++++++++++++++++++++++++++-
16
1 file changed, 23 insertions(+), 39 deletions(-)
17
qapi/block-core.json | 14 ++++++-
18
2 files changed, 105 insertions(+), 2 deletions(-)
17
19
18
diff --git a/util/throttle.c b/util/throttle.c
20
diff --git a/block/blkdebug.c b/block/blkdebug.c
19
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
20
--- a/util/throttle.c
22
--- a/block/blkdebug.c
21
+++ b/util/throttle.c
23
+++ b/block/blkdebug.c
22
@@ -XXX,XX +XXX,XX @@ static int64_t throttle_do_compute_wait(double limit, double extra)
24
@@ -XXX,XX +XXX,XX @@
23
int64_t throttle_compute_wait(LeakyBucket *bkt)
25
#include "qemu/cutils.h"
24
{
26
#include "qemu/config-file.h"
25
double extra; /* the number of extra units blocking the io */
27
#include "block/block_int.h"
26
+ double bucket_size; /* I/O before throttling to bkt->avg */
28
+#include "block/qdict.h"
27
+ double burst_bucket_size; /* Before throttling to bkt->max */
29
#include "qemu/module.h"
28
30
#include "qemu/option.h"
29
if (!bkt->avg) {
31
+#include "qapi/qapi-visit-block-core.h"
30
return 0;
32
#include "qapi/qmp/qdict.h"
31
}
33
+#include "qapi/qmp/qlist.h"
32
34
#include "qapi/qmp/qstring.h"
33
- /* If the bucket is full then we have to wait */
35
+#include "qapi/qobject-input-visitor.h"
34
- extra = bkt->level - bkt->max * bkt->burst_length;
36
#include "sysemu/qtest.h"
35
+ if (!bkt->max) {
37
36
+ /* If bkt->max is 0 we still want to allow short bursts of I/O
38
typedef struct BDRVBlkdebugState {
37
+ * from the guest, otherwise every other request will be throttled
39
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVBlkdebugState {
38
+ * and performance will suffer considerably. */
40
uint64_t opt_discard;
39
+ bucket_size = bkt->avg / 10;
41
uint64_t max_discard;
40
+ burst_bucket_size = 0;
42
41
+ } else {
43
+ uint64_t take_child_perms;
42
+ /* If we have a burst limit then we have to wait until all I/O
44
+ uint64_t unshare_child_perms;
43
+ * at burst rate has finished before throttling to bkt->avg */
45
+
44
+ bucket_size = bkt->max * bkt->burst_length;
46
/* For blkdebug_refresh_filename() */
45
+ burst_bucket_size = bkt->max / 10;
47
char *config_file;
48
49
@@ -XXX,XX +XXX,XX @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
50
qdict_put_str(options, "x-image", filename);
51
}
52
53
+static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
54
+ const char *prefix, Error **errp)
55
+{
56
+ int ret = 0;
57
+ QDict *subqdict = NULL;
58
+ QObject *crumpled_subqdict = NULL;
59
+ Visitor *v = NULL;
60
+ BlockPermissionList *perm_list = NULL, *element;
61
+ Error *local_err = NULL;
62
+
63
+ *dest = 0;
64
+
65
+ qdict_extract_subqdict(options, &subqdict, prefix);
66
+ if (!qdict_size(subqdict)) {
67
+ goto out;
46
+ }
68
+ }
47
+
69
+
48
+ /* If the main bucket is full then we have to wait */
70
+ crumpled_subqdict = qdict_crumple(subqdict, errp);
49
+ extra = bkt->level - bucket_size;
71
+ if (!crumpled_subqdict) {
50
if (extra > 0) {
72
+ ret = -EINVAL;
51
return throttle_do_compute_wait(bkt->avg, extra);
73
+ goto out;
52
}
74
+ }
53
75
+
54
- /* If the bucket is not full yet we have to make sure that we
76
+ v = qobject_input_visitor_new(crumpled_subqdict);
55
- * fulfill the goal of bkt->max units per second. */
77
+ visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err);
56
+ /* If the main bucket is not full yet we still have to check the
78
+ if (local_err) {
57
+ * burst bucket in order to enforce the burst limit */
79
+ error_propagate(errp, local_err);
58
if (bkt->burst_length > 1) {
80
+ ret = -EINVAL;
59
- /* We use 1/10 of the max value to smooth the throttling.
81
+ goto out;
60
- * See throttle_fix_bucket() for more details. */
82
+ }
61
- extra = bkt->burst_level - bkt->max / 10;
83
+
62
+ extra = bkt->burst_level - burst_bucket_size;
84
+ for (element = perm_list; element; element = element->next) {
63
if (extra > 0) {
85
+ *dest |= bdrv_qapi_perm_to_blk_perm(element->value);
64
return throttle_do_compute_wait(bkt->max, extra);
86
+ }
65
}
87
+
66
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
88
+out:
67
return true;
89
+ qapi_free_BlockPermissionList(perm_list);
90
+ visit_free(v);
91
+ qobject_unref(subqdict);
92
+ qobject_unref(crumpled_subqdict);
93
+ return ret;
94
+}
95
+
96
+static int blkdebug_parse_perms(BDRVBlkdebugState *s, QDict *options,
97
+ Error **errp)
98
+{
99
+ int ret;
100
+
101
+ ret = blkdebug_parse_perm_list(&s->take_child_perms, options,
102
+ "take-child-perms.", errp);
103
+ if (ret < 0) {
104
+ return ret;
105
+ }
106
+
107
+ ret = blkdebug_parse_perm_list(&s->unshare_child_perms, options,
108
+ "unshare-child-perms.", errp);
109
+ if (ret < 0) {
110
+ return ret;
111
+ }
112
+
113
+ return 0;
114
+}
115
+
116
static QemuOptsList runtime_opts = {
117
.name = "blkdebug",
118
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
119
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
120
/* Set initial state */
121
s->state = 1;
122
123
+ /* Parse permissions modifiers before opening the image file */
124
+ ret = blkdebug_parse_perms(s, options, errp);
125
+ if (ret < 0) {
126
+ goto out;
127
+ }
128
+
129
/* Open the image file */
130
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
131
bs, &child_file, false, &local_err);
132
@@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
133
return 0;
68
}
134
}
69
135
70
-/* fix bucket parameters */
136
+static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
71
-static void throttle_fix_bucket(LeakyBucket *bkt)
137
+ const BdrvChildRole *role,
72
-{
138
+ BlockReopenQueue *reopen_queue,
73
- double min;
139
+ uint64_t perm, uint64_t shared,
74
-
140
+ uint64_t *nperm, uint64_t *nshared)
75
- /* zero bucket level */
141
+{
76
- bkt->level = bkt->burst_level = 0;
142
+ BDRVBlkdebugState *s = bs->opaque;
77
-
143
+
78
- /* If bkt->max is 0 we still want to allow short bursts of I/O
144
+ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
79
- * from the guest, otherwise every other request will be throttled
145
+ nperm, nshared);
80
- * and performance will suffer considerably. */
146
+
81
- min = bkt->avg / 10;
147
+ *nperm |= s->take_child_perms;
82
- if (bkt->avg && !bkt->max) {
148
+ *nshared &= ~s->unshare_child_perms;
83
- bkt->max = min;
149
+}
84
- }
150
+
85
-}
151
static const char *const blkdebug_strong_runtime_opts[] = {
86
-
152
"config",
87
-/* undo internal bucket parameter changes (see throttle_fix_bucket()) */
153
"inject-error.",
88
-static void throttle_unfix_bucket(LeakyBucket *bkt)
154
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
89
-{
155
.bdrv_file_open = blkdebug_open,
90
- if (bkt->max < bkt->avg) {
156
.bdrv_close = blkdebug_close,
91
- bkt->max = 0;
157
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
92
- }
158
- .bdrv_child_perm = bdrv_filter_default_perms,
93
-}
159
+ .bdrv_child_perm = blkdebug_child_perm,
94
-
160
95
/* Used to configure the throttle
161
.bdrv_getlength = blkdebug_getlength,
96
*
162
.bdrv_refresh_filename = blkdebug_refresh_filename,
97
* @ts: the throttle state we are working on
163
diff --git a/qapi/block-core.json b/qapi/block-core.json
98
@@ -XXX,XX +XXX,XX @@ void throttle_config(ThrottleState *ts,
164
index XXXXXXX..XXXXXXX 100644
99
165
--- a/qapi/block-core.json
100
ts->cfg = *cfg;
166
+++ b/qapi/block-core.json
101
167
@@ -XXX,XX +XXX,XX @@
102
+ /* Zero bucket level */
168
#
103
for (i = 0; i < BUCKETS_COUNT; i++) {
169
# @set-state: array of state-change descriptions
104
- throttle_fix_bucket(&ts->cfg.buckets[i]);
170
#
105
+ ts->cfg.buckets[i].level = 0;
171
+# @take-child-perms: Permissions to take on @image in addition to what
106
+ ts->cfg.buckets[i].burst_level = 0;
172
+# is necessary anyway (which depends on how the
107
}
173
+# blkdebug node is used). Defaults to none.
108
174
+# (since 5.0)
109
ts->previous_leak = qemu_clock_get_ns(clock_type);
175
+#
110
@@ -XXX,XX +XXX,XX @@ void throttle_config(ThrottleState *ts,
176
+# @unshare-child-perms: Permissions not to share on @image in addition
111
*/
177
+# to what cannot be shared anyway (which depends
112
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg)
178
+# on how the blkdebug node is used). Defaults
113
{
179
+# to none. (since 5.0)
114
- int i;
180
+#
115
-
181
# Since: 2.9
116
*cfg = ts->cfg;
182
##
117
-
183
{ 'struct': 'BlockdevOptionsBlkdebug',
118
- for (i = 0; i < BUCKETS_COUNT; i++) {
184
@@ -XXX,XX +XXX,XX @@
119
- throttle_unfix_bucket(&cfg->buckets[i]);
185
'*opt-write-zero': 'int32', '*max-write-zero': 'int32',
120
- }
186
'*opt-discard': 'int32', '*max-discard': 'int32',
121
}
187
'*inject-error': ['BlkdebugInjectErrorOptions'],
122
188
- '*set-state': ['BlkdebugSetStateOptions'] } }
123
189
+ '*set-state': ['BlkdebugSetStateOptions'],
190
+ '*take-child-perms': ['BlockPermission'],
191
+ '*unshare-child-perms': ['BlockPermission'] } }
192
193
##
194
# @BlockdevOptionsBlklogwrites:
124
--
195
--
125
2.13.5
196
2.24.1
126
197
127
198
diff view generated by jsdifflib
New patch
1
Callers can use this new parameter to expect failure during the
2
completion process.
1
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: John Snow <jsnow@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20191108123455.39445-5-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/iotests.py | 18 ++++++++++++------
11
1 file changed, 12 insertions(+), 6 deletions(-)
12
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/iotests.py
16
+++ b/tests/qemu-iotests/iotests.py
17
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
18
self.assert_no_active_block_jobs()
19
return result
20
21
- def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0):
22
+ def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0,
23
+ error=None):
24
'''Wait for a block job to finish, returning the event'''
25
while True:
26
for event in self.vm.get_qmp_events(wait=wait):
27
if event['event'] == 'BLOCK_JOB_COMPLETED':
28
self.assert_qmp(event, 'data/device', drive)
29
- self.assert_qmp_absent(event, 'data/error')
30
- if check_offset:
31
- self.assert_qmp(event, 'data/offset', event['data']['len'])
32
+ if error is None:
33
+ self.assert_qmp_absent(event, 'data/error')
34
+ if check_offset:
35
+ self.assert_qmp(event, 'data/offset',
36
+ event['data']['len'])
37
+ else:
38
+ self.assert_qmp(event, 'data/error', error)
39
self.assert_no_active_block_jobs()
40
return event
41
elif event['event'] == 'JOB_STATUS_CHANGE':
42
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
43
self.assert_qmp(event, 'data/type', 'mirror')
44
self.assert_qmp(event, 'data/offset', event['data']['len'])
45
46
- def complete_and_wait(self, drive='drive0', wait_ready=True):
47
+ def complete_and_wait(self, drive='drive0', wait_ready=True,
48
+ completion_error=None):
49
'''Complete a block job and wait for it to finish'''
50
if wait_ready:
51
self.wait_ready(drive=drive)
52
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
53
result = self.vm.qmp('block-job-complete', device=drive)
54
self.assert_qmp(result, 'return', {})
55
56
- event = self.wait_until_completed(drive=drive)
57
+ event = self.wait_until_completed(drive=drive, error=completion_error)
58
self.assert_qmp(event, 'data/type', 'mirror')
59
60
def pause_wait(self, job_id='job0'):
61
--
62
2.24.1
63
64
diff view generated by jsdifflib
New patch
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
3
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Reviewed-by: John Snow <jsnow@redhat.com>
5
Message-id: 20191108123455.39445-6-mreitz@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/041 | 44 ++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/041.out | 4 ++--
10
2 files changed, 46 insertions(+), 2 deletions(-)
1
11
12
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/041
15
+++ b/tests/qemu-iotests/041
16
@@ -XXX,XX +XXX,XX @@ class TestOrphanedSource(iotests.QMPTestCase):
17
target='dest-ro')
18
self.assert_qmp(result, 'error/class', 'GenericError')
19
20
+ def test_failing_permission_in_complete(self):
21
+ self.assert_no_active_block_jobs()
22
+
23
+ # Unshare consistent-read on the target
24
+ # (The mirror job does not care)
25
+ result = self.vm.qmp('blockdev-add',
26
+ driver='blkdebug',
27
+ node_name='dest-perm',
28
+ image='dest',
29
+ unshare_child_perms=['consistent-read'])
30
+ self.assert_qmp(result, 'return', {})
31
+
32
+ result = self.vm.qmp('blockdev-mirror', job_id='job', device='src',
33
+ sync='full', target='dest',
34
+ filter_node_name='mirror-filter')
35
+ self.assert_qmp(result, 'return', {})
36
+
37
+ # Require consistent-read on the source
38
+ # (We can only add this node once the job has started, or it
39
+ # will complain that it does not want to run on non-root nodes)
40
+ result = self.vm.qmp('blockdev-add',
41
+ driver='blkdebug',
42
+ node_name='src-perm',
43
+ image='src',
44
+ take_child_perms=['consistent-read'])
45
+ self.assert_qmp(result, 'return', {})
46
+
47
+ # While completing, mirror will attempt to replace src by
48
+ # dest, which must fail because src-perm requires
49
+ # consistent-read but dest-perm does not share it; thus
50
+ # aborting the job when it is supposed to complete
51
+ self.complete_and_wait('job',
52
+ completion_error='Operation not permitted')
53
+
54
+ # Assert that all of our nodes are still there (except for the
55
+ # mirror filter, which should be gone despite the failure)
56
+ nodes = self.vm.qmp('query-named-block-nodes')['return']
57
+ nodes = [node['node-name'] for node in nodes]
58
+
59
+ for expect in ('src', 'src-perm', 'dest', 'dest-perm'):
60
+ self.assertTrue(expect in nodes, '%s disappeared' % expect)
61
+ self.assertFalse('mirror-filter' in nodes,
62
+ 'Mirror filter node did not disappear')
63
+
64
if __name__ == '__main__':
65
iotests.main(supported_fmts=['qcow2', 'qed'],
66
supported_protocols=['file'])
67
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/041.out
70
+++ b/tests/qemu-iotests/041.out
71
@@ -XXX,XX +XXX,XX @@
72
-..........................................................................................
73
+...........................................................................................
74
----------------------------------------------------------------------
75
-Ran 90 tests
76
+Ran 91 tests
77
78
OK
79
--
80
2.24.1
81
82
diff view generated by jsdifflib
New patch
1
From: PanNengyuan <pannengyuan@huawei.com>
1
2
3
This avoid a memory leak when qom-set is called to set throttle_group
4
limits, here is an easy way to reproduce:
5
6
1. run qemu-iotests as follow and check the result with asan:
7
./check -qcow2 184
8
9
Following is the asan output backtrack:
10
Direct leak of 912 byte(s) in 3 object(s) allocated from:
11
#0 0xffff8d7ab3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3)
12
#1 0xffff8d4c31cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb)
13
#2 0x190c857 in qobject_input_start_struct /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qapi/qobject-input-visitor.c:295
14
#3 0x19070df in visit_start_struct /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qapi/qapi-visit-core.c:49
15
#4 0x1948b87 in visit_type_ThrottleLimits qapi/qapi-visit-block-core.c:3759
16
#5 0x17e4aa3 in throttle_group_set_limits /mnt/sdc/qemu-master/qemu-4.2.0-rc0/block/throttle-groups.c:900
17
#6 0x1650eff in object_property_set /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/object.c:1272
18
#7 0x1658517 in object_property_set_qobject /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/qom-qobject.c:26
19
#8 0x15880bb in qmp_qom_set /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/qom-qmp-cmds.c:74
20
#9 0x157e3e3 in qmp_marshal_qom_set qapi/qapi-commands-qom.c:154
21
22
Reported-by: Euler Robot <euler.robot@huawei.com>
23
Signed-off-by: PanNengyuan <pannengyuan@huawei.com>
24
Message-id: 1574835614-42028-1-git-send-email-pannengyuan@huawei.com
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
---
27
block/throttle-groups.c | 4 ++--
28
1 file changed, 2 insertions(+), 2 deletions(-)
29
30
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/throttle-groups.c
33
+++ b/block/throttle-groups.c
34
@@ -XXX,XX +XXX,XX @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
35
{
36
ThrottleGroup *tg = THROTTLE_GROUP(obj);
37
ThrottleConfig cfg;
38
- ThrottleLimits arg = { 0 };
39
- ThrottleLimits *argp = &arg;
40
+ ThrottleLimits *argp;
41
Error *local_err = NULL;
42
43
visit_type_ThrottleLimits(v, name, &argp, &local_err);
44
@@ -XXX,XX +XXX,XX @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
45
unlock:
46
qemu_mutex_unlock(&tg->lock);
47
ret:
48
+ qapi_free_ThrottleLimits(argp);
49
error_propagate(errp, local_err);
50
return;
51
}
52
--
53
2.24.1
54
55
diff view generated by jsdifflib
1
Most qcow2 files are uncompressed so it is wasteful to allocate (32 + 1)
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
* cluster_size + 512 bytes upfront. Allocate s->cluster_cache and
3
s->cluster_data when the first read operation is performance on a
4
compressed cluster.
5
2
6
The buffers are freed in .bdrv_close(). .bdrv_open() no longer has any
3
qcow2_can_store_new_dirty_bitmap works wrong, as it considers only
7
code paths that can allocate these buffers, so remove the free functions
4
bitmaps already stored in the qcow2 image and ignores persistent
8
in the error code path.
5
BdrvDirtyBitmap objects.
9
6
10
This patch can result in significant memory savings when many qcow2
7
So, let's instead count persistent BdrvDirtyBitmaps. We load all qcow2
11
disks are attached or backing file chains are long:
8
bitmaps on open, so there should not be any bitmap in the image for
9
which we don't have BdrvDirtyBitmaps version. If it is - it's a kind of
10
corruption, and no reason to check for corruptions here (open() and
11
close() are better places for it).
12
12
13
Before 12.81% (1,023,193,088B)
13
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
After 5.36% (393,893,888B)
14
Message-id: 20191014115126.15360-2-vsementsov@virtuozzo.com
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Cc: qemu-stable@nongnu.org
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/qcow2-bitmap.c | 41 ++++++++++++++++++-----------------------
20
1 file changed, 18 insertions(+), 23 deletions(-)
15
21
16
Reported-by: Alexey Kardashevskiy <aik@ozlabs.ru>
22
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
17
Tested-by: Alexey Kardashevskiy <aik@ozlabs.ru>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Message-id: 20170821135530.32344-1-stefanha@redhat.com
21
Cc: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
---
24
block/qcow2-cluster.c | 17 +++++++++++++++++
25
block/qcow2.c | 12 ------------
26
2 files changed, 17 insertions(+), 12 deletions(-)
27
28
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
29
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
30
--- a/block/qcow2-cluster.c
24
--- a/block/qcow2-bitmap.c
31
+++ b/block/qcow2-cluster.c
25
+++ b/block/qcow2-bitmap.c
32
@@ -XXX,XX +XXX,XX @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
26
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
33
nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
27
Error **errp)
34
sector_offset = coffset & 511;
28
{
35
csize = nb_csectors * 512 - sector_offset;
29
BDRVQcow2State *s = bs->opaque;
30
- bool found;
31
- Qcow2BitmapList *bm_list;
32
+ BdrvDirtyBitmap *bitmap;
33
+ uint64_t bitmap_directory_size = 0;
34
+ uint32_t nb_bitmaps = 0;
36
+
35
+
37
+ /* Allocate buffers on first decompress operation, most images are
36
+ if (bdrv_find_dirty_bitmap(bs, name)) {
38
+ * uncompressed and the memory overhead can be avoided. The buffers
37
+ error_setg(errp, "Bitmap already exists: %s", name);
39
+ * are freed in .bdrv_close().
38
+ return false;
40
+ */
39
+ }
41
+ if (!s->cluster_data) {
40
42
+ /* one more sector for decompressed data alignment */
41
if (s->qcow_version < 3) {
43
+ s->cluster_data = qemu_try_blockalign(bs->file->bs,
42
/* Without autoclear_features, we would always have to assume
44
+ QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512);
43
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
45
+ if (!s->cluster_data) {
46
+ return -ENOMEM;
47
+ }
48
+ }
49
+ if (!s->cluster_cache) {
50
+ s->cluster_cache = g_malloc(s->cluster_size);
51
+ }
52
+
53
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
54
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data,
55
nb_csectors);
56
diff --git a/block/qcow2.c b/block/qcow2.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
59
+++ b/block/qcow2.c
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
61
goto fail;
44
goto fail;
62
}
45
}
63
46
64
- s->cluster_cache = g_malloc(s->cluster_size);
47
- if (s->nb_bitmaps == 0) {
65
- /* one more sector for decompressed data alignment */
48
- return true;
66
- s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS
49
+ FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
67
- * s->cluster_size + 512);
50
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
68
- if (s->cluster_data == NULL) {
51
+ nb_bitmaps++;
69
- error_setg(errp, "Could not allocate temporary cluster buffer");
52
+ bitmap_directory_size +=
70
- ret = -ENOMEM;
53
+ calc_dir_entry_size(strlen(bdrv_dirty_bitmap_name(bitmap)), 0);
54
+ }
55
}
56
+ nb_bitmaps++;
57
+ bitmap_directory_size += calc_dir_entry_size(strlen(name), 0);
58
59
- if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) {
60
+ if (nb_bitmaps > QCOW2_MAX_BITMAPS) {
61
error_setg(errp,
62
"Maximum number of persistent bitmaps is already reached");
63
goto fail;
64
}
65
66
- if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) >
67
- QCOW2_MAX_BITMAP_DIRECTORY_SIZE)
68
- {
69
+ if (bitmap_directory_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
70
error_setg(errp, "Not enough space in the bitmap directory");
71
goto fail;
72
}
73
74
- qemu_co_mutex_lock(&s->lock);
75
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
76
- s->bitmap_directory_size, errp);
77
- qemu_co_mutex_unlock(&s->lock);
78
- if (bm_list == NULL) {
71
- goto fail;
79
- goto fail;
72
- }
80
- }
73
-
81
-
74
s->cluster_cache_offset = -1;
82
- found = find_bitmap_by_name(bm_list, name);
75
s->flags = flags;
83
- bitmap_list_free(bm_list);
76
84
- if (found) {
77
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
85
- error_setg(errp, "Bitmap with the same name is already stored");
78
if (s->refcount_block_cache) {
86
- goto fail;
79
qcow2_cache_destroy(bs, s->refcount_block_cache);
87
- }
80
}
88
-
81
- g_free(s->cluster_cache);
89
return true;
82
- qemu_vfree(s->cluster_data);
90
83
qcrypto_block_free(s->crypto);
91
fail:
84
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
85
return ret;
86
--
92
--
87
2.13.5
93
2.24.1
88
94
89
95
diff view generated by jsdifflib
New patch
1
Probably due to blind copy-pasting, we have several instances of "qocw2"
2
in our iotests. Fix them.
1
3
4
Reported-by: Maxim Levitsky <mlevitsk@redhat.com>
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20191107163708.833192-2-mreitz@redhat.com
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/060 | 2 +-
12
tests/qemu-iotests/061 | 2 +-
13
tests/qemu-iotests/062 | 2 +-
14
tests/qemu-iotests/066 | 2 +-
15
tests/qemu-iotests/068 | 2 +-
16
tests/qemu-iotests/108 | 2 +-
17
tests/qemu-iotests/138 | 2 +-
18
tests/qemu-iotests/261 | 2 +-
19
8 files changed, 8 insertions(+), 8 deletions(-)
20
21
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
22
index XXXXXXX..XXXXXXX 100755
23
--- a/tests/qemu-iotests/060
24
+++ b/tests/qemu-iotests/060
25
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
26
. ./common.rc
27
. ./common.filter
28
29
-# This tests qocw2-specific low-level functionality
30
+# This tests qcow2-specific low-level functionality
31
_supported_fmt qcow2
32
_supported_proto file
33
_supported_os Linux
34
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
35
index XXXXXXX..XXXXXXX 100755
36
--- a/tests/qemu-iotests/061
37
+++ b/tests/qemu-iotests/061
38
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
39
. ./common.rc
40
. ./common.filter
41
42
-# This tests qocw2-specific low-level functionality
43
+# This tests qcow2-specific low-level functionality
44
_supported_fmt qcow2
45
_supported_proto file
46
_supported_os Linux
47
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
48
index XXXXXXX..XXXXXXX 100755
49
--- a/tests/qemu-iotests/062
50
+++ b/tests/qemu-iotests/062
51
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
52
. ./common.rc
53
. ./common.filter
54
55
-# This tests qocw2-specific low-level functionality
56
+# This tests qcow2-specific low-level functionality
57
_supported_fmt qcow2
58
_supported_proto generic
59
60
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
61
index XXXXXXX..XXXXXXX 100755
62
--- a/tests/qemu-iotests/066
63
+++ b/tests/qemu-iotests/066
64
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
65
. ./common.rc
66
. ./common.filter
67
68
-# This tests qocw2-specific low-level functionality
69
+# This tests qcow2-specific low-level functionality
70
_supported_fmt qcow2
71
_supported_proto generic
72
73
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
74
index XXXXXXX..XXXXXXX 100755
75
--- a/tests/qemu-iotests/068
76
+++ b/tests/qemu-iotests/068
77
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
78
. ./common.rc
79
. ./common.filter
80
81
-# This tests qocw2-specific low-level functionality
82
+# This tests qcow2-specific low-level functionality
83
_supported_fmt qcow2
84
_supported_proto generic
85
86
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
87
index XXXXXXX..XXXXXXX 100755
88
--- a/tests/qemu-iotests/108
89
+++ b/tests/qemu-iotests/108
90
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
91
. ./common.rc
92
. ./common.filter
93
94
-# This tests qocw2-specific low-level functionality
95
+# This tests qcow2-specific low-level functionality
96
_supported_fmt qcow2
97
_supported_proto file
98
_supported_os Linux
99
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
100
index XXXXXXX..XXXXXXX 100755
101
--- a/tests/qemu-iotests/138
102
+++ b/tests/qemu-iotests/138
103
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
104
. ./common.rc
105
. ./common.filter
106
107
-# This tests qocw2-specific low-level functionality
108
+# This tests qcow2-specific low-level functionality
109
_supported_fmt qcow2
110
_supported_proto file
111
_supported_os Linux
112
diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261
113
index XXXXXXX..XXXXXXX 100755
114
--- a/tests/qemu-iotests/261
115
+++ b/tests/qemu-iotests/261
116
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
117
. ./common.rc
118
. ./common.filter
119
120
-# This tests qocw2-specific low-level functionality
121
+# This tests qcow2-specific low-level functionality
122
_supported_fmt qcow2
123
_supported_proto file
124
_supported_os Linux
125
--
126
2.24.1
127
128
diff view generated by jsdifflib
New patch
1
This is useful for tests that want to whitelist fields from dump-header
2
(with grep) but still print all header extensions.
1
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Message-id: 20191107163708.833192-3-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/qcow2.py | 5 +++++
10
1 file changed, 5 insertions(+)
11
12
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/qcow2.py
15
+++ b/tests/qemu-iotests/qcow2.py
16
@@ -XXX,XX +XXX,XX @@ def cmd_dump_header(fd):
17
h.dump()
18
h.dump_extensions()
19
20
+def cmd_dump_header_exts(fd):
21
+ h = QcowHeader(fd)
22
+ h.dump_extensions()
23
+
24
def cmd_set_header(fd, name, value):
25
try:
26
value = int(value, 0)
27
@@ -XXX,XX +XXX,XX @@ def cmd_set_feature_bit(fd, group, bit):
28
29
cmds = [
30
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
31
+ [ 'dump-header-exts', cmd_dump_header_exts, 0, 'Dump image header extensions' ],
32
[ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
33
[ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
34
[ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ],
35
--
36
2.24.1
37
38
diff view generated by jsdifflib
New patch
1
Print the feature fields as a set of bits so that filtering is easier.
1
2
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
5
Message-id: 20191107163708.833192-4-mreitz@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/031.out | 36 +++++++++----------
9
tests/qemu-iotests/036.out | 18 +++++-----
10
tests/qemu-iotests/039.out | 22 ++++++------
11
tests/qemu-iotests/060.out | 20 +++++------
12
tests/qemu-iotests/061.out | 72 ++++++++++++++++++-------------------
13
tests/qemu-iotests/137.out | 2 +-
14
tests/qemu-iotests/qcow2.py | 18 +++++++---
15
7 files changed, 99 insertions(+), 89 deletions(-)
16
17
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/031.out
20
+++ b/tests/qemu-iotests/031.out
21
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
22
refcount_table_clusters 1
23
nb_snapshots 0
24
snapshot_offset 0x0
25
-incompatible_features 0x0
26
-compatible_features 0x0
27
-autoclear_features 0x0
28
+incompatible_features []
29
+compatible_features []
30
+autoclear_features []
31
refcount_order 4
32
header_length 72
33
34
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
35
refcount_table_clusters 1
36
nb_snapshots 0
37
snapshot_offset 0x0
38
-incompatible_features 0x0
39
-compatible_features 0x0
40
-autoclear_features 0x0
41
+incompatible_features []
42
+compatible_features []
43
+autoclear_features []
44
refcount_order 4
45
header_length 72
46
47
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
48
refcount_table_clusters 1
49
nb_snapshots 0
50
snapshot_offset 0x0
51
-incompatible_features 0x0
52
-compatible_features 0x0
53
-autoclear_features 0x0
54
+incompatible_features []
55
+compatible_features []
56
+autoclear_features []
57
refcount_order 4
58
header_length 72
59
60
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
61
refcount_table_clusters 1
62
nb_snapshots 0
63
snapshot_offset 0x0
64
-incompatible_features 0x0
65
-compatible_features 0x0
66
-autoclear_features 0x0
67
+incompatible_features []
68
+compatible_features []
69
+autoclear_features []
70
refcount_order 4
71
header_length 104
72
73
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
74
refcount_table_clusters 1
75
nb_snapshots 0
76
snapshot_offset 0x0
77
-incompatible_features 0x0
78
-compatible_features 0x0
79
-autoclear_features 0x0
80
+incompatible_features []
81
+compatible_features []
82
+autoclear_features []
83
refcount_order 4
84
header_length 104
85
86
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
87
refcount_table_clusters 1
88
nb_snapshots 0
89
snapshot_offset 0x0
90
-incompatible_features 0x0
91
-compatible_features 0x0
92
-autoclear_features 0x0
93
+incompatible_features []
94
+compatible_features []
95
+autoclear_features []
96
refcount_order 4
97
header_length 104
98
99
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
100
index XXXXXXX..XXXXXXX 100644
101
--- a/tests/qemu-iotests/036.out
102
+++ b/tests/qemu-iotests/036.out
103
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
104
refcount_table_clusters 1
105
nb_snapshots 0
106
snapshot_offset 0x0
107
-incompatible_features 0x8000000000000000
108
-compatible_features 0x0
109
-autoclear_features 0x0
110
+incompatible_features [63]
111
+compatible_features []
112
+autoclear_features []
113
refcount_order 4
114
header_length 104
115
116
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
117
refcount_table_clusters 1
118
nb_snapshots 0
119
snapshot_offset 0x0
120
-incompatible_features 0x0
121
-compatible_features 0x0
122
-autoclear_features 0x8000000000000000
123
+incompatible_features []
124
+compatible_features []
125
+autoclear_features [63]
126
refcount_order 4
127
header_length 104
128
129
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
130
refcount_table_clusters 1
131
nb_snapshots 0
132
snapshot_offset 0x0
133
-incompatible_features 0x0
134
-compatible_features 0x0
135
-autoclear_features 0x0
136
+incompatible_features []
137
+compatible_features []
138
+autoclear_features []
139
refcount_order 4
140
header_length 104
141
142
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
143
index XXXXXXX..XXXXXXX 100644
144
--- a/tests/qemu-iotests/039.out
145
+++ b/tests/qemu-iotests/039.out
146
@@ -XXX,XX +XXX,XX @@ QA output created by 039
147
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
148
wrote 512/512 bytes at offset 0
149
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
150
-incompatible_features 0x0
151
+incompatible_features []
152
No errors were found on the image.
153
154
== Creating a dirty image file ==
155
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
156
wrote 512/512 bytes at offset 0
157
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
158
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
159
-incompatible_features 0x1
160
+incompatible_features [0]
161
ERROR cluster 5 refcount=0 reference=1
162
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
163
164
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
165
== Read-only access must still work ==
166
read 512/512 bytes at offset 0
167
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
-incompatible_features 0x1
169
+incompatible_features [0]
170
171
== Repairing the image file must succeed ==
172
ERROR cluster 5 refcount=0 reference=1
173
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
174
175
Double checking the fixed image now...
176
No errors were found on the image.
177
-incompatible_features 0x0
178
+incompatible_features []
179
180
== Data should still be accessible after repair ==
181
read 512/512 bytes at offset 0
182
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
183
wrote 512/512 bytes at offset 0
184
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
185
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
186
-incompatible_features 0x1
187
+incompatible_features [0]
188
ERROR cluster 5 refcount=0 reference=1
189
Rebuilding refcount structure
190
Repairing cluster 1 refcount=1 reference=0
191
Repairing cluster 2 refcount=1 reference=0
192
wrote 512/512 bytes at offset 0
193
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
-incompatible_features 0x0
195
+incompatible_features []
196
197
== Creating an image file with lazy_refcounts=off ==
198
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
199
wrote 512/512 bytes at offset 0
200
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
201
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
202
-incompatible_features 0x0
203
+incompatible_features []
204
No errors were found on the image.
205
206
== Committing to a backing file with lazy_refcounts=on ==
207
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
208
wrote 512/512 bytes at offset 0
209
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
210
Image committed.
211
-incompatible_features 0x0
212
-incompatible_features 0x0
213
+incompatible_features []
214
+incompatible_features []
215
No errors were found on the image.
216
No errors were found on the image.
217
218
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
219
wrote 512/512 bytes at offset 0
220
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
221
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
222
-incompatible_features 0x1
223
+incompatible_features [0]
224
ERROR cluster 5 refcount=0 reference=1
225
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
226
227
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
228
wrote 512/512 bytes at offset 0
229
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
230
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
231
-incompatible_features 0x0
232
+incompatible_features []
233
No errors were found on the image.
234
*** done
235
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
236
index XXXXXXX..XXXXXXX 100644
237
--- a/tests/qemu-iotests/060.out
238
+++ b/tests/qemu-iotests/060.out
239
@@ -XXX,XX +XXX,XX @@ ERROR cluster 3 refcount=1 reference=3
240
241
1 errors were found on the image.
242
Data may be corrupted, or further writes to the image may corrupt it.
243
-incompatible_features 0x0
244
+incompatible_features []
245
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed
246
write failed: Input/output error
247
-incompatible_features 0x2
248
+incompatible_features [1]
249
image: TEST_DIR/t.IMGFMT
250
file format: IMGFMT
251
virtual size: 64 MiB (67108864 bytes)
252
@@ -XXX,XX +XXX,XX @@ ERROR cluster 2 refcount=1 reference=2
253
254
2 errors were found on the image.
255
Data may be corrupted, or further writes to the image may corrupt it.
256
-incompatible_features 0x0
257
+incompatible_features []
258
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount block); further corruption events will be suppressed
259
write failed: Input/output error
260
-incompatible_features 0x2
261
+incompatible_features [1]
262
ERROR refcount block 0 refcount=2
263
ERROR cluster 2 refcount=1 reference=2
264
Rebuilding refcount structure
265
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
266
267
Double checking the fixed image now...
268
No errors were found on the image.
269
-incompatible_features 0x0
270
+incompatible_features []
271
wrote 512/512 bytes at offset 0
272
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
-incompatible_features 0x0
274
+incompatible_features []
275
276
=== Testing cluster data reference into inactive L2 table ===
277
278
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
279
280
1 leaked clusters were found on the image.
281
This means waste of disk space, but no harm to data.
282
-incompatible_features 0x0
283
+incompatible_features []
284
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with inactive L2 table); further corruption events will be suppressed
285
write failed: Input/output error
286
-incompatible_features 0x2
287
+incompatible_features [1]
288
ERROR cluster 4 refcount=1 reference=2
289
Leaked cluster 9 refcount=1 reference=0
290
Repairing cluster 4 refcount=1 reference=2
291
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
292
293
Double checking the fixed image now...
294
No errors were found on the image.
295
-incompatible_features 0x0
296
+incompatible_features []
297
wrote 512/512 bytes at offset 0
298
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
299
-incompatible_features 0x0
300
+incompatible_features []
301
read 512/512 bytes at offset 0
302
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
303
No errors were found on the image.
304
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
305
index XXXXXXX..XXXXXXX 100644
306
--- a/tests/qemu-iotests/061.out
307
+++ b/tests/qemu-iotests/061.out
308
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
309
refcount_table_clusters 1
310
nb_snapshots 0
311
snapshot_offset 0x0
312
-incompatible_features 0x0
313
-compatible_features 0x1
314
-autoclear_features 0x0
315
+incompatible_features []
316
+compatible_features [0]
317
+autoclear_features []
318
refcount_order 4
319
header_length 104
320
321
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
322
refcount_table_clusters 1
323
nb_snapshots 0
324
snapshot_offset 0x0
325
-incompatible_features 0x0
326
-compatible_features 0x0
327
-autoclear_features 0x0
328
+incompatible_features []
329
+compatible_features []
330
+autoclear_features []
331
refcount_order 4
332
header_length 72
333
334
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
335
refcount_table_clusters 1
336
nb_snapshots 0
337
snapshot_offset 0x0
338
-incompatible_features 0x0
339
-compatible_features 0x1
340
-autoclear_features 0x0
341
+incompatible_features []
342
+compatible_features [0]
343
+autoclear_features []
344
refcount_order 4
345
header_length 104
346
347
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
348
refcount_table_clusters 1
349
nb_snapshots 0
350
snapshot_offset 0x0
351
-incompatible_features 0x0
352
-compatible_features 0x0
353
-autoclear_features 0x0
354
+incompatible_features []
355
+compatible_features []
356
+autoclear_features []
357
refcount_order 4
358
header_length 72
359
360
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
361
refcount_table_clusters 1
362
nb_snapshots 0
363
snapshot_offset 0x0
364
-incompatible_features 0x1
365
-compatible_features 0x1
366
-autoclear_features 0x0
367
+incompatible_features [0]
368
+compatible_features [0]
369
+autoclear_features []
370
refcount_order 4
371
header_length 104
372
373
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x80000
374
refcount_table_clusters 1
375
nb_snapshots 0
376
snapshot_offset 0x0
377
-incompatible_features 0x0
378
-compatible_features 0x0
379
-autoclear_features 0x0
380
+incompatible_features []
381
+compatible_features []
382
+autoclear_features []
383
refcount_order 4
384
header_length 72
385
386
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
387
refcount_table_clusters 1
388
nb_snapshots 0
389
snapshot_offset 0x0
390
-incompatible_features 0x0
391
-compatible_features 0x40000000000
392
-autoclear_features 0x40000000000
393
+incompatible_features []
394
+compatible_features [42]
395
+autoclear_features [42]
396
refcount_order 4
397
header_length 104
398
399
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
400
refcount_table_clusters 1
401
nb_snapshots 0
402
snapshot_offset 0x0
403
-incompatible_features 0x0
404
-compatible_features 0x0
405
-autoclear_features 0x0
406
+incompatible_features []
407
+compatible_features []
408
+autoclear_features []
409
refcount_order 4
410
header_length 72
411
412
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
413
refcount_table_clusters 1
414
nb_snapshots 0
415
snapshot_offset 0x0
416
-incompatible_features 0x0
417
-compatible_features 0x0
418
-autoclear_features 0x0
419
+incompatible_features []
420
+compatible_features []
421
+autoclear_features []
422
refcount_order 4
423
header_length 72
424
425
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
426
refcount_table_clusters 1
427
nb_snapshots 0
428
snapshot_offset 0x0
429
-incompatible_features 0x0
430
-compatible_features 0x1
431
-autoclear_features 0x0
432
+incompatible_features []
433
+compatible_features [0]
434
+autoclear_features []
435
refcount_order 4
436
header_length 104
437
438
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
439
refcount_table_clusters 1
440
nb_snapshots 0
441
snapshot_offset 0x0
442
-incompatible_features 0x1
443
-compatible_features 0x1
444
-autoclear_features 0x0
445
+incompatible_features [0]
446
+compatible_features [0]
447
+autoclear_features []
448
refcount_order 4
449
header_length 104
450
451
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x80000
452
refcount_table_clusters 1
453
nb_snapshots 0
454
snapshot_offset 0x0
455
-incompatible_features 0x0
456
-compatible_features 0x0
457
-autoclear_features 0x0
458
+incompatible_features []
459
+compatible_features []
460
+autoclear_features []
461
refcount_order 4
462
header_length 104
463
464
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
465
index XXXXXXX..XXXXXXX 100644
466
--- a/tests/qemu-iotests/137.out
467
+++ b/tests/qemu-iotests/137.out
468
@@ -XXX,XX +XXX,XX @@ qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are
469
wrote 512/512 bytes at offset 0
470
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
471
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
472
-incompatible_features 0x0
473
+incompatible_features []
474
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
475
wrote 65536/65536 bytes at offset 0
476
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
477
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
478
index XXXXXXX..XXXXXXX 100755
479
--- a/tests/qemu-iotests/qcow2.py
480
+++ b/tests/qemu-iotests/qcow2.py
481
@@ -XXX,XX +XXX,XX @@ class QcowHeader:
482
[ uint64_t, '%#x', 'snapshot_offset' ],
483
484
# Version 3 header fields
485
- [ uint64_t, '%#x', 'incompatible_features' ],
486
- [ uint64_t, '%#x', 'compatible_features' ],
487
- [ uint64_t, '%#x', 'autoclear_features' ],
488
+ [ uint64_t, 'mask', 'incompatible_features' ],
489
+ [ uint64_t, 'mask', 'compatible_features' ],
490
+ [ uint64_t, 'mask', 'autoclear_features' ],
491
[ uint32_t, '%d', 'refcount_order' ],
492
[ uint32_t, '%d', 'header_length' ],
493
];
494
@@ -XXX,XX +XXX,XX @@ class QcowHeader:
495
496
def dump(self):
497
for f in QcowHeader.fields:
498
- print("%-25s" % f[2], f[1] % self.__dict__[f[2]])
499
+ value = self.__dict__[f[2]]
500
+ if f[1] == 'mask':
501
+ bits = []
502
+ for bit in range(64):
503
+ if value & (1 << bit):
504
+ bits.append(bit)
505
+ value_str = str(bits)
506
+ else:
507
+ value_str = f[1] % value
508
+
509
+ print("%-25s" % f[2], value_str)
510
print("")
511
512
def dump_extensions(self):
513
--
514
2.24.1
515
516
diff view generated by jsdifflib
1
The minimum Python version supported by QEMU is 2.6. The argparse
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
standard library module was only added in Python 2.7. Many scripts
2
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
3
would like to use argparse because it supports command-line
3
Message-id: 20191107163708.833192-5-mreitz@redhat.com
4
sub-commands.
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
6
tests/qemu-iotests/common.filter | 24 ++++++++++++++++++++++++
7
1 file changed, 24 insertions(+)
5
8
6
This patch adds argparse. See the top of argparse.py for details.
9
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
7
10
index XXXXXXX..XXXXXXX 100644
8
Suggested-by: Daniel P. Berrange <berrange@redhat.com>
11
--- a/tests/qemu-iotests/common.filter
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
+++ b/tests/qemu-iotests/common.filter
10
Acked-by: John Snow <jsnow@redhat.com>
13
@@ -XXX,XX +XXX,XX @@ _filter_qmp_empty_return()
11
Message-id: 20170825155732.15665-2-stefanha@redhat.com
14
grep -v '{"return": {}}'
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
}
13
---
16
14
COPYING.PYTHON | 270 ++++++
17
+_filter_json_filename()
15
scripts/argparse.py | 2406 +++++++++++++++++++++++++++++++++++++++++++++++++++
18
+{
16
2 files changed, 2676 insertions(+)
19
+ $PYTHON -c 'import sys
17
create mode 100644 COPYING.PYTHON
20
+result, *fnames = sys.stdin.read().split("json:{")
18
create mode 100644 scripts/argparse.py
21
+depth = 0
19
22
+for fname in fnames:
20
diff --git a/COPYING.PYTHON b/COPYING.PYTHON
23
+ depth += 1 # For the opening brace in the split separator
21
new file mode 100644
24
+ for chr_i, chr in enumerate(fname):
22
index XXXXXXX..XXXXXXX
25
+ if chr == "{":
23
--- /dev/null
26
+ depth += 1
24
+++ b/COPYING.PYTHON
27
+ elif chr == "}":
25
@@ -XXX,XX +XXX,XX @@
28
+ depth -= 1
26
+A. HISTORY OF THE SOFTWARE
29
+ if depth == 0:
27
+==========================
28
+
29
+Python was created in the early 1990s by Guido van Rossum at Stichting
30
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
31
+as a successor of a language called ABC. Guido remains Python's
32
+principal author, although it includes many contributions from others.
33
+
34
+In 1995, Guido continued his work on Python at the Corporation for
35
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
36
+in Reston, Virginia where he released several versions of the
37
+software.
38
+
39
+In May 2000, Guido and the Python core development team moved to
40
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
41
+year, the PythonLabs team moved to Digital Creations (now Zope
42
+Corporation, see http://www.zope.com). In 2001, the Python Software
43
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
44
+non-profit organization created specifically to own Python-related
45
+Intellectual Property. Zope Corporation is a sponsoring member of
46
+the PSF.
47
+
48
+All Python releases are Open Source (see http://www.opensource.org for
49
+the Open Source Definition). Historically, most, but not all, Python
50
+releases have also been GPL-compatible; the table below summarizes
51
+the various releases.
52
+
53
+ Release Derived Year Owner GPL-
54
+ from compatible? (1)
55
+
56
+ 0.9.0 thru 1.2 1991-1995 CWI yes
57
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
58
+ 1.6 1.5.2 2000 CNRI no
59
+ 2.0 1.6 2000 BeOpen.com no
60
+ 1.6.1 1.6 2001 CNRI yes (2)
61
+ 2.1 2.0+1.6.1 2001 PSF no
62
+ 2.0.1 2.0+1.6.1 2001 PSF yes
63
+ 2.1.1 2.1+2.0.1 2001 PSF yes
64
+ 2.2 2.1.1 2001 PSF yes
65
+ 2.1.2 2.1.1 2002 PSF yes
66
+ 2.1.3 2.1.2 2002 PSF yes
67
+ 2.2.1 2.2 2002 PSF yes
68
+ 2.2.2 2.2.1 2002 PSF yes
69
+ 2.2.3 2.2.2 2003 PSF yes
70
+ 2.3 2.2.2 2002-2003 PSF yes
71
+ 2.3.1 2.3 2002-2003 PSF yes
72
+ 2.3.2 2.3.1 2002-2003 PSF yes
73
+ 2.3.3 2.3.2 2002-2003 PSF yes
74
+ 2.3.4 2.3.3 2004 PSF yes
75
+ 2.3.5 2.3.4 2005 PSF yes
76
+ 2.4 2.3 2004 PSF yes
77
+ 2.4.1 2.4 2005 PSF yes
78
+ 2.4.2 2.4.1 2005 PSF yes
79
+ 2.4.3 2.4.2 2006 PSF yes
80
+ 2.5 2.4 2006 PSF yes
81
+ 2.7 2.6 2010 PSF yes
82
+
83
+Footnotes:
84
+
85
+(1) GPL-compatible doesn't mean that we're distributing Python under
86
+ the GPL. All Python licenses, unlike the GPL, let you distribute
87
+ a modified version without making your changes open source. The
88
+ GPL-compatible licenses make it possible to combine Python with
89
+ other software that is released under the GPL; the others don't.
90
+
91
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
92
+ because its license has a choice of law clause. According to
93
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
94
+ is "not incompatible" with the GPL.
95
+
96
+Thanks to the many outside volunteers who have worked under Guido's
97
+direction to make these releases possible.
98
+
99
+
100
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
101
+===============================================================
102
+
103
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
104
+--------------------------------------------
105
+
106
+1. This LICENSE AGREEMENT is between the Python Software Foundation
107
+("PSF"), and the Individual or Organization ("Licensee") accessing and
108
+otherwise using this software ("Python") in source or binary form and
109
+its associated documentation.
110
+
111
+2. Subject to the terms and conditions of this License Agreement, PSF
112
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
113
+license to reproduce, analyze, test, perform and/or display publicly,
114
+prepare derivative works, distribute, and otherwise use Python
115
+alone or in any derivative version, provided, however, that PSF's
116
+License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
117
+2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
118
+Reserved" are retained in Python alone or in any derivative version
119
+prepared by Licensee.
120
+
121
+3. In the event Licensee prepares a derivative work that is based on
122
+or incorporates Python or any part thereof, and wants to make
123
+the derivative work available to others as provided herein, then
124
+Licensee hereby agrees to include in any such work a brief summary of
125
+the changes made to Python.
126
+
127
+4. PSF is making Python available to Licensee on an "AS IS"
128
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
129
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
130
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
131
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
132
+INFRINGE ANY THIRD PARTY RIGHTS.
133
+
134
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
135
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
136
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
137
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
138
+
139
+6. This License Agreement will automatically terminate upon a material
140
+breach of its terms and conditions.
141
+
142
+7. Nothing in this License Agreement shall be deemed to create any
143
+relationship of agency, partnership, or joint venture between PSF and
144
+Licensee. This License Agreement does not grant permission to use PSF
145
+trademarks or trade name in a trademark sense to endorse or promote
146
+products or services of Licensee, or any third party.
147
+
148
+8. By copying, installing or otherwise using Python, Licensee
149
+agrees to be bound by the terms and conditions of this License
150
+Agreement.
151
+
152
+
153
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
154
+-------------------------------------------
155
+
156
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
157
+
158
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
159
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
160
+Individual or Organization ("Licensee") accessing and otherwise using
161
+this software in source or binary form and its associated
162
+documentation ("the Software").
163
+
164
+2. Subject to the terms and conditions of this BeOpen Python License
165
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
166
+royalty-free, world-wide license to reproduce, analyze, test, perform
167
+and/or display publicly, prepare derivative works, distribute, and
168
+otherwise use the Software alone or in any derivative version,
169
+provided, however, that the BeOpen Python License is retained in the
170
+Software, alone or in any derivative version prepared by Licensee.
171
+
172
+3. BeOpen is making the Software available to Licensee on an "AS IS"
173
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
174
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
175
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
176
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
177
+INFRINGE ANY THIRD PARTY RIGHTS.
178
+
179
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
180
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
181
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
182
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
183
+
184
+5. This License Agreement will automatically terminate upon a material
185
+breach of its terms and conditions.
186
+
187
+6. This License Agreement shall be governed by and interpreted in all
188
+respects by the law of the State of California, excluding conflict of
189
+law provisions. Nothing in this License Agreement shall be deemed to
190
+create any relationship of agency, partnership, or joint venture
191
+between BeOpen and Licensee. This License Agreement does not grant
192
+permission to use BeOpen trademarks or trade names in a trademark
193
+sense to endorse or promote products or services of Licensee, or any
194
+third party. As an exception, the "BeOpen Python" logos available at
195
+http://www.pythonlabs.com/logos.html may be used according to the
196
+permissions granted on that web page.
197
+
198
+7. By copying, installing or otherwise using the software, Licensee
199
+agrees to be bound by the terms and conditions of this License
200
+Agreement.
201
+
202
+
203
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
204
+---------------------------------------
205
+
206
+1. This LICENSE AGREEMENT is between the Corporation for National
207
+Research Initiatives, having an office at 1895 Preston White Drive,
208
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
209
+("Licensee") accessing and otherwise using Python 1.6.1 software in
210
+source or binary form and its associated documentation.
211
+
212
+2. Subject to the terms and conditions of this License Agreement, CNRI
213
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
214
+license to reproduce, analyze, test, perform and/or display publicly,
215
+prepare derivative works, distribute, and otherwise use Python 1.6.1
216
+alone or in any derivative version, provided, however, that CNRI's
217
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
218
+1995-2001 Corporation for National Research Initiatives; All Rights
219
+Reserved" are retained in Python 1.6.1 alone or in any derivative
220
+version prepared by Licensee. Alternately, in lieu of CNRI's License
221
+Agreement, Licensee may substitute the following text (omitting the
222
+quotes): "Python 1.6.1 is made available subject to the terms and
223
+conditions in CNRI's License Agreement. This Agreement together with
224
+Python 1.6.1 may be located on the Internet using the following
225
+unique, persistent identifier (known as a handle): 1895.22/1013. This
226
+Agreement may also be obtained from a proxy server on the Internet
227
+using the following URL: http://hdl.handle.net/1895.22/1013".
228
+
229
+3. In the event Licensee prepares a derivative work that is based on
230
+or incorporates Python 1.6.1 or any part thereof, and wants to make
231
+the derivative work available to others as provided herein, then
232
+Licensee hereby agrees to include in any such work a brief summary of
233
+the changes made to Python 1.6.1.
234
+
235
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
236
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
237
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
238
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
239
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
240
+INFRINGE ANY THIRD PARTY RIGHTS.
241
+
242
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
243
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
244
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
245
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
246
+
247
+6. This License Agreement will automatically terminate upon a material
248
+breach of its terms and conditions.
249
+
250
+7. This License Agreement shall be governed by the federal
251
+intellectual property law of the United States, including without
252
+limitation the federal copyright law, and, to the extent such
253
+U.S. federal law does not apply, by the law of the Commonwealth of
254
+Virginia, excluding Virginia's conflict of law provisions.
255
+Notwithstanding the foregoing, with regard to derivative works based
256
+on Python 1.6.1 that incorporate non-separable material that was
257
+previously distributed under the GNU General Public License (GPL), the
258
+law of the Commonwealth of Virginia shall govern this License
259
+Agreement only as to issues arising under or with respect to
260
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
261
+License Agreement shall be deemed to create any relationship of
262
+agency, partnership, or joint venture between CNRI and Licensee. This
263
+License Agreement does not grant permission to use CNRI trademarks or
264
+trade name in a trademark sense to endorse or promote products or
265
+services of Licensee, or any third party.
266
+
267
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
268
+installing or otherwise using Python 1.6.1, Licensee agrees to be
269
+bound by the terms and conditions of this License Agreement.
270
+
271
+ ACCEPT
272
+
273
+
274
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
275
+--------------------------------------------------
276
+
277
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
278
+The Netherlands. All rights reserved.
279
+
280
+Permission to use, copy, modify, and distribute this software and its
281
+documentation for any purpose and without fee is hereby granted,
282
+provided that the above copyright notice appear in all copies and that
283
+both that copyright notice and this permission notice appear in
284
+supporting documentation, and that the name of Stichting Mathematisch
285
+Centrum or CWI not be used in advertising or publicity pertaining to
286
+distribution of the software without specific, written prior
287
+permission.
288
+
289
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
290
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
291
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
292
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
293
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
294
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
295
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
296
diff --git a/scripts/argparse.py b/scripts/argparse.py
297
new file mode 100644
298
index XXXXXXX..XXXXXXX
299
--- /dev/null
300
+++ b/scripts/argparse.py
301
@@ -XXX,XX +XXX,XX @@
302
+# This is a local copy of the standard library argparse module taken from PyPI.
303
+# It is licensed under the Python Software Foundation License. This is a
304
+# fallback for Python 2.6 which does not include this module. Python 2.7+ and
305
+# 3+ will never load this module because built-in modules are loaded before
306
+# anything in sys.path.
307
+#
308
+# If your script is not located in the same directory as this file, import it
309
+# like this:
310
+#
311
+# import os
312
+# import sys
313
+# sys.path.append(os.path.join(os.path.dirname(__file__), ..., 'scripts'))
314
+# import argparse
315
+
316
+# Author: Steven J. Bethard <steven.bethard@gmail.com>.
317
+# Maintainer: Thomas Waldmann <tw@waldmann-edv.de>
318
+
319
+"""Command-line parsing library
320
+
321
+This module is an optparse-inspired command-line parsing library that:
322
+
323
+ - handles both optional and positional arguments
324
+ - produces highly informative usage messages
325
+ - supports parsers that dispatch to sub-parsers
326
+
327
+The following is a simple usage example that sums integers from the
328
+command-line and writes the result to a file::
329
+
330
+ parser = argparse.ArgumentParser(
331
+ description='sum the integers at the command line')
332
+ parser.add_argument(
333
+ 'integers', metavar='int', nargs='+', type=int,
334
+ help='an integer to be summed')
335
+ parser.add_argument(
336
+ '--log', default=sys.stdout, type=argparse.FileType('w'),
337
+ help='the file where the sum should be written')
338
+ args = parser.parse_args()
339
+ args.log.write('%s' % sum(args.integers))
340
+ args.log.close()
341
+
342
+The module contains the following public classes:
343
+
344
+ - ArgumentParser -- The main entry point for command-line parsing. As the
345
+ example above shows, the add_argument() method is used to populate
346
+ the parser with actions for optional and positional arguments. Then
347
+ the parse_args() method is invoked to convert the args at the
348
+ command-line into an object with attributes.
349
+
350
+ - ArgumentError -- The exception raised by ArgumentParser objects when
351
+ there are errors with the parser's actions. Errors raised while
352
+ parsing the command-line are caught by ArgumentParser and emitted
353
+ as command-line messages.
354
+
355
+ - FileType -- A factory for defining types of files to be created. As the
356
+ example above shows, instances of FileType are typically passed as
357
+ the type= argument of add_argument() calls.
358
+
359
+ - Action -- The base class for parser actions. Typically actions are
360
+ selected by passing strings like 'store_true' or 'append_const' to
361
+ the action= argument of add_argument(). However, for greater
362
+ customization of ArgumentParser actions, subclasses of Action may
363
+ be defined and passed as the action= argument.
364
+
365
+ - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
366
+ ArgumentDefaultsHelpFormatter -- Formatter classes which
367
+ may be passed as the formatter_class= argument to the
368
+ ArgumentParser constructor. HelpFormatter is the default,
369
+ RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
370
+ not to change the formatting for help text, and
371
+ ArgumentDefaultsHelpFormatter adds information about argument defaults
372
+ to the help.
373
+
374
+All other classes in this module are considered implementation details.
375
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
376
+considered public as object names -- the API of the formatter objects is
377
+still considered an implementation detail.)
378
+"""
379
+
380
+__version__ = '1.4.0' # we use our own version number independant of the
381
+ # one in stdlib and we release this on pypi.
382
+
383
+__external_lib__ = True # to make sure the tests really test THIS lib,
384
+ # not the builtin one in Python stdlib
385
+
386
+__all__ = [
387
+ 'ArgumentParser',
388
+ 'ArgumentError',
389
+ 'ArgumentTypeError',
390
+ 'FileType',
391
+ 'HelpFormatter',
392
+ 'ArgumentDefaultsHelpFormatter',
393
+ 'RawDescriptionHelpFormatter',
394
+ 'RawTextHelpFormatter',
395
+ 'Namespace',
396
+ 'Action',
397
+ 'ONE_OR_MORE',
398
+ 'OPTIONAL',
399
+ 'PARSER',
400
+ 'REMAINDER',
401
+ 'SUPPRESS',
402
+ 'ZERO_OR_MORE',
403
+]
404
+
405
+
406
+import copy as _copy
407
+import os as _os
408
+import re as _re
409
+import sys as _sys
410
+import textwrap as _textwrap
411
+
412
+from gettext import gettext as _
413
+
414
+try:
415
+ set
416
+except NameError:
417
+ # for python < 2.4 compatibility (sets module is there since 2.3):
418
+ from sets import Set as set
419
+
420
+try:
421
+ basestring
422
+except NameError:
423
+ basestring = str
424
+
425
+try:
426
+ sorted
427
+except NameError:
428
+ # for python < 2.4 compatibility:
429
+ def sorted(iterable, reverse=False):
430
+ result = list(iterable)
431
+ result.sort()
432
+ if reverse:
433
+ result.reverse()
434
+ return result
435
+
436
+
437
+def _callable(obj):
438
+ return hasattr(obj, '__call__') or hasattr(obj, '__bases__')
439
+
440
+
441
+SUPPRESS = '==SUPPRESS=='
442
+
443
+OPTIONAL = '?'
444
+ZERO_OR_MORE = '*'
445
+ONE_OR_MORE = '+'
446
+PARSER = 'A...'
447
+REMAINDER = '...'
448
+_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
449
+
450
+# =============================
451
+# Utility functions and classes
452
+# =============================
453
+
454
+class _AttributeHolder(object):
455
+ """Abstract base class that provides __repr__.
456
+
457
+ The __repr__ method returns a string in the format::
458
+ ClassName(attr=name, attr=name, ...)
459
+ The attributes are determined either by a class-level attribute,
460
+ '_kwarg_names', or by inspecting the instance __dict__.
461
+ """
462
+
463
+ def __repr__(self):
464
+ type_name = type(self).__name__
465
+ arg_strings = []
466
+ for arg in self._get_args():
467
+ arg_strings.append(repr(arg))
468
+ for name, value in self._get_kwargs():
469
+ arg_strings.append('%s=%r' % (name, value))
470
+ return '%s(%s)' % (type_name, ', '.join(arg_strings))
471
+
472
+ def _get_kwargs(self):
473
+ return sorted(self.__dict__.items())
474
+
475
+ def _get_args(self):
476
+ return []
477
+
478
+
479
+def _ensure_value(namespace, name, value):
480
+ if getattr(namespace, name, None) is None:
481
+ setattr(namespace, name, value)
482
+ return getattr(namespace, name)
483
+
484
+
485
+# ===============
486
+# Formatting Help
487
+# ===============
488
+
489
+class HelpFormatter(object):
490
+ """Formatter for generating usage messages and argument help strings.
491
+
492
+ Only the name of this class is considered a public API. All the methods
493
+ provided by the class are considered an implementation detail.
494
+ """
495
+
496
+ def __init__(self,
497
+ prog,
498
+ indent_increment=2,
499
+ max_help_position=24,
500
+ width=None):
501
+
502
+ # default setting for width
503
+ if width is None:
504
+ try:
505
+ width = int(_os.environ['COLUMNS'])
506
+ except (KeyError, ValueError):
507
+ width = 80
508
+ width -= 2
509
+
510
+ self._prog = prog
511
+ self._indent_increment = indent_increment
512
+ self._max_help_position = max_help_position
513
+ self._width = width
514
+
515
+ self._current_indent = 0
516
+ self._level = 0
517
+ self._action_max_length = 0
518
+
519
+ self._root_section = self._Section(self, None)
520
+ self._current_section = self._root_section
521
+
522
+ self._whitespace_matcher = _re.compile(r'\s+')
523
+ self._long_break_matcher = _re.compile(r'\n\n\n+')
524
+
525
+ # ===============================
526
+ # Section and indentation methods
527
+ # ===============================
528
+ def _indent(self):
529
+ self._current_indent += self._indent_increment
530
+ self._level += 1
531
+
532
+ def _dedent(self):
533
+ self._current_indent -= self._indent_increment
534
+ assert self._current_indent >= 0, 'Indent decreased below 0.'
535
+ self._level -= 1
536
+
537
+ class _Section(object):
538
+
539
+ def __init__(self, formatter, parent, heading=None):
540
+ self.formatter = formatter
541
+ self.parent = parent
542
+ self.heading = heading
543
+ self.items = []
544
+
545
+ def format_help(self):
546
+ # format the indented section
547
+ if self.parent is not None:
548
+ self.formatter._indent()
549
+ join = self.formatter._join_parts
550
+ for func, args in self.items:
551
+ func(*args)
552
+ item_help = join([func(*args) for func, args in self.items])
553
+ if self.parent is not None:
554
+ self.formatter._dedent()
555
+
556
+ # return nothing if the section was empty
557
+ if not item_help:
558
+ return ''
559
+
560
+ # add the heading if the section was non-empty
561
+ if self.heading is not SUPPRESS and self.heading is not None:
562
+ current_indent = self.formatter._current_indent
563
+ heading = '%*s%s:\n' % (current_indent, '', self.heading)
564
+ else:
565
+ heading = ''
566
+
567
+ # join the section-initial newline, the heading and the help
568
+ return join(['\n', heading, item_help, '\n'])
569
+
570
+ def _add_item(self, func, args):
571
+ self._current_section.items.append((func, args))
572
+
573
+ # ========================
574
+ # Message building methods
575
+ # ========================
576
+ def start_section(self, heading):
577
+ self._indent()
578
+ section = self._Section(self, self._current_section, heading)
579
+ self._add_item(section.format_help, [])
580
+ self._current_section = section
581
+
582
+ def end_section(self):
583
+ self._current_section = self._current_section.parent
584
+ self._dedent()
585
+
586
+ def add_text(self, text):
587
+ if text is not SUPPRESS and text is not None:
588
+ self._add_item(self._format_text, [text])
589
+
590
+ def add_usage(self, usage, actions, groups, prefix=None):
591
+ if usage is not SUPPRESS:
592
+ args = usage, actions, groups, prefix
593
+ self._add_item(self._format_usage, args)
594
+
595
+ def add_argument(self, action):
596
+ if action.help is not SUPPRESS:
597
+
598
+ # find all invocations
599
+ get_invocation = self._format_action_invocation
600
+ invocations = [get_invocation(action)]
601
+ for subaction in self._iter_indented_subactions(action):
602
+ invocations.append(get_invocation(subaction))
603
+
604
+ # update the maximum item length
605
+ invocation_length = max([len(s) for s in invocations])
606
+ action_length = invocation_length + self._current_indent
607
+ self._action_max_length = max(self._action_max_length,
608
+ action_length)
609
+
610
+ # add the item to the list
611
+ self._add_item(self._format_action, [action])
612
+
613
+ def add_arguments(self, actions):
614
+ for action in actions:
615
+ self.add_argument(action)
616
+
617
+ # =======================
618
+ # Help-formatting methods
619
+ # =======================
620
+ def format_help(self):
621
+ help = self._root_section.format_help()
622
+ if help:
623
+ help = self._long_break_matcher.sub('\n\n', help)
624
+ help = help.strip('\n') + '\n'
625
+ return help
626
+
627
+ def _join_parts(self, part_strings):
628
+ return ''.join([part
629
+ for part in part_strings
630
+ if part and part is not SUPPRESS])
631
+
632
+ def _format_usage(self, usage, actions, groups, prefix):
633
+ if prefix is None:
634
+ prefix = _('usage: ')
635
+
636
+ # if usage is specified, use that
637
+ if usage is not None:
638
+ usage = usage % dict(prog=self._prog)
639
+
640
+ # if no optionals or positionals are available, usage is just prog
641
+ elif usage is None and not actions:
642
+ usage = '%(prog)s' % dict(prog=self._prog)
643
+
644
+ # if optionals and positionals are available, calculate usage
645
+ elif usage is None:
646
+ prog = '%(prog)s' % dict(prog=self._prog)
647
+
648
+ # split optionals from positionals
649
+ optionals = []
650
+ positionals = []
651
+ for action in actions:
652
+ if action.option_strings:
653
+ optionals.append(action)
654
+ else:
655
+ positionals.append(action)
656
+
657
+ # build full usage string
658
+ format = self._format_actions_usage
659
+ action_usage = format(optionals + positionals, groups)
660
+ usage = ' '.join([s for s in [prog, action_usage] if s])
661
+
662
+ # wrap the usage parts if it's too long
663
+ text_width = self._width - self._current_indent
664
+ if len(prefix) + len(usage) > text_width:
665
+
666
+ # break usage into wrappable parts
667
+ part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
668
+ opt_usage = format(optionals, groups)
669
+ pos_usage = format(positionals, groups)
670
+ opt_parts = _re.findall(part_regexp, opt_usage)
671
+ pos_parts = _re.findall(part_regexp, pos_usage)
672
+ assert ' '.join(opt_parts) == opt_usage
673
+ assert ' '.join(pos_parts) == pos_usage
674
+
675
+ # helper for wrapping lines
676
+ def get_lines(parts, indent, prefix=None):
677
+ lines = []
678
+ line = []
679
+ if prefix is not None:
680
+ line_len = len(prefix) - 1
681
+ else:
682
+ line_len = len(indent) - 1
683
+ for part in parts:
684
+ if line_len + 1 + len(part) > text_width:
685
+ lines.append(indent + ' '.join(line))
686
+ line = []
687
+ line_len = len(indent) - 1
688
+ line.append(part)
689
+ line_len += len(part) + 1
690
+ if line:
691
+ lines.append(indent + ' '.join(line))
692
+ if prefix is not None:
693
+ lines[0] = lines[0][len(indent):]
694
+ return lines
695
+
696
+ # if prog is short, follow it with optionals or positionals
697
+ if len(prefix) + len(prog) <= 0.75 * text_width:
698
+ indent = ' ' * (len(prefix) + len(prog) + 1)
699
+ if opt_parts:
700
+ lines = get_lines([prog] + opt_parts, indent, prefix)
701
+ lines.extend(get_lines(pos_parts, indent))
702
+ elif pos_parts:
703
+ lines = get_lines([prog] + pos_parts, indent, prefix)
704
+ else:
705
+ lines = [prog]
706
+
707
+ # if prog is long, put it on its own line
708
+ else:
709
+ indent = ' ' * len(prefix)
710
+ parts = opt_parts + pos_parts
711
+ lines = get_lines(parts, indent)
712
+ if len(lines) > 1:
713
+ lines = []
714
+ lines.extend(get_lines(opt_parts, indent))
715
+ lines.extend(get_lines(pos_parts, indent))
716
+ lines = [prog] + lines
717
+
718
+ # join lines into usage
719
+ usage = '\n'.join(lines)
720
+
721
+ # prefix with 'usage:'
722
+ return '%s%s\n\n' % (prefix, usage)
723
+
724
+ def _format_actions_usage(self, actions, groups):
725
+ # find group indices and identify actions in groups
726
+ group_actions = set()
727
+ inserts = {}
728
+ for group in groups:
729
+ try:
730
+ start = actions.index(group._group_actions[0])
731
+ except ValueError:
732
+ continue
733
+ else:
734
+ end = start + len(group._group_actions)
735
+ if actions[start:end] == group._group_actions:
736
+ for action in group._group_actions:
737
+ group_actions.add(action)
738
+ if not group.required:
739
+ if start in inserts:
740
+ inserts[start] += ' ['
741
+ else:
742
+ inserts[start] = '['
743
+ inserts[end] = ']'
744
+ else:
745
+ if start in inserts:
746
+ inserts[start] += ' ('
747
+ else:
748
+ inserts[start] = '('
749
+ inserts[end] = ')'
750
+ for i in range(start + 1, end):
751
+ inserts[i] = '|'
752
+
753
+ # collect all actions format strings
754
+ parts = []
755
+ for i, action in enumerate(actions):
756
+
757
+ # suppressed arguments are marked with None
758
+ # remove | separators for suppressed arguments
759
+ if action.help is SUPPRESS:
760
+ parts.append(None)
761
+ if inserts.get(i) == '|':
762
+ inserts.pop(i)
763
+ elif inserts.get(i + 1) == '|':
764
+ inserts.pop(i + 1)
765
+
766
+ # produce all arg strings
767
+ elif not action.option_strings:
768
+ part = self._format_args(action, action.dest)
769
+
770
+ # if it's in a group, strip the outer []
771
+ if action in group_actions:
772
+ if part[0] == '[' and part[-1] == ']':
773
+ part = part[1:-1]
774
+
775
+ # add the action string to the list
776
+ parts.append(part)
777
+
778
+ # produce the first way to invoke the option in brackets
779
+ else:
780
+ option_string = action.option_strings[0]
781
+
782
+ # if the Optional doesn't take a value, format is:
783
+ # -s or --long
784
+ if action.nargs == 0:
785
+ part = '%s' % option_string
786
+
787
+ # if the Optional takes a value, format is:
788
+ # -s ARGS or --long ARGS
789
+ else:
790
+ default = action.dest.upper()
791
+ args_string = self._format_args(action, default)
792
+ part = '%s %s' % (option_string, args_string)
793
+
794
+ # make it look optional if it's not required or in a group
795
+ if not action.required and action not in group_actions:
796
+ part = '[%s]' % part
797
+
798
+ # add the action string to the list
799
+ parts.append(part)
800
+
801
+ # insert things at the necessary indices
802
+ for i in sorted(inserts, reverse=True):
803
+ parts[i:i] = [inserts[i]]
804
+
805
+ # join all the action items with spaces
806
+ text = ' '.join([item for item in parts if item is not None])
807
+
808
+ # clean up separators for mutually exclusive groups
809
+ open = r'[\[(]'
810
+ close = r'[\])]'
811
+ text = _re.sub(r'(%s) ' % open, r'\1', text)
812
+ text = _re.sub(r' (%s)' % close, r'\1', text)
813
+ text = _re.sub(r'%s *%s' % (open, close), r'', text)
814
+ text = _re.sub(r'\(([^|]*)\)', r'\1', text)
815
+ text = text.strip()
816
+
817
+ # return the text
818
+ return text
819
+
820
+ def _format_text(self, text):
821
+ if '%(prog)' in text:
822
+ text = text % dict(prog=self._prog)
823
+ text_width = self._width - self._current_indent
824
+ indent = ' ' * self._current_indent
825
+ return self._fill_text(text, text_width, indent) + '\n\n'
826
+
827
+ def _format_action(self, action):
828
+ # determine the required width and the entry label
829
+ help_position = min(self._action_max_length + 2,
830
+ self._max_help_position)
831
+ help_width = self._width - help_position
832
+ action_width = help_position - self._current_indent - 2
833
+ action_header = self._format_action_invocation(action)
834
+
835
+ # ho nelp; start on same line and add a final newline
836
+ if not action.help:
837
+ tup = self._current_indent, '', action_header
838
+ action_header = '%*s%s\n' % tup
839
+
840
+ # short action name; start on the same line and pad two spaces
841
+ elif len(action_header) <= action_width:
842
+ tup = self._current_indent, '', action_width, action_header
843
+ action_header = '%*s%-*s ' % tup
844
+ indent_first = 0
845
+
846
+ # long action name; start on the next line
847
+ else:
848
+ tup = self._current_indent, '', action_header
849
+ action_header = '%*s%s\n' % tup
850
+ indent_first = help_position
851
+
852
+ # collect the pieces of the action help
853
+ parts = [action_header]
854
+
855
+ # if there was help for the action, add lines of help text
856
+ if action.help:
857
+ help_text = self._expand_help(action)
858
+ help_lines = self._split_lines(help_text, help_width)
859
+ parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
860
+ for line in help_lines[1:]:
861
+ parts.append('%*s%s\n' % (help_position, '', line))
862
+
863
+ # or add a newline if the description doesn't end with one
864
+ elif not action_header.endswith('\n'):
865
+ parts.append('\n')
866
+
867
+ # if there are any sub-actions, add their help as well
868
+ for subaction in self._iter_indented_subactions(action):
869
+ parts.append(self._format_action(subaction))
870
+
871
+ # return a single string
872
+ return self._join_parts(parts)
873
+
874
+ def _format_action_invocation(self, action):
875
+ if not action.option_strings:
876
+ metavar, = self._metavar_formatter(action, action.dest)(1)
877
+ return metavar
878
+
879
+ else:
880
+ parts = []
881
+
882
+ # if the Optional doesn't take a value, format is:
883
+ # -s, --long
884
+ if action.nargs == 0:
885
+ parts.extend(action.option_strings)
886
+
887
+ # if the Optional takes a value, format is:
888
+ # -s ARGS, --long ARGS
889
+ else:
890
+ default = action.dest.upper()
891
+ args_string = self._format_args(action, default)
892
+ for option_string in action.option_strings:
893
+ parts.append('%s %s' % (option_string, args_string))
894
+
895
+ return ', '.join(parts)
896
+
897
+ def _metavar_formatter(self, action, default_metavar):
898
+ if action.metavar is not None:
899
+ result = action.metavar
900
+ elif action.choices is not None:
901
+ choice_strs = [str(choice) for choice in action.choices]
902
+ result = '{%s}' % ','.join(choice_strs)
903
+ else:
904
+ result = default_metavar
905
+
906
+ def format(tuple_size):
907
+ if isinstance(result, tuple):
908
+ return result
909
+ else:
910
+ return (result, ) * tuple_size
911
+ return format
912
+
913
+ def _format_args(self, action, default_metavar):
914
+ get_metavar = self._metavar_formatter(action, default_metavar)
915
+ if action.nargs is None:
916
+ result = '%s' % get_metavar(1)
917
+ elif action.nargs == OPTIONAL:
918
+ result = '[%s]' % get_metavar(1)
919
+ elif action.nargs == ZERO_OR_MORE:
920
+ result = '[%s [%s ...]]' % get_metavar(2)
921
+ elif action.nargs == ONE_OR_MORE:
922
+ result = '%s [%s ...]' % get_metavar(2)
923
+ elif action.nargs == REMAINDER:
924
+ result = '...'
925
+ elif action.nargs == PARSER:
926
+ result = '%s ...' % get_metavar(1)
927
+ else:
928
+ formats = ['%s' for _ in range(action.nargs)]
929
+ result = ' '.join(formats) % get_metavar(action.nargs)
930
+ return result
931
+
932
+ def _expand_help(self, action):
933
+ params = dict(vars(action), prog=self._prog)
934
+ for name in list(params):
935
+ if params[name] is SUPPRESS:
936
+ del params[name]
937
+ for name in list(params):
938
+ if hasattr(params[name], '__name__'):
939
+ params[name] = params[name].__name__
940
+ if params.get('choices') is not None:
941
+ choices_str = ', '.join([str(c) for c in params['choices']])
942
+ params['choices'] = choices_str
943
+ return self._get_help_string(action) % params
944
+
945
+ def _iter_indented_subactions(self, action):
946
+ try:
947
+ get_subactions = action._get_subactions
948
+ except AttributeError:
949
+ pass
950
+ else:
951
+ self._indent()
952
+ for subaction in get_subactions():
953
+ yield subaction
954
+ self._dedent()
955
+
956
+ def _split_lines(self, text, width):
957
+ text = self._whitespace_matcher.sub(' ', text).strip()
958
+ return _textwrap.wrap(text, width)
959
+
960
+ def _fill_text(self, text, width, indent):
961
+ text = self._whitespace_matcher.sub(' ', text).strip()
962
+ return _textwrap.fill(text, width, initial_indent=indent,
963
+ subsequent_indent=indent)
964
+
965
+ def _get_help_string(self, action):
966
+ return action.help
967
+
968
+
969
+class RawDescriptionHelpFormatter(HelpFormatter):
970
+ """Help message formatter which retains any formatting in descriptions.
971
+
972
+ Only the name of this class is considered a public API. All the methods
973
+ provided by the class are considered an implementation detail.
974
+ """
975
+
976
+ def _fill_text(self, text, width, indent):
977
+ return ''.join([indent + line for line in text.splitlines(True)])
978
+
979
+
980
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
981
+ """Help message formatter which retains formatting of all help text.
982
+
983
+ Only the name of this class is considered a public API. All the methods
984
+ provided by the class are considered an implementation detail.
985
+ """
986
+
987
+ def _split_lines(self, text, width):
988
+ return text.splitlines()
989
+
990
+
991
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
992
+ """Help message formatter which adds default values to argument help.
993
+
994
+ Only the name of this class is considered a public API. All the methods
995
+ provided by the class are considered an implementation detail.
996
+ """
997
+
998
+ def _get_help_string(self, action):
999
+ help = action.help
1000
+ if '%(default)' not in action.help:
1001
+ if action.default is not SUPPRESS:
1002
+ defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
1003
+ if action.option_strings or action.nargs in defaulting_nargs:
1004
+ help += ' (default: %(default)s)'
1005
+ return help
1006
+
1007
+
1008
+# =====================
1009
+# Options and Arguments
1010
+# =====================
1011
+
1012
+def _get_action_name(argument):
1013
+ if argument is None:
1014
+ return None
1015
+ elif argument.option_strings:
1016
+ return '/'.join(argument.option_strings)
1017
+ elif argument.metavar not in (None, SUPPRESS):
1018
+ return argument.metavar
1019
+ elif argument.dest not in (None, SUPPRESS):
1020
+ return argument.dest
1021
+ else:
1022
+ return None
1023
+
1024
+
1025
+class ArgumentError(Exception):
1026
+ """An error from creating or using an argument (optional or positional).
1027
+
1028
+ The string value of this exception is the message, augmented with
1029
+ information about the argument that caused it.
1030
+ """
1031
+
1032
+ def __init__(self, argument, message):
1033
+ self.argument_name = _get_action_name(argument)
1034
+ self.message = message
1035
+
1036
+ def __str__(self):
1037
+ if self.argument_name is None:
1038
+ format = '%(message)s'
1039
+ else:
1040
+ format = 'argument %(argument_name)s: %(message)s'
1041
+ return format % dict(message=self.message,
1042
+ argument_name=self.argument_name)
1043
+
1044
+
1045
+class ArgumentTypeError(Exception):
1046
+ """An error from trying to convert a command line string to a type."""
1047
+ pass
1048
+
1049
+
1050
+# ==============
1051
+# Action classes
1052
+# ==============
1053
+
1054
+class Action(_AttributeHolder):
1055
+ """Information about how to convert command line strings to Python objects.
1056
+
1057
+ Action objects are used by an ArgumentParser to represent the information
1058
+ needed to parse a single argument from one or more strings from the
1059
+ command line. The keyword arguments to the Action constructor are also
1060
+ all attributes of Action instances.
1061
+
1062
+ Keyword Arguments:
1063
+
1064
+ - option_strings -- A list of command-line option strings which
1065
+ should be associated with this action.
1066
+
1067
+ - dest -- The name of the attribute to hold the created object(s)
1068
+
1069
+ - nargs -- The number of command-line arguments that should be
1070
+ consumed. By default, one argument will be consumed and a single
1071
+ value will be produced. Other values include:
1072
+ - N (an integer) consumes N arguments (and produces a list)
1073
+ - '?' consumes zero or one arguments
1074
+ - '*' consumes zero or more arguments (and produces a list)
1075
+ - '+' consumes one or more arguments (and produces a list)
1076
+ Note that the difference between the default and nargs=1 is that
1077
+ with the default, a single value will be produced, while with
1078
+ nargs=1, a list containing a single value will be produced.
1079
+
1080
+ - const -- The value to be produced if the option is specified and the
1081
+ option uses an action that takes no values.
1082
+
1083
+ - default -- The value to be produced if the option is not specified.
1084
+
1085
+ - type -- The type which the command-line arguments should be converted
1086
+ to, should be one of 'string', 'int', 'float', 'complex' or a
1087
+ callable object that accepts a single string argument. If None,
1088
+ 'string' is assumed.
1089
+
1090
+ - choices -- A container of values that should be allowed. If not None,
1091
+ after a command-line argument has been converted to the appropriate
1092
+ type, an exception will be raised if it is not a member of this
1093
+ collection.
1094
+
1095
+ - required -- True if the action must always be specified at the
1096
+ command line. This is only meaningful for optional command-line
1097
+ arguments.
1098
+
1099
+ - help -- The help string describing the argument.
1100
+
1101
+ - metavar -- The name to be used for the option's argument with the
1102
+ help string. If None, the 'dest' value will be used as the name.
1103
+ """
1104
+
1105
+ def __init__(self,
1106
+ option_strings,
1107
+ dest,
1108
+ nargs=None,
1109
+ const=None,
1110
+ default=None,
1111
+ type=None,
1112
+ choices=None,
1113
+ required=False,
1114
+ help=None,
1115
+ metavar=None):
1116
+ self.option_strings = option_strings
1117
+ self.dest = dest
1118
+ self.nargs = nargs
1119
+ self.const = const
1120
+ self.default = default
1121
+ self.type = type
1122
+ self.choices = choices
1123
+ self.required = required
1124
+ self.help = help
1125
+ self.metavar = metavar
1126
+
1127
+ def _get_kwargs(self):
1128
+ names = [
1129
+ 'option_strings',
1130
+ 'dest',
1131
+ 'nargs',
1132
+ 'const',
1133
+ 'default',
1134
+ 'type',
1135
+ 'choices',
1136
+ 'help',
1137
+ 'metavar',
1138
+ ]
1139
+ return [(name, getattr(self, name)) for name in names]
1140
+
1141
+ def __call__(self, parser, namespace, values, option_string=None):
1142
+ raise NotImplementedError(_('.__call__() not defined'))
1143
+
1144
+
1145
+class _StoreAction(Action):
1146
+
1147
+ def __init__(self,
1148
+ option_strings,
1149
+ dest,
1150
+ nargs=None,
1151
+ const=None,
1152
+ default=None,
1153
+ type=None,
1154
+ choices=None,
1155
+ required=False,
1156
+ help=None,
1157
+ metavar=None):
1158
+ if nargs == 0:
1159
+ raise ValueError('nargs for store actions must be > 0; if you '
1160
+ 'have nothing to store, actions such as store '
1161
+ 'true or store const may be more appropriate')
1162
+ if const is not None and nargs != OPTIONAL:
1163
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
1164
+ super(_StoreAction, self).__init__(
1165
+ option_strings=option_strings,
1166
+ dest=dest,
1167
+ nargs=nargs,
1168
+ const=const,
1169
+ default=default,
1170
+ type=type,
1171
+ choices=choices,
1172
+ required=required,
1173
+ help=help,
1174
+ metavar=metavar)
1175
+
1176
+ def __call__(self, parser, namespace, values, option_string=None):
1177
+ setattr(namespace, self.dest, values)
1178
+
1179
+
1180
+class _StoreConstAction(Action):
1181
+
1182
+ def __init__(self,
1183
+ option_strings,
1184
+ dest,
1185
+ const,
1186
+ default=None,
1187
+ required=False,
1188
+ help=None,
1189
+ metavar=None):
1190
+ super(_StoreConstAction, self).__init__(
1191
+ option_strings=option_strings,
1192
+ dest=dest,
1193
+ nargs=0,
1194
+ const=const,
1195
+ default=default,
1196
+ required=required,
1197
+ help=help)
1198
+
1199
+ def __call__(self, parser, namespace, values, option_string=None):
1200
+ setattr(namespace, self.dest, self.const)
1201
+
1202
+
1203
+class _StoreTrueAction(_StoreConstAction):
1204
+
1205
+ def __init__(self,
1206
+ option_strings,
1207
+ dest,
1208
+ default=False,
1209
+ required=False,
1210
+ help=None):
1211
+ super(_StoreTrueAction, self).__init__(
1212
+ option_strings=option_strings,
1213
+ dest=dest,
1214
+ const=True,
1215
+ default=default,
1216
+ required=required,
1217
+ help=help)
1218
+
1219
+
1220
+class _StoreFalseAction(_StoreConstAction):
1221
+
1222
+ def __init__(self,
1223
+ option_strings,
1224
+ dest,
1225
+ default=True,
1226
+ required=False,
1227
+ help=None):
1228
+ super(_StoreFalseAction, self).__init__(
1229
+ option_strings=option_strings,
1230
+ dest=dest,
1231
+ const=False,
1232
+ default=default,
1233
+ required=required,
1234
+ help=help)
1235
+
1236
+
1237
+class _AppendAction(Action):
1238
+
1239
+ def __init__(self,
1240
+ option_strings,
1241
+ dest,
1242
+ nargs=None,
1243
+ const=None,
1244
+ default=None,
1245
+ type=None,
1246
+ choices=None,
1247
+ required=False,
1248
+ help=None,
1249
+ metavar=None):
1250
+ if nargs == 0:
1251
+ raise ValueError('nargs for append actions must be > 0; if arg '
1252
+ 'strings are not supplying the value to append, '
1253
+ 'the append const action may be more appropriate')
1254
+ if const is not None and nargs != OPTIONAL:
1255
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
1256
+ super(_AppendAction, self).__init__(
1257
+ option_strings=option_strings,
1258
+ dest=dest,
1259
+ nargs=nargs,
1260
+ const=const,
1261
+ default=default,
1262
+ type=type,
1263
+ choices=choices,
1264
+ required=required,
1265
+ help=help,
1266
+ metavar=metavar)
1267
+
1268
+ def __call__(self, parser, namespace, values, option_string=None):
1269
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
1270
+ items.append(values)
1271
+ setattr(namespace, self.dest, items)
1272
+
1273
+
1274
+class _AppendConstAction(Action):
1275
+
1276
+ def __init__(self,
1277
+ option_strings,
1278
+ dest,
1279
+ const,
1280
+ default=None,
1281
+ required=False,
1282
+ help=None,
1283
+ metavar=None):
1284
+ super(_AppendConstAction, self).__init__(
1285
+ option_strings=option_strings,
1286
+ dest=dest,
1287
+ nargs=0,
1288
+ const=const,
1289
+ default=default,
1290
+ required=required,
1291
+ help=help,
1292
+ metavar=metavar)
1293
+
1294
+ def __call__(self, parser, namespace, values, option_string=None):
1295
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
1296
+ items.append(self.const)
1297
+ setattr(namespace, self.dest, items)
1298
+
1299
+
1300
+class _CountAction(Action):
1301
+
1302
+ def __init__(self,
1303
+ option_strings,
1304
+ dest,
1305
+ default=None,
1306
+ required=False,
1307
+ help=None):
1308
+ super(_CountAction, self).__init__(
1309
+ option_strings=option_strings,
1310
+ dest=dest,
1311
+ nargs=0,
1312
+ default=default,
1313
+ required=required,
1314
+ help=help)
1315
+
1316
+ def __call__(self, parser, namespace, values, option_string=None):
1317
+ new_count = _ensure_value(namespace, self.dest, 0) + 1
1318
+ setattr(namespace, self.dest, new_count)
1319
+
1320
+
1321
+class _HelpAction(Action):
1322
+
1323
+ def __init__(self,
1324
+ option_strings,
1325
+ dest=SUPPRESS,
1326
+ default=SUPPRESS,
1327
+ help=None):
1328
+ super(_HelpAction, self).__init__(
1329
+ option_strings=option_strings,
1330
+ dest=dest,
1331
+ default=default,
1332
+ nargs=0,
1333
+ help=help)
1334
+
1335
+ def __call__(self, parser, namespace, values, option_string=None):
1336
+ parser.print_help()
1337
+ parser.exit()
1338
+
1339
+
1340
+class _VersionAction(Action):
1341
+
1342
+ def __init__(self,
1343
+ option_strings,
1344
+ version=None,
1345
+ dest=SUPPRESS,
1346
+ default=SUPPRESS,
1347
+ help="show program's version number and exit"):
1348
+ super(_VersionAction, self).__init__(
1349
+ option_strings=option_strings,
1350
+ dest=dest,
1351
+ default=default,
1352
+ nargs=0,
1353
+ help=help)
1354
+ self.version = version
1355
+
1356
+ def __call__(self, parser, namespace, values, option_string=None):
1357
+ version = self.version
1358
+ if version is None:
1359
+ version = parser.version
1360
+ formatter = parser._get_formatter()
1361
+ formatter.add_text(version)
1362
+ parser.exit(message=formatter.format_help())
1363
+
1364
+
1365
+class _SubParsersAction(Action):
1366
+
1367
+ class _ChoicesPseudoAction(Action):
1368
+
1369
+ def __init__(self, name, aliases, help):
1370
+ metavar = dest = name
1371
+ if aliases:
1372
+ metavar += ' (%s)' % ', '.join(aliases)
1373
+ sup = super(_SubParsersAction._ChoicesPseudoAction, self)
1374
+ sup.__init__(option_strings=[], dest=dest, help=help,
1375
+ metavar=metavar)
1376
+
1377
+ def __init__(self,
1378
+ option_strings,
1379
+ prog,
1380
+ parser_class,
1381
+ dest=SUPPRESS,
1382
+ help=None,
1383
+ metavar=None):
1384
+
1385
+ self._prog_prefix = prog
1386
+ self._parser_class = parser_class
1387
+ self._name_parser_map = {}
1388
+ self._choices_actions = []
1389
+
1390
+ super(_SubParsersAction, self).__init__(
1391
+ option_strings=option_strings,
1392
+ dest=dest,
1393
+ nargs=PARSER,
1394
+ choices=self._name_parser_map,
1395
+ help=help,
1396
+ metavar=metavar)
1397
+
1398
+ def add_parser(self, name, **kwargs):
1399
+ # set prog from the existing prefix
1400
+ if kwargs.get('prog') is None:
1401
+ kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
1402
+
1403
+ aliases = kwargs.pop('aliases', ())
1404
+
1405
+ # create a pseudo-action to hold the choice help
1406
+ if 'help' in kwargs:
1407
+ help = kwargs.pop('help')
1408
+ choice_action = self._ChoicesPseudoAction(name, aliases, help)
1409
+ self._choices_actions.append(choice_action)
1410
+
1411
+ # create the parser and add it to the map
1412
+ parser = self._parser_class(**kwargs)
1413
+ self._name_parser_map[name] = parser
1414
+
1415
+ # make parser available under aliases also
1416
+ for alias in aliases:
1417
+ self._name_parser_map[alias] = parser
1418
+
1419
+ return parser
1420
+
1421
+ def _get_subactions(self):
1422
+ return self._choices_actions
1423
+
1424
+ def __call__(self, parser, namespace, values, option_string=None):
1425
+ parser_name = values[0]
1426
+ arg_strings = values[1:]
1427
+
1428
+ # set the parser name if requested
1429
+ if self.dest is not SUPPRESS:
1430
+ setattr(namespace, self.dest, parser_name)
1431
+
1432
+ # select the parser
1433
+ try:
1434
+ parser = self._name_parser_map[parser_name]
1435
+ except KeyError:
1436
+ tup = parser_name, ', '.join(self._name_parser_map)
1437
+ msg = _('unknown parser %r (choices: %s)' % tup)
1438
+ raise ArgumentError(self, msg)
1439
+
1440
+ # parse all the remaining options into the namespace
1441
+ # store any unrecognized options on the object, so that the top
1442
+ # level parser can decide what to do with them
1443
+ namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
1444
+ if arg_strings:
1445
+ vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
1446
+ getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
1447
+
1448
+
1449
+# ==============
1450
+# Type classes
1451
+# ==============
1452
+
1453
+class FileType(object):
1454
+ """Factory for creating file object types
1455
+
1456
+ Instances of FileType are typically passed as type= arguments to the
1457
+ ArgumentParser add_argument() method.
1458
+
1459
+ Keyword Arguments:
1460
+ - mode -- A string indicating how the file is to be opened. Accepts the
1461
+ same values as the builtin open() function.
1462
+ - bufsize -- The file's desired buffer size. Accepts the same values as
1463
+ the builtin open() function.
1464
+ """
1465
+
1466
+ def __init__(self, mode='r', bufsize=None):
1467
+ self._mode = mode
1468
+ self._bufsize = bufsize
1469
+
1470
+ def __call__(self, string):
1471
+ # the special argument "-" means sys.std{in,out}
1472
+ if string == '-':
1473
+ if 'r' in self._mode:
1474
+ return _sys.stdin
1475
+ elif 'w' in self._mode:
1476
+ return _sys.stdout
1477
+ else:
1478
+ msg = _('argument "-" with mode %r' % self._mode)
1479
+ raise ValueError(msg)
1480
+
1481
+ try:
1482
+ # all other arguments are used as file names
1483
+ if self._bufsize:
1484
+ return open(string, self._mode, self._bufsize)
1485
+ else:
1486
+ return open(string, self._mode)
1487
+ except IOError:
1488
+ err = _sys.exc_info()[1]
1489
+ message = _("can't open '%s': %s")
1490
+ raise ArgumentTypeError(message % (string, err))
1491
+
1492
+ def __repr__(self):
1493
+ args = [self._mode, self._bufsize]
1494
+ args_str = ', '.join([repr(arg) for arg in args if arg is not None])
1495
+ return '%s(%s)' % (type(self).__name__, args_str)
1496
+
1497
+# ===========================
1498
+# Optional and Positional Parsing
1499
+# ===========================
1500
+
1501
+class Namespace(_AttributeHolder):
1502
+ """Simple object for storing attributes.
1503
+
1504
+ Implements equality by attribute names and values, and provides a simple
1505
+ string representation.
1506
+ """
1507
+
1508
+ def __init__(self, **kwargs):
1509
+ for name in kwargs:
1510
+ setattr(self, name, kwargs[name])
1511
+
1512
+ __hash__ = None
1513
+
1514
+ def __eq__(self, other):
1515
+ return vars(self) == vars(other)
1516
+
1517
+ def __ne__(self, other):
1518
+ return not (self == other)
1519
+
1520
+ def __contains__(self, key):
1521
+ return key in self.__dict__
1522
+
1523
+
1524
+class _ActionsContainer(object):
1525
+
1526
+ def __init__(self,
1527
+ description,
1528
+ prefix_chars,
1529
+ argument_default,
1530
+ conflict_handler):
1531
+ super(_ActionsContainer, self).__init__()
1532
+
1533
+ self.description = description
1534
+ self.argument_default = argument_default
1535
+ self.prefix_chars = prefix_chars
1536
+ self.conflict_handler = conflict_handler
1537
+
1538
+ # set up registries
1539
+ self._registries = {}
1540
+
1541
+ # register actions
1542
+ self.register('action', None, _StoreAction)
1543
+ self.register('action', 'store', _StoreAction)
1544
+ self.register('action', 'store_const', _StoreConstAction)
1545
+ self.register('action', 'store_true', _StoreTrueAction)
1546
+ self.register('action', 'store_false', _StoreFalseAction)
1547
+ self.register('action', 'append', _AppendAction)
1548
+ self.register('action', 'append_const', _AppendConstAction)
1549
+ self.register('action', 'count', _CountAction)
1550
+ self.register('action', 'help', _HelpAction)
1551
+ self.register('action', 'version', _VersionAction)
1552
+ self.register('action', 'parsers', _SubParsersAction)
1553
+
1554
+ # raise an exception if the conflict handler is invalid
1555
+ self._get_handler()
1556
+
1557
+ # action storage
1558
+ self._actions = []
1559
+ self._option_string_actions = {}
1560
+
1561
+ # groups
1562
+ self._action_groups = []
1563
+ self._mutually_exclusive_groups = []
1564
+
1565
+ # defaults storage
1566
+ self._defaults = {}
1567
+
1568
+ # determines whether an "option" looks like a negative number
1569
+ self._negative_number_matcher = _re.compile(r'^-\d+$|^-\d*\.\d+$')
1570
+
1571
+ # whether or not there are any optionals that look like negative
1572
+ # numbers -- uses a list so it can be shared and edited
1573
+ self._has_negative_number_optionals = []
1574
+
1575
+ # ====================
1576
+ # Registration methods
1577
+ # ====================
1578
+ def register(self, registry_name, value, object):
1579
+ registry = self._registries.setdefault(registry_name, {})
1580
+ registry[value] = object
1581
+
1582
+ def _registry_get(self, registry_name, value, default=None):
1583
+ return self._registries[registry_name].get(value, default)
1584
+
1585
+ # ==================================
1586
+ # Namespace default accessor methods
1587
+ # ==================================
1588
+ def set_defaults(self, **kwargs):
1589
+ self._defaults.update(kwargs)
1590
+
1591
+ # if these defaults match any existing arguments, replace
1592
+ # the previous default on the object with the new one
1593
+ for action in self._actions:
1594
+ if action.dest in kwargs:
1595
+ action.default = kwargs[action.dest]
1596
+
1597
+ def get_default(self, dest):
1598
+ for action in self._actions:
1599
+ if action.dest == dest and action.default is not None:
1600
+ return action.default
1601
+ return self._defaults.get(dest, None)
1602
+
1603
+
1604
+ # =======================
1605
+ # Adding argument actions
1606
+ # =======================
1607
+ def add_argument(self, *args, **kwargs):
1608
+ """
1609
+ add_argument(dest, ..., name=value, ...)
1610
+ add_argument(option_string, option_string, ..., name=value, ...)
1611
+ """
1612
+
1613
+ # if no positional args are supplied or only one is supplied and
1614
+ # it doesn't look like an option string, parse a positional
1615
+ # argument
1616
+ chars = self.prefix_chars
1617
+ if not args or len(args) == 1 and args[0][0] not in chars:
1618
+ if args and 'dest' in kwargs:
1619
+ raise ValueError('dest supplied twice for positional argument')
1620
+ kwargs = self._get_positional_kwargs(*args, **kwargs)
1621
+
1622
+ # otherwise, we're adding an optional argument
1623
+ else:
1624
+ kwargs = self._get_optional_kwargs(*args, **kwargs)
1625
+
1626
+ # if no default was supplied, use the parser-level default
1627
+ if 'default' not in kwargs:
1628
+ dest = kwargs['dest']
1629
+ if dest in self._defaults:
1630
+ kwargs['default'] = self._defaults[dest]
1631
+ elif self.argument_default is not None:
1632
+ kwargs['default'] = self.argument_default
1633
+
1634
+ # create the action object, and add it to the parser
1635
+ action_class = self._pop_action_class(kwargs)
1636
+ if not _callable(action_class):
1637
+ raise ValueError('unknown action "%s"' % action_class)
1638
+ action = action_class(**kwargs)
1639
+
1640
+ # raise an error if the action type is not callable
1641
+ type_func = self._registry_get('type', action.type, action.type)
1642
+ if not _callable(type_func):
1643
+ raise ValueError('%r is not callable' % type_func)
1644
+
1645
+ return self._add_action(action)
1646
+
1647
+ def add_argument_group(self, *args, **kwargs):
1648
+ group = _ArgumentGroup(self, *args, **kwargs)
1649
+ self._action_groups.append(group)
1650
+ return group
1651
+
1652
+ def add_mutually_exclusive_group(self, **kwargs):
1653
+ group = _MutuallyExclusiveGroup(self, **kwargs)
1654
+ self._mutually_exclusive_groups.append(group)
1655
+ return group
1656
+
1657
+ def _add_action(self, action):
1658
+ # resolve any conflicts
1659
+ self._check_conflict(action)
1660
+
1661
+ # add to actions list
1662
+ self._actions.append(action)
1663
+ action.container = self
1664
+
1665
+ # index the action by any option strings it has
1666
+ for option_string in action.option_strings:
1667
+ self._option_string_actions[option_string] = action
1668
+
1669
+ # set the flag if any option strings look like negative numbers
1670
+ for option_string in action.option_strings:
1671
+ if self._negative_number_matcher.match(option_string):
1672
+ if not self._has_negative_number_optionals:
1673
+ self._has_negative_number_optionals.append(True)
1674
+
1675
+ # return the created action
1676
+ return action
1677
+
1678
+ def _remove_action(self, action):
1679
+ self._actions.remove(action)
1680
+
1681
+ def _add_container_actions(self, container):
1682
+ # collect groups by titles
1683
+ title_group_map = {}
1684
+ for group in self._action_groups:
1685
+ if group.title in title_group_map:
1686
+ msg = _('cannot merge actions - two groups are named %r')
1687
+ raise ValueError(msg % (group.title))
1688
+ title_group_map[group.title] = group
1689
+
1690
+ # map each action to its group
1691
+ group_map = {}
1692
+ for group in container._action_groups:
1693
+
1694
+ # if a group with the title exists, use that, otherwise
1695
+ # create a new group matching the container's group
1696
+ if group.title not in title_group_map:
1697
+ title_group_map[group.title] = self.add_argument_group(
1698
+ title=group.title,
1699
+ description=group.description,
1700
+ conflict_handler=group.conflict_handler)
1701
+
1702
+ # map the actions to their new group
1703
+ for action in group._group_actions:
1704
+ group_map[action] = title_group_map[group.title]
1705
+
1706
+ # add container's mutually exclusive groups
1707
+ # NOTE: if add_mutually_exclusive_group ever gains title= and
1708
+ # description= then this code will need to be expanded as above
1709
+ for group in container._mutually_exclusive_groups:
1710
+ mutex_group = self.add_mutually_exclusive_group(
1711
+ required=group.required)
1712
+
1713
+ # map the actions to their new mutex group
1714
+ for action in group._group_actions:
1715
+ group_map[action] = mutex_group
1716
+
1717
+ # add all actions to this container or their group
1718
+ for action in container._actions:
1719
+ group_map.get(action, self)._add_action(action)
1720
+
1721
+ def _get_positional_kwargs(self, dest, **kwargs):
1722
+ # make sure required is not specified
1723
+ if 'required' in kwargs:
1724
+ msg = _("'required' is an invalid argument for positionals")
1725
+ raise TypeError(msg)
1726
+
1727
+ # mark positional arguments as required if at least one is
1728
+ # always required
1729
+ if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
1730
+ kwargs['required'] = True
1731
+ if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
1732
+ kwargs['required'] = True
1733
+
1734
+ # return the keyword arguments with no option strings
1735
+ return dict(kwargs, dest=dest, option_strings=[])
1736
+
1737
+ def _get_optional_kwargs(self, *args, **kwargs):
1738
+ # determine short and long option strings
1739
+ option_strings = []
1740
+ long_option_strings = []
1741
+ for option_string in args:
1742
+ # error on strings that don't start with an appropriate prefix
1743
+ if not option_string[0] in self.prefix_chars:
1744
+ msg = _('invalid option string %r: '
1745
+ 'must start with a character %r')
1746
+ tup = option_string, self.prefix_chars
1747
+ raise ValueError(msg % tup)
1748
+
1749
+ # strings starting with two prefix characters are long options
1750
+ option_strings.append(option_string)
1751
+ if option_string[0] in self.prefix_chars:
1752
+ if len(option_string) > 1:
1753
+ if option_string[1] in self.prefix_chars:
1754
+ long_option_strings.append(option_string)
1755
+
1756
+ # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
1757
+ dest = kwargs.pop('dest', None)
1758
+ if dest is None:
1759
+ if long_option_strings:
1760
+ dest_option_string = long_option_strings[0]
1761
+ else:
1762
+ dest_option_string = option_strings[0]
1763
+ dest = dest_option_string.lstrip(self.prefix_chars)
1764
+ if not dest:
1765
+ msg = _('dest= is required for options like %r')
1766
+ raise ValueError(msg % option_string)
1767
+ dest = dest.replace('-', '_')
1768
+
1769
+ # return the updated keyword arguments
1770
+ return dict(kwargs, dest=dest, option_strings=option_strings)
1771
+
1772
+ def _pop_action_class(self, kwargs, default=None):
1773
+ action = kwargs.pop('action', default)
1774
+ return self._registry_get('action', action, action)
1775
+
1776
+ def _get_handler(self):
1777
+ # determine function from conflict handler string
1778
+ handler_func_name = '_handle_conflict_%s' % self.conflict_handler
1779
+ try:
1780
+ return getattr(self, handler_func_name)
1781
+ except AttributeError:
1782
+ msg = _('invalid conflict_resolution value: %r')
1783
+ raise ValueError(msg % self.conflict_handler)
1784
+
1785
+ def _check_conflict(self, action):
1786
+
1787
+ # find all options that conflict with this option
1788
+ confl_optionals = []
1789
+ for option_string in action.option_strings:
1790
+ if option_string in self._option_string_actions:
1791
+ confl_optional = self._option_string_actions[option_string]
1792
+ confl_optionals.append((option_string, confl_optional))
1793
+
1794
+ # resolve any conflicts
1795
+ if confl_optionals:
1796
+ conflict_handler = self._get_handler()
1797
+ conflict_handler(action, confl_optionals)
1798
+
1799
+ def _handle_conflict_error(self, action, conflicting_actions):
1800
+ message = _('conflicting option string(s): %s')
1801
+ conflict_string = ', '.join([option_string
1802
+ for option_string, action
1803
+ in conflicting_actions])
1804
+ raise ArgumentError(action, message % conflict_string)
1805
+
1806
+ def _handle_conflict_resolve(self, action, conflicting_actions):
1807
+
1808
+ # remove all conflicting options
1809
+ for option_string, action in conflicting_actions:
1810
+
1811
+ # remove the conflicting option
1812
+ action.option_strings.remove(option_string)
1813
+ self._option_string_actions.pop(option_string, None)
1814
+
1815
+ # if the option now has no option string, remove it from the
1816
+ # container holding it
1817
+ if not action.option_strings:
1818
+ action.container._remove_action(action)
1819
+
1820
+
1821
+class _ArgumentGroup(_ActionsContainer):
1822
+
1823
+ def __init__(self, container, title=None, description=None, **kwargs):
1824
+ # add any missing keyword arguments by checking the container
1825
+ update = kwargs.setdefault
1826
+ update('conflict_handler', container.conflict_handler)
1827
+ update('prefix_chars', container.prefix_chars)
1828
+ update('argument_default', container.argument_default)
1829
+ super_init = super(_ArgumentGroup, self).__init__
1830
+ super_init(description=description, **kwargs)
1831
+
1832
+ # group attributes
1833
+ self.title = title
1834
+ self._group_actions = []
1835
+
1836
+ # share most attributes with the container
1837
+ self._registries = container._registries
1838
+ self._actions = container._actions
1839
+ self._option_string_actions = container._option_string_actions
1840
+ self._defaults = container._defaults
1841
+ self._has_negative_number_optionals = \
1842
+ container._has_negative_number_optionals
1843
+
1844
+ def _add_action(self, action):
1845
+ action = super(_ArgumentGroup, self)._add_action(action)
1846
+ self._group_actions.append(action)
1847
+ return action
1848
+
1849
+ def _remove_action(self, action):
1850
+ super(_ArgumentGroup, self)._remove_action(action)
1851
+ self._group_actions.remove(action)
1852
+
1853
+
1854
+class _MutuallyExclusiveGroup(_ArgumentGroup):
1855
+
1856
+ def __init__(self, container, required=False):
1857
+ super(_MutuallyExclusiveGroup, self).__init__(container)
1858
+ self.required = required
1859
+ self._container = container
1860
+
1861
+ def _add_action(self, action):
1862
+ if action.required:
1863
+ msg = _('mutually exclusive arguments must be optional')
1864
+ raise ValueError(msg)
1865
+ action = self._container._add_action(action)
1866
+ self._group_actions.append(action)
1867
+ return action
1868
+
1869
+ def _remove_action(self, action):
1870
+ self._container._remove_action(action)
1871
+ self._group_actions.remove(action)
1872
+
1873
+
1874
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
1875
+ """Object for parsing command line strings into Python objects.
1876
+
1877
+ Keyword Arguments:
1878
+ - prog -- The name of the program (default: sys.argv[0])
1879
+ - usage -- A usage message (default: auto-generated from arguments)
1880
+ - description -- A description of what the program does
1881
+ - epilog -- Text following the argument descriptions
1882
+ - parents -- Parsers whose arguments should be copied into this one
1883
+ - formatter_class -- HelpFormatter class for printing help messages
1884
+ - prefix_chars -- Characters that prefix optional arguments
1885
+ - fromfile_prefix_chars -- Characters that prefix files containing
1886
+ additional arguments
1887
+ - argument_default -- The default value for all arguments
1888
+ - conflict_handler -- String indicating how to handle conflicts
1889
+ - add_help -- Add a -h/-help option
1890
+ """
1891
+
1892
+ def __init__(self,
1893
+ prog=None,
1894
+ usage=None,
1895
+ description=None,
1896
+ epilog=None,
1897
+ version=None,
1898
+ parents=[],
1899
+ formatter_class=HelpFormatter,
1900
+ prefix_chars='-',
1901
+ fromfile_prefix_chars=None,
1902
+ argument_default=None,
1903
+ conflict_handler='error',
1904
+ add_help=True):
1905
+
1906
+ if version is not None:
1907
+ import warnings
1908
+ warnings.warn(
1909
+ """The "version" argument to ArgumentParser is deprecated. """
1910
+ """Please use """
1911
+ """"add_argument(..., action='version', version="N", ...)" """
1912
+ """instead""", DeprecationWarning)
1913
+
1914
+ superinit = super(ArgumentParser, self).__init__
1915
+ superinit(description=description,
1916
+ prefix_chars=prefix_chars,
1917
+ argument_default=argument_default,
1918
+ conflict_handler=conflict_handler)
1919
+
1920
+ # default setting for prog
1921
+ if prog is None:
1922
+ prog = _os.path.basename(_sys.argv[0])
1923
+
1924
+ self.prog = prog
1925
+ self.usage = usage
1926
+ self.epilog = epilog
1927
+ self.version = version
1928
+ self.formatter_class = formatter_class
1929
+ self.fromfile_prefix_chars = fromfile_prefix_chars
1930
+ self.add_help = add_help
1931
+
1932
+ add_group = self.add_argument_group
1933
+ self._positionals = add_group(_('positional arguments'))
1934
+ self._optionals = add_group(_('optional arguments'))
1935
+ self._subparsers = None
1936
+
1937
+ # register types
1938
+ def identity(string):
1939
+ return string
1940
+ self.register('type', None, identity)
1941
+
1942
+ # add help and version arguments if necessary
1943
+ # (using explicit default to override global argument_default)
1944
+ if '-' in prefix_chars:
1945
+ default_prefix = '-'
1946
+ else:
1947
+ default_prefix = prefix_chars[0]
1948
+ if self.add_help:
1949
+ self.add_argument(
1950
+ default_prefix+'h', default_prefix*2+'help',
1951
+ action='help', default=SUPPRESS,
1952
+ help=_('show this help message and exit'))
1953
+ if self.version:
1954
+ self.add_argument(
1955
+ default_prefix+'v', default_prefix*2+'version',
1956
+ action='version', default=SUPPRESS,
1957
+ version=self.version,
1958
+ help=_("show program's version number and exit"))
1959
+
1960
+ # add parent arguments and defaults
1961
+ for parent in parents:
1962
+ self._add_container_actions(parent)
1963
+ try:
1964
+ defaults = parent._defaults
1965
+ except AttributeError:
1966
+ pass
1967
+ else:
1968
+ self._defaults.update(defaults)
1969
+
1970
+ # =======================
1971
+ # Pretty __repr__ methods
1972
+ # =======================
1973
+ def _get_kwargs(self):
1974
+ names = [
1975
+ 'prog',
1976
+ 'usage',
1977
+ 'description',
1978
+ 'version',
1979
+ 'formatter_class',
1980
+ 'conflict_handler',
1981
+ 'add_help',
1982
+ ]
1983
+ return [(name, getattr(self, name)) for name in names]
1984
+
1985
+ # ==================================
1986
+ # Optional/Positional adding methods
1987
+ # ==================================
1988
+ def add_subparsers(self, **kwargs):
1989
+ if self._subparsers is not None:
1990
+ self.error(_('cannot have multiple subparser arguments'))
1991
+
1992
+ # add the parser class to the arguments if it's not present
1993
+ kwargs.setdefault('parser_class', type(self))
1994
+
1995
+ if 'title' in kwargs or 'description' in kwargs:
1996
+ title = _(kwargs.pop('title', 'subcommands'))
1997
+ description = _(kwargs.pop('description', None))
1998
+ self._subparsers = self.add_argument_group(title, description)
1999
+ else:
2000
+ self._subparsers = self._positionals
2001
+
2002
+ # prog defaults to the usage message of this parser, skipping
2003
+ # optional arguments and with no "usage:" prefix
2004
+ if kwargs.get('prog') is None:
2005
+ formatter = self._get_formatter()
2006
+ positionals = self._get_positional_actions()
2007
+ groups = self._mutually_exclusive_groups
2008
+ formatter.add_usage(self.usage, positionals, groups, '')
2009
+ kwargs['prog'] = formatter.format_help().strip()
2010
+
2011
+ # create the parsers action and add it to the positionals list
2012
+ parsers_class = self._pop_action_class(kwargs, 'parsers')
2013
+ action = parsers_class(option_strings=[], **kwargs)
2014
+ self._subparsers._add_action(action)
2015
+
2016
+ # return the created parsers action
2017
+ return action
2018
+
2019
+ def _add_action(self, action):
2020
+ if action.option_strings:
2021
+ self._optionals._add_action(action)
2022
+ else:
2023
+ self._positionals._add_action(action)
2024
+ return action
2025
+
2026
+ def _get_optional_actions(self):
2027
+ return [action
2028
+ for action in self._actions
2029
+ if action.option_strings]
2030
+
2031
+ def _get_positional_actions(self):
2032
+ return [action
2033
+ for action in self._actions
2034
+ if not action.option_strings]
2035
+
2036
+ # =====================================
2037
+ # Command line argument parsing methods
2038
+ # =====================================
2039
+ def parse_args(self, args=None, namespace=None):
2040
+ args, argv = self.parse_known_args(args, namespace)
2041
+ if argv:
2042
+ msg = _('unrecognized arguments: %s')
2043
+ self.error(msg % ' '.join(argv))
2044
+ return args
2045
+
2046
+ def parse_known_args(self, args=None, namespace=None):
2047
+ # args default to the system args
2048
+ if args is None:
2049
+ args = _sys.argv[1:]
2050
+
2051
+ # default Namespace built from parser defaults
2052
+ if namespace is None:
2053
+ namespace = Namespace()
2054
+
2055
+ # add any action defaults that aren't present
2056
+ for action in self._actions:
2057
+ if action.dest is not SUPPRESS:
2058
+ if not hasattr(namespace, action.dest):
2059
+ if action.default is not SUPPRESS:
2060
+ setattr(namespace, action.dest, action.default)
2061
+
2062
+ # add any parser defaults that aren't present
2063
+ for dest in self._defaults:
2064
+ if not hasattr(namespace, dest):
2065
+ setattr(namespace, dest, self._defaults[dest])
2066
+
2067
+ # parse the arguments and exit if there are any errors
2068
+ try:
2069
+ namespace, args = self._parse_known_args(args, namespace)
2070
+ if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
2071
+ args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
2072
+ delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)
2073
+ return namespace, args
2074
+ except ArgumentError:
2075
+ err = _sys.exc_info()[1]
2076
+ self.error(str(err))
2077
+
2078
+ def _parse_known_args(self, arg_strings, namespace):
2079
+ # replace arg strings that are file references
2080
+ if self.fromfile_prefix_chars is not None:
2081
+ arg_strings = self._read_args_from_files(arg_strings)
2082
+
2083
+ # map all mutually exclusive arguments to the other arguments
2084
+ # they can't occur with
2085
+ action_conflicts = {}
2086
+ for mutex_group in self._mutually_exclusive_groups:
2087
+ group_actions = mutex_group._group_actions
2088
+ for i, mutex_action in enumerate(mutex_group._group_actions):
2089
+ conflicts = action_conflicts.setdefault(mutex_action, [])
2090
+ conflicts.extend(group_actions[:i])
2091
+ conflicts.extend(group_actions[i + 1:])
2092
+
2093
+ # find all option indices, and determine the arg_string_pattern
2094
+ # which has an 'O' if there is an option at an index,
2095
+ # an 'A' if there is an argument, or a '-' if there is a '--'
2096
+ option_string_indices = {}
2097
+ arg_string_pattern_parts = []
2098
+ arg_strings_iter = iter(arg_strings)
2099
+ for i, arg_string in enumerate(arg_strings_iter):
2100
+
2101
+ # all args after -- are non-options
2102
+ if arg_string == '--':
2103
+ arg_string_pattern_parts.append('-')
2104
+ for arg_string in arg_strings_iter:
2105
+ arg_string_pattern_parts.append('A')
2106
+
2107
+ # otherwise, add the arg to the arg strings
2108
+ # and note the index if it was an option
2109
+ else:
2110
+ option_tuple = self._parse_optional(arg_string)
2111
+ if option_tuple is None:
2112
+ pattern = 'A'
2113
+ else:
2114
+ option_string_indices[i] = option_tuple
2115
+ pattern = 'O'
2116
+ arg_string_pattern_parts.append(pattern)
2117
+
2118
+ # join the pieces together to form the pattern
2119
+ arg_strings_pattern = ''.join(arg_string_pattern_parts)
2120
+
2121
+ # converts arg strings to the appropriate and then takes the action
2122
+ seen_actions = set()
2123
+ seen_non_default_actions = set()
2124
+
2125
+ def take_action(action, argument_strings, option_string=None):
2126
+ seen_actions.add(action)
2127
+ argument_values = self._get_values(action, argument_strings)
2128
+
2129
+ # error if this argument is not allowed with other previously
2130
+ # seen arguments, assuming that actions that use the default
2131
+ # value don't really count as "present"
2132
+ if argument_values is not action.default:
2133
+ seen_non_default_actions.add(action)
2134
+ for conflict_action in action_conflicts.get(action, []):
2135
+ if conflict_action in seen_non_default_actions:
2136
+ msg = _('not allowed with argument %s')
2137
+ action_name = _get_action_name(conflict_action)
2138
+ raise ArgumentError(action, msg % action_name)
2139
+
2140
+ # take the action if we didn't receive a SUPPRESS value
2141
+ # (e.g. from a default)
2142
+ if argument_values is not SUPPRESS:
2143
+ action(self, namespace, argument_values, option_string)
2144
+
2145
+ # function to convert arg_strings into an optional action
2146
+ def consume_optional(start_index):
2147
+
2148
+ # get the optional identified at this index
2149
+ option_tuple = option_string_indices[start_index]
2150
+ action, option_string, explicit_arg = option_tuple
2151
+
2152
+ # identify additional optionals in the same arg string
2153
+ # (e.g. -xyz is the same as -x -y -z if no args are required)
2154
+ match_argument = self._match_argument
2155
+ action_tuples = []
2156
+ while True:
2157
+
2158
+ # if we found no optional action, skip it
2159
+ if action is None:
2160
+ extras.append(arg_strings[start_index])
2161
+ return start_index + 1
2162
+
2163
+ # if there is an explicit argument, try to match the
2164
+ # optional's string arguments to only this
2165
+ if explicit_arg is not None:
2166
+ arg_count = match_argument(action, 'A')
2167
+
2168
+ # if the action is a single-dash option and takes no
2169
+ # arguments, try to parse more single-dash options out
2170
+ # of the tail of the option string
2171
+ chars = self.prefix_chars
2172
+ if arg_count == 0 and option_string[1] not in chars:
2173
+ action_tuples.append((action, [], option_string))
2174
+ char = option_string[0]
2175
+ option_string = char + explicit_arg[0]
2176
+ new_explicit_arg = explicit_arg[1:] or None
2177
+ optionals_map = self._option_string_actions
2178
+ if option_string in optionals_map:
2179
+ action = optionals_map[option_string]
2180
+ explicit_arg = new_explicit_arg
2181
+ else:
2182
+ msg = _('ignored explicit argument %r')
2183
+ raise ArgumentError(action, msg % explicit_arg)
2184
+
2185
+ # if the action expect exactly one argument, we've
2186
+ # successfully matched the option; exit the loop
2187
+ elif arg_count == 1:
2188
+ stop = start_index + 1
2189
+ args = [explicit_arg]
2190
+ action_tuples.append((action, args, option_string))
2191
+ break
2192
+
2193
+ # error if a double-dash option did not use the
2194
+ # explicit argument
2195
+ else:
2196
+ msg = _('ignored explicit argument %r')
2197
+ raise ArgumentError(action, msg % explicit_arg)
2198
+
2199
+ # if there is no explicit argument, try to match the
2200
+ # optional's string arguments with the following strings
2201
+ # if successful, exit the loop
2202
+ else:
2203
+ start = start_index + 1
2204
+ selected_patterns = arg_strings_pattern[start:]
2205
+ arg_count = match_argument(action, selected_patterns)
2206
+ stop = start + arg_count
2207
+ args = arg_strings[start:stop]
2208
+ action_tuples.append((action, args, option_string))
2209
+ break
2210
+
2211
+ # add the Optional to the list and return the index at which
2212
+ # the Optional's string args stopped
2213
+ assert action_tuples
2214
+ for action, args, option_string in action_tuples:
2215
+ take_action(action, args, option_string)
2216
+ return stop
2217
+
2218
+ # the list of Positionals left to be parsed; this is modified
2219
+ # by consume_positionals()
2220
+ positionals = self._get_positional_actions()
2221
+
2222
+ # function to convert arg_strings into positional actions
2223
+ def consume_positionals(start_index):
2224
+ # match as many Positionals as possible
2225
+ match_partial = self._match_arguments_partial
2226
+ selected_pattern = arg_strings_pattern[start_index:]
2227
+ arg_counts = match_partial(positionals, selected_pattern)
2228
+
2229
+ # slice off the appropriate arg strings for each Positional
2230
+ # and add the Positional and its args to the list
2231
+ for action, arg_count in zip(positionals, arg_counts):
2232
+ args = arg_strings[start_index: start_index + arg_count]
2233
+ start_index += arg_count
2234
+ take_action(action, args)
2235
+
2236
+ # slice off the Positionals that we just parsed and return the
2237
+ # index at which the Positionals' string args stopped
2238
+ positionals[:] = positionals[len(arg_counts):]
2239
+ return start_index
2240
+
2241
+ # consume Positionals and Optionals alternately, until we have
2242
+ # passed the last option string
2243
+ extras = []
2244
+ start_index = 0
2245
+ if option_string_indices:
2246
+ max_option_string_index = max(option_string_indices)
2247
+ else:
2248
+ max_option_string_index = -1
2249
+ while start_index <= max_option_string_index:
2250
+
2251
+ # consume any Positionals preceding the next option
2252
+ next_option_string_index = min([
2253
+ index
2254
+ for index in option_string_indices
2255
+ if index >= start_index])
2256
+ if start_index != next_option_string_index:
2257
+ positionals_end_index = consume_positionals(start_index)
2258
+
2259
+ # only try to parse the next optional if we didn't consume
2260
+ # the option string during the positionals parsing
2261
+ if positionals_end_index > start_index:
2262
+ start_index = positionals_end_index
2263
+ continue
2264
+ else:
2265
+ start_index = positionals_end_index
2266
+
2267
+ # if we consumed all the positionals we could and we're not
2268
+ # at the index of an option string, there were extra arguments
2269
+ if start_index not in option_string_indices:
2270
+ strings = arg_strings[start_index:next_option_string_index]
2271
+ extras.extend(strings)
2272
+ start_index = next_option_string_index
2273
+
2274
+ # consume the next optional and any arguments for it
2275
+ start_index = consume_optional(start_index)
2276
+
2277
+ # consume any positionals following the last Optional
2278
+ stop_index = consume_positionals(start_index)
2279
+
2280
+ # if we didn't consume all the argument strings, there were extras
2281
+ extras.extend(arg_strings[stop_index:])
2282
+
2283
+ # if we didn't use all the Positional objects, there were too few
2284
+ # arg strings supplied.
2285
+ if positionals:
2286
+ self.error(_('too few arguments'))
2287
+
2288
+ # make sure all required actions were present, and convert defaults.
2289
+ for action in self._actions:
2290
+ if action not in seen_actions:
2291
+ if action.required:
2292
+ name = _get_action_name(action)
2293
+ self.error(_('argument %s is required') % name)
2294
+ else:
2295
+ # Convert action default now instead of doing it before
2296
+ # parsing arguments to avoid calling convert functions
2297
+ # twice (which may fail) if the argument was given, but
2298
+ # only if it was defined already in the namespace
2299
+ if (action.default is not None and
2300
+ isinstance(action.default, basestring) and
2301
+ hasattr(namespace, action.dest) and
2302
+ action.default is getattr(namespace, action.dest)):
2303
+ setattr(namespace, action.dest,
2304
+ self._get_value(action, action.default))
2305
+
2306
+ # make sure all required groups had one option present
2307
+ for group in self._mutually_exclusive_groups:
2308
+ if group.required:
2309
+ for action in group._group_actions:
2310
+ if action in seen_non_default_actions:
2311
+ break
2312
+
2313
+ # if no actions were used, report the error
2314
+ else:
2315
+ names = [_get_action_name(action)
2316
+ for action in group._group_actions
2317
+ if action.help is not SUPPRESS]
2318
+ msg = _('one of the arguments %s is required')
2319
+ self.error(msg % ' '.join(names))
2320
+
2321
+ # return the updated namespace and the extra arguments
2322
+ return namespace, extras
2323
+
2324
+ def _read_args_from_files(self, arg_strings):
2325
+ # expand arguments referencing files
2326
+ new_arg_strings = []
2327
+ for arg_string in arg_strings:
2328
+
2329
+ # for regular arguments, just add them back into the list
2330
+ if arg_string[0] not in self.fromfile_prefix_chars:
2331
+ new_arg_strings.append(arg_string)
2332
+
2333
+ # replace arguments referencing files with the file content
2334
+ else:
2335
+ try:
2336
+ args_file = open(arg_string[1:])
2337
+ try:
2338
+ arg_strings = []
2339
+ for arg_line in args_file.read().splitlines():
2340
+ for arg in self.convert_arg_line_to_args(arg_line):
2341
+ arg_strings.append(arg)
2342
+ arg_strings = self._read_args_from_files(arg_strings)
2343
+ new_arg_strings.extend(arg_strings)
2344
+ finally:
2345
+ args_file.close()
2346
+ except IOError:
2347
+ err = _sys.exc_info()[1]
2348
+ self.error(str(err))
2349
+
2350
+ # return the modified argument list
2351
+ return new_arg_strings
2352
+
2353
+ def convert_arg_line_to_args(self, arg_line):
2354
+ return [arg_line]
2355
+
2356
+ def _match_argument(self, action, arg_strings_pattern):
2357
+ # match the pattern for this action to the arg strings
2358
+ nargs_pattern = self._get_nargs_pattern(action)
2359
+ match = _re.match(nargs_pattern, arg_strings_pattern)
2360
+
2361
+ # raise an exception if we weren't able to find a match
2362
+ if match is None:
2363
+ nargs_errors = {
2364
+ None: _('expected one argument'),
2365
+ OPTIONAL: _('expected at most one argument'),
2366
+ ONE_OR_MORE: _('expected at least one argument'),
2367
+ }
2368
+ default = _('expected %s argument(s)') % action.nargs
2369
+ msg = nargs_errors.get(action.nargs, default)
2370
+ raise ArgumentError(action, msg)
2371
+
2372
+ # return the number of arguments matched
2373
+ return len(match.group(1))
2374
+
2375
+ def _match_arguments_partial(self, actions, arg_strings_pattern):
2376
+ # progressively shorten the actions list by slicing off the
2377
+ # final actions until we find a match
2378
+ result = []
2379
+ for i in range(len(actions), 0, -1):
2380
+ actions_slice = actions[:i]
2381
+ pattern = ''.join([self._get_nargs_pattern(action)
2382
+ for action in actions_slice])
2383
+ match = _re.match(pattern, arg_strings_pattern)
2384
+ if match is not None:
2385
+ result.extend([len(string) for string in match.groups()])
2386
+ break
30
+ break
2387
+
31
+
2388
+ # return the list of arg string counts
32
+ # json:{} filenames may be nested; filter out everything from
2389
+ return result
33
+ # inside the outermost one
34
+ if depth == 0:
35
+ chr_i += 1 # First character past the filename
36
+ result += "json:{ /* filtered */ }" + fname[chr_i:]
2390
+
37
+
2391
+ def _parse_optional(self, arg_string):
38
+sys.stdout.write(result)'
2392
+ # if it's an empty string, it was meant to be a positional
39
+}
2393
+ if not arg_string:
2394
+ return None
2395
+
40
+
2396
+ # if it doesn't start with a prefix, it was meant to be positional
41
# make sure this script returns success
2397
+ if not arg_string[0] in self.prefix_chars:
42
true
2398
+ return None
2399
+
2400
+ # if the option string is present in the parser, return the action
2401
+ if arg_string in self._option_string_actions:
2402
+ action = self._option_string_actions[arg_string]
2403
+ return action, arg_string, None
2404
+
2405
+ # if it's just a single character, it was meant to be positional
2406
+ if len(arg_string) == 1:
2407
+ return None
2408
+
2409
+ # if the option string before the "=" is present, return the action
2410
+ if '=' in arg_string:
2411
+ option_string, explicit_arg = arg_string.split('=', 1)
2412
+ if option_string in self._option_string_actions:
2413
+ action = self._option_string_actions[option_string]
2414
+ return action, option_string, explicit_arg
2415
+
2416
+ # search through all possible prefixes of the option string
2417
+ # and all actions in the parser for possible interpretations
2418
+ option_tuples = self._get_option_tuples(arg_string)
2419
+
2420
+ # if multiple actions match, the option string was ambiguous
2421
+ if len(option_tuples) > 1:
2422
+ options = ', '.join([option_string
2423
+ for action, option_string, explicit_arg in option_tuples])
2424
+ tup = arg_string, options
2425
+ self.error(_('ambiguous option: %s could match %s') % tup)
2426
+
2427
+ # if exactly one action matched, this segmentation is good,
2428
+ # so return the parsed action
2429
+ elif len(option_tuples) == 1:
2430
+ option_tuple, = option_tuples
2431
+ return option_tuple
2432
+
2433
+ # if it was not found as an option, but it looks like a negative
2434
+ # number, it was meant to be positional
2435
+ # unless there are negative-number-like options
2436
+ if self._negative_number_matcher.match(arg_string):
2437
+ if not self._has_negative_number_optionals:
2438
+ return None
2439
+
2440
+ # if it contains a space, it was meant to be a positional
2441
+ if ' ' in arg_string:
2442
+ return None
2443
+
2444
+ # it was meant to be an optional but there is no such option
2445
+ # in this parser (though it might be a valid option in a subparser)
2446
+ return None, arg_string, None
2447
+
2448
+ def _get_option_tuples(self, option_string):
2449
+ result = []
2450
+
2451
+ # option strings starting with two prefix characters are only
2452
+ # split at the '='
2453
+ chars = self.prefix_chars
2454
+ if option_string[0] in chars and option_string[1] in chars:
2455
+ if '=' in option_string:
2456
+ option_prefix, explicit_arg = option_string.split('=', 1)
2457
+ else:
2458
+ option_prefix = option_string
2459
+ explicit_arg = None
2460
+ for option_string in self._option_string_actions:
2461
+ if option_string.startswith(option_prefix):
2462
+ action = self._option_string_actions[option_string]
2463
+ tup = action, option_string, explicit_arg
2464
+ result.append(tup)
2465
+
2466
+ # single character options can be concatenated with their arguments
2467
+ # but multiple character options always have to have their argument
2468
+ # separate
2469
+ elif option_string[0] in chars and option_string[1] not in chars:
2470
+ option_prefix = option_string
2471
+ explicit_arg = None
2472
+ short_option_prefix = option_string[:2]
2473
+ short_explicit_arg = option_string[2:]
2474
+
2475
+ for option_string in self._option_string_actions:
2476
+ if option_string == short_option_prefix:
2477
+ action = self._option_string_actions[option_string]
2478
+ tup = action, option_string, short_explicit_arg
2479
+ result.append(tup)
2480
+ elif option_string.startswith(option_prefix):
2481
+ action = self._option_string_actions[option_string]
2482
+ tup = action, option_string, explicit_arg
2483
+ result.append(tup)
2484
+
2485
+ # shouldn't ever get here
2486
+ else:
2487
+ self.error(_('unexpected option string: %s') % option_string)
2488
+
2489
+ # return the collected option tuples
2490
+ return result
2491
+
2492
+ def _get_nargs_pattern(self, action):
2493
+ # in all examples below, we have to allow for '--' args
2494
+ # which are represented as '-' in the pattern
2495
+ nargs = action.nargs
2496
+
2497
+ # the default (None) is assumed to be a single argument
2498
+ if nargs is None:
2499
+ nargs_pattern = '(-*A-*)'
2500
+
2501
+ # allow zero or one arguments
2502
+ elif nargs == OPTIONAL:
2503
+ nargs_pattern = '(-*A?-*)'
2504
+
2505
+ # allow zero or more arguments
2506
+ elif nargs == ZERO_OR_MORE:
2507
+ nargs_pattern = '(-*[A-]*)'
2508
+
2509
+ # allow one or more arguments
2510
+ elif nargs == ONE_OR_MORE:
2511
+ nargs_pattern = '(-*A[A-]*)'
2512
+
2513
+ # allow any number of options or arguments
2514
+ elif nargs == REMAINDER:
2515
+ nargs_pattern = '([-AO]*)'
2516
+
2517
+ # allow one argument followed by any number of options or arguments
2518
+ elif nargs == PARSER:
2519
+ nargs_pattern = '(-*A[-AO]*)'
2520
+
2521
+ # all others should be integers
2522
+ else:
2523
+ nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
2524
+
2525
+ # if this is an optional action, -- is not allowed
2526
+ if action.option_strings:
2527
+ nargs_pattern = nargs_pattern.replace('-*', '')
2528
+ nargs_pattern = nargs_pattern.replace('-', '')
2529
+
2530
+ # return the pattern
2531
+ return nargs_pattern
2532
+
2533
+ # ========================
2534
+ # Value conversion methods
2535
+ # ========================
2536
+ def _get_values(self, action, arg_strings):
2537
+ # for everything but PARSER args, strip out '--'
2538
+ if action.nargs not in [PARSER, REMAINDER]:
2539
+ arg_strings = [s for s in arg_strings if s != '--']
2540
+
2541
+ # optional argument produces a default when not present
2542
+ if not arg_strings and action.nargs == OPTIONAL:
2543
+ if action.option_strings:
2544
+ value = action.const
2545
+ else:
2546
+ value = action.default
2547
+ if isinstance(value, basestring):
2548
+ value = self._get_value(action, value)
2549
+ self._check_value(action, value)
2550
+
2551
+ # when nargs='*' on a positional, if there were no command-line
2552
+ # args, use the default if it is anything other than None
2553
+ elif (not arg_strings and action.nargs == ZERO_OR_MORE and
2554
+ not action.option_strings):
2555
+ if action.default is not None:
2556
+ value = action.default
2557
+ else:
2558
+ value = arg_strings
2559
+ self._check_value(action, value)
2560
+
2561
+ # single argument or optional argument produces a single value
2562
+ elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
2563
+ arg_string, = arg_strings
2564
+ value = self._get_value(action, arg_string)
2565
+ self._check_value(action, value)
2566
+
2567
+ # REMAINDER arguments convert all values, checking none
2568
+ elif action.nargs == REMAINDER:
2569
+ value = [self._get_value(action, v) for v in arg_strings]
2570
+
2571
+ # PARSER arguments convert all values, but check only the first
2572
+ elif action.nargs == PARSER:
2573
+ value = [self._get_value(action, v) for v in arg_strings]
2574
+ self._check_value(action, value[0])
2575
+
2576
+ # all other types of nargs produce a list
2577
+ else:
2578
+ value = [self._get_value(action, v) for v in arg_strings]
2579
+ for v in value:
2580
+ self._check_value(action, v)
2581
+
2582
+ # return the converted value
2583
+ return value
2584
+
2585
+ def _get_value(self, action, arg_string):
2586
+ type_func = self._registry_get('type', action.type, action.type)
2587
+ if not _callable(type_func):
2588
+ msg = _('%r is not callable')
2589
+ raise ArgumentError(action, msg % type_func)
2590
+
2591
+ # convert the value to the appropriate type
2592
+ try:
2593
+ result = type_func(arg_string)
2594
+
2595
+ # ArgumentTypeErrors indicate errors
2596
+ except ArgumentTypeError:
2597
+ name = getattr(action.type, '__name__', repr(action.type))
2598
+ msg = str(_sys.exc_info()[1])
2599
+ raise ArgumentError(action, msg)
2600
+
2601
+ # TypeErrors or ValueErrors also indicate errors
2602
+ except (TypeError, ValueError):
2603
+ name = getattr(action.type, '__name__', repr(action.type))
2604
+ msg = _('invalid %s value: %r')
2605
+ raise ArgumentError(action, msg % (name, arg_string))
2606
+
2607
+ # return the converted value
2608
+ return result
2609
+
2610
+ def _check_value(self, action, value):
2611
+ # converted value must be one of the choices (if specified)
2612
+ if action.choices is not None and value not in action.choices:
2613
+ tup = value, ', '.join(map(repr, action.choices))
2614
+ msg = _('invalid choice: %r (choose from %s)') % tup
2615
+ raise ArgumentError(action, msg)
2616
+
2617
+ # =======================
2618
+ # Help-formatting methods
2619
+ # =======================
2620
+ def format_usage(self):
2621
+ formatter = self._get_formatter()
2622
+ formatter.add_usage(self.usage, self._actions,
2623
+ self._mutually_exclusive_groups)
2624
+ return formatter.format_help()
2625
+
2626
+ def format_help(self):
2627
+ formatter = self._get_formatter()
2628
+
2629
+ # usage
2630
+ formatter.add_usage(self.usage, self._actions,
2631
+ self._mutually_exclusive_groups)
2632
+
2633
+ # description
2634
+ formatter.add_text(self.description)
2635
+
2636
+ # positionals, optionals and user-defined groups
2637
+ for action_group in self._action_groups:
2638
+ formatter.start_section(action_group.title)
2639
+ formatter.add_text(action_group.description)
2640
+ formatter.add_arguments(action_group._group_actions)
2641
+ formatter.end_section()
2642
+
2643
+ # epilog
2644
+ formatter.add_text(self.epilog)
2645
+
2646
+ # determine help from format above
2647
+ return formatter.format_help()
2648
+
2649
+ def format_version(self):
2650
+ import warnings
2651
+ warnings.warn(
2652
+ 'The format_version method is deprecated -- the "version" '
2653
+ 'argument to ArgumentParser is no longer supported.',
2654
+ DeprecationWarning)
2655
+ formatter = self._get_formatter()
2656
+ formatter.add_text(self.version)
2657
+ return formatter.format_help()
2658
+
2659
+ def _get_formatter(self):
2660
+ return self.formatter_class(prog=self.prog)
2661
+
2662
+ # =====================
2663
+ # Help-printing methods
2664
+ # =====================
2665
+ def print_usage(self, file=None):
2666
+ if file is None:
2667
+ file = _sys.stdout
2668
+ self._print_message(self.format_usage(), file)
2669
+
2670
+ def print_help(self, file=None):
2671
+ if file is None:
2672
+ file = _sys.stdout
2673
+ self._print_message(self.format_help(), file)
2674
+
2675
+ def print_version(self, file=None):
2676
+ import warnings
2677
+ warnings.warn(
2678
+ 'The print_version method is deprecated -- the "version" '
2679
+ 'argument to ArgumentParser is no longer supported.',
2680
+ DeprecationWarning)
2681
+ self._print_message(self.format_version(), file)
2682
+
2683
+ def _print_message(self, message, file=None):
2684
+ if message:
2685
+ if file is None:
2686
+ file = _sys.stderr
2687
+ file.write(message)
2688
+
2689
+ # ===============
2690
+ # Exiting methods
2691
+ # ===============
2692
+ def exit(self, status=0, message=None):
2693
+ if message:
2694
+ self._print_message(message, _sys.stderr)
2695
+ _sys.exit(status)
2696
+
2697
+ def error(self, message):
2698
+ """error(message: string)
2699
+
2700
+ Prints a usage message incorporating the message to stderr and
2701
+ exits.
2702
+
2703
+ If you override this in a subclass, it should not return -- it
2704
+ should either exit or raise an exception.
2705
+ """
2706
+ self.print_usage(_sys.stderr)
2707
+ self.exit(2, _('%s: error: %s\n') % (self.prog, message))
2708
--
43
--
2709
2.13.5
44
2.24.1
2710
45
2711
46
diff view generated by jsdifflib
New patch
1
This test can run just fine with other values for refcount_bits, so we
2
should filter the value from qcow2.py's dump-header. In fact, we can
3
filter everything but the feature bits and header extensions, because
4
that is what the test is about.
1
5
6
(036 currently ignores user-specified image options, but that will be
7
fixed in the next patch.)
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Message-id: 20191107163708.833192-6-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/036 | 9 ++++---
15
tests/qemu-iotests/036.out | 48 --------------------------------------
16
2 files changed, 6 insertions(+), 51 deletions(-)
17
18
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/036
21
+++ b/tests/qemu-iotests/036
22
@@ -XXX,XX +XXX,XX @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
23
24
# Without feature table
25
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
26
-$PYTHON qcow2.py "$TEST_IMG" dump-header
27
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
28
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
29
_img_info
30
31
# With feature table containing bit 63
32
@@ -XXX,XX +XXX,XX @@ echo === Create image with unknown autoclear feature bit ===
33
echo
34
_make_test_img 64M
35
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
36
-$PYTHON qcow2.py "$TEST_IMG" dump-header
37
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
38
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
39
40
echo
41
echo === Repair image ===
42
echo
43
_check_test_img -r all
44
45
-$PYTHON qcow2.py "$TEST_IMG" dump-header
46
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
47
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
48
49
# success, all done
50
echo "*** done"
51
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
52
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/036.out
54
+++ b/tests/qemu-iotests/036.out
55
@@ -XXX,XX +XXX,XX @@ QA output created by 036
56
=== Image with unknown incompatible feature bit ===
57
58
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
59
-magic 0x514649fb
60
-version 3
61
-backing_file_offset 0x0
62
-backing_file_size 0x0
63
-cluster_bits 16
64
-size 67108864
65
-crypt_method 0
66
-l1_size 1
67
-l1_table_offset 0x30000
68
-refcount_table_offset 0x10000
69
-refcount_table_clusters 1
70
-nb_snapshots 0
71
-snapshot_offset 0x0
72
incompatible_features [63]
73
compatible_features []
74
autoclear_features []
75
-refcount_order 4
76
-header_length 104
77
-
78
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: 8000000000000000
79
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature
80
81
@@ -XXX,XX +XXX,XX @@ qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): tes
82
=== Create image with unknown autoclear feature bit ===
83
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
85
-magic 0x514649fb
86
-version 3
87
-backing_file_offset 0x0
88
-backing_file_size 0x0
89
-cluster_bits 16
90
-size 67108864
91
-crypt_method 0
92
-l1_size 1
93
-l1_table_offset 0x30000
94
-refcount_table_offset 0x10000
95
-refcount_table_clusters 1
96
-nb_snapshots 0
97
-snapshot_offset 0x0
98
incompatible_features []
99
compatible_features []
100
autoclear_features [63]
101
-refcount_order 4
102
-header_length 104
103
-
104
Header extension:
105
magic 0x6803f857
106
length 192
107
@@ -XXX,XX +XXX,XX @@ data <binary>
108
=== Repair image ===
109
110
No errors were found on the image.
111
-magic 0x514649fb
112
-version 3
113
-backing_file_offset 0x0
114
-backing_file_size 0x0
115
-cluster_bits 16
116
-size 67108864
117
-crypt_method 0
118
-l1_size 1
119
-l1_table_offset 0x30000
120
-refcount_table_offset 0x10000
121
-refcount_table_clusters 1
122
-nb_snapshots 0
123
-snapshot_offset 0x0
124
incompatible_features []
125
compatible_features []
126
autoclear_features []
127
-refcount_order 4
128
-header_length 104
129
-
130
Header extension:
131
magic 0x6803f857
132
length 192
133
--
134
2.24.1
135
136
diff view generated by jsdifflib
New patch
1
Some tests require compat=1.1 and thus set IMGOPTS='compat=1.1'
2
globally. That is not how it should be done; instead, they should
3
simply set _unsupported_imgopts to compat=0.10 (compat=1.1 is the
4
default anyway).
1
5
6
This makes the tests heed user-specified $IMGOPTS. Some do not work
7
with all image options, though, so we need to disable them accordingly.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Maxim Levitsky <mlevitsky@redhat.com>
11
Message-id: 20191107163708.833192-7-mreitz@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/036 | 3 +--
15
tests/qemu-iotests/060 | 4 ++--
16
tests/qemu-iotests/062 | 3 ++-
17
tests/qemu-iotests/066 | 3 ++-
18
tests/qemu-iotests/068 | 3 ++-
19
tests/qemu-iotests/098 | 4 ++--
20
6 files changed, 11 insertions(+), 9 deletions(-)
21
22
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/036
25
+++ b/tests/qemu-iotests/036
26
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
27
# This tests qcow2-specific low-level functionality
28
_supported_fmt qcow2
29
_supported_proto file
30
-
31
# Only qcow2v3 and later supports feature bits
32
-IMGOPTS="compat=1.1"
33
+_unsupported_imgopts 'compat=0.10'
34
35
echo
36
echo === Image with unknown incompatible feature bit ===
37
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
38
index XXXXXXX..XXXXXXX 100755
39
--- a/tests/qemu-iotests/060
40
+++ b/tests/qemu-iotests/060
41
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
42
_supported_fmt qcow2
43
_supported_proto file
44
_supported_os Linux
45
+# These tests only work for compat=1.1 images with refcount_bits=16
46
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
47
48
# The repair process will create a large file - so check for availability first
49
_require_large_file 64G
50
@@ -XXX,XX +XXX,XX @@ l1_offset=196608 # 0x30000 (XXX: just an assumption)
51
l2_offset=262144 # 0x40000 (XXX: just an assumption)
52
l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
53
54
-IMGOPTS="compat=1.1"
55
-
56
OPEN_RW="open -o overlap-check=all $TEST_IMG"
57
# Overlap checks are done before write operations only, therefore opening an
58
# image read-only makes the overlap-check option irrelevant
59
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
60
index XXXXXXX..XXXXXXX 100755
61
--- a/tests/qemu-iotests/062
62
+++ b/tests/qemu-iotests/062
63
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
64
# This tests qcow2-specific low-level functionality
65
_supported_fmt qcow2
66
_supported_proto generic
67
+# We need zero clusters and snapshots
68
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
69
70
-IMGOPTS="compat=1.1"
71
IMG_SIZE=64M
72
73
echo
74
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
75
index XXXXXXX..XXXXXXX 100755
76
--- a/tests/qemu-iotests/066
77
+++ b/tests/qemu-iotests/066
78
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
79
# This tests qcow2-specific low-level functionality
80
_supported_fmt qcow2
81
_supported_proto generic
82
+# We need zero clusters and snapshots
83
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
84
85
# Intentionally create an unaligned image
86
-IMGOPTS="compat=1.1"
87
IMG_SIZE=$((64 * 1024 * 1024 + 512))
88
89
echo
90
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
91
index XXXXXXX..XXXXXXX 100755
92
--- a/tests/qemu-iotests/068
93
+++ b/tests/qemu-iotests/068
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
95
# This tests qcow2-specific low-level functionality
96
_supported_fmt qcow2
97
_supported_proto generic
98
+# Internal snapshots are (currently) impossible with refcount_bits=1
99
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
100
101
-IMGOPTS="compat=1.1"
102
IMG_SIZE=128K
103
104
case "$QEMU_DEFAULT_MACHINE" in
105
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
106
index XXXXXXX..XXXXXXX 100755
107
--- a/tests/qemu-iotests/098
108
+++ b/tests/qemu-iotests/098
109
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
110
111
_supported_fmt qcow2
112
_supported_proto file
113
-
114
-IMGOPTS="compat=1.1"
115
+# The code path we want to test here only works for compat=1.1 images
116
+_unsupported_imgopts 'compat=0.10'
117
118
for event in l1_update empty_image_prepare reftable_update refblock_alloc; do
119
120
--
121
2.24.1
122
123
diff view generated by jsdifflib
New patch
1
IMGOPTS can never be empty for qcow2, because the check scripts adds
2
compat=1.1 unless the user specified any compat option themselves.
3
Thus, this block does not do anything and can be dropped.
1
4
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
7
Message-id: 20191107163708.833192-8-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/050 | 4 ----
11
1 file changed, 4 deletions(-)
12
13
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/050
16
+++ b/tests/qemu-iotests/050
17
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
18
_supported_fmt qcow2 qed
19
_supported_proto file
20
21
-if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
22
- IMGOPTS=compat=1.1
23
-fi
24
-
25
echo
26
echo "== Creating images =="
27
28
--
29
2.24.1
30
31
diff view generated by jsdifflib
New patch
1
This will allow us to add more options than just -b.
1
2
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
5
Message-id: 20191107163708.833192-9-mreitz@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/common.rc | 28 ++++++++++++++++++++--------
9
1 file changed, 20 insertions(+), 8 deletions(-)
10
11
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/common.rc
14
+++ b/tests/qemu-iotests/common.rc
15
@@ -XXX,XX +XXX,XX @@ _make_test_img()
16
# extra qemu-img options can be added by tests
17
# at least one argument (the image size) needs to be added
18
local extra_img_options=""
19
- local image_size=$*
20
local optstr=""
21
local img_name=""
22
local use_backing=0
23
local backing_file=""
24
local object_options=""
25
+ local misc_params=()
26
27
if [ -n "$TEST_IMG_FILE" ]; then
28
img_name=$TEST_IMG_FILE
29
@@ -XXX,XX +XXX,XX @@ _make_test_img()
30
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
31
fi
32
33
- if [ "$1" = "-b" ]; then
34
- use_backing=1
35
- backing_file=$2
36
- image_size=$3
37
- fi
38
+ for param; do
39
+ if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
40
+ backing_file=$param
41
+ continue
42
+ fi
43
+
44
+ case "$param" in
45
+ -b)
46
+ use_backing=1
47
+ ;;
48
+
49
+ *)
50
+ misc_params=("${misc_params[@]}" "$param")
51
+ ;;
52
+ esac
53
+ done
54
+
55
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
56
optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
57
fi
58
@@ -XXX,XX +XXX,XX @@ _make_test_img()
59
# XXX(hch): have global image options?
60
(
61
if [ $use_backing = 1 ]; then
62
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
63
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" "${misc_params[@]}" 2>&1
64
else
65
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
66
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" "${misc_params[@]}" 2>&1
67
fi
68
) | _filter_img_create
69
70
--
71
2.24.1
72
73
diff view generated by jsdifflib
New patch
1
Blindly overriding IMGOPTS is suboptimal as this discards user-specified
2
options. Whatever options the test needs should simply be appended.
1
3
4
Some tests do this (with IMGOPTS=$(_optstr_add "$IMGOPTS" "...")), but
5
that is cumbersome. It’s simpler to just give _make_test_img an -o
6
parameter with which tests can add options.
7
8
Some tests actually must override the user-specified options, though,
9
for example when creating an image in a different format than the test
10
$IMGFMT. For such cases, --no-opts allows clearing the current option
11
list.
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
15
Message-id: 20191107163708.833192-10-mreitz@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
tests/qemu-iotests/common.rc | 13 +++++++++++++
19
1 file changed, 13 insertions(+)
20
21
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
22
index XXXXXXX..XXXXXXX 100644
23
--- a/tests/qemu-iotests/common.rc
24
+++ b/tests/qemu-iotests/common.rc
25
@@ -XXX,XX +XXX,XX @@ _make_test_img()
26
local use_backing=0
27
local backing_file=""
28
local object_options=""
29
+ local opts_param=false
30
local misc_params=()
31
32
if [ -n "$TEST_IMG_FILE" ]; then
33
@@ -XXX,XX +XXX,XX @@ _make_test_img()
34
if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
35
backing_file=$param
36
continue
37
+ elif $opts_param; then
38
+ optstr=$(_optstr_add "$optstr" "$param")
39
+ opts_param=false
40
+ continue
41
fi
42
43
case "$param" in
44
@@ -XXX,XX +XXX,XX @@ _make_test_img()
45
use_backing=1
46
;;
47
48
+ -o)
49
+ opts_param=true
50
+ ;;
51
+
52
+ --no-opts)
53
+ optstr=""
54
+ ;;
55
+
56
*)
57
misc_params=("${misc_params[@]}" "$param")
58
;;
59
--
60
2.24.1
61
62
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
It did not matter before, but now that _make_test_img understands -o, we
2
should use it properly here.
2
3
3
The level of the burst bucket is stored in bkt.burst_level, not
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
bkt.burst_length.
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
5
6
Message-id: 20191107163708.833192-11-mreitz@redhat.com
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
8
Message-id: 49aab2711d02f285567f3b3b13a113847af33812.1503580370.git.berto@igalia.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
8
---
11
include/qemu/throttle.h | 2 +-
9
tests/qemu-iotests/051 | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
10
1 file changed, 1 insertion(+), 1 deletion(-)
13
11
14
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
12
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100755
16
--- a/include/qemu/throttle.h
14
--- a/tests/qemu-iotests/051
17
+++ b/include/qemu/throttle.h
15
+++ b/tests/qemu-iotests/051
18
@@ -XXX,XX +XXX,XX @@ typedef enum {
16
@@ -XXX,XX +XXX,XX @@ echo
19
* - The bkt.avg rate does not apply until the bucket is full,
17
echo === With version 2 images enabling lazy refcounts must fail ===
20
* allowing the user to do bursts until then. The I/O limit during
18
echo
21
* bursts is bkt.max. To enforce this limit we keep an additional
19
22
- * bucket in bkt.burst_length that leaks at a rate of bkt.max units
20
-_make_test_img -ocompat=0.10 $size
23
+ * bucket in bkt.burst_level that leaks at a rate of bkt.max units
21
+_make_test_img -o compat=0.10 $size
24
* per second.
22
25
*
23
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=on
26
* - Because of all of the above, the user can perform I/O at a
24
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=off
27
--
25
--
28
2.13.5
26
2.24.1
29
27
30
28
diff view generated by jsdifflib
New patch
1
Tests should not overwrite all user-supplied image options, but only add
2
to it (which will effectively overwrite conflicting values). Accomplish
3
this by passing options to _make_test_img via -o instead of $IMGOPTS.
1
4
5
For some tests, there is no functional change because they already only
6
appended options to IMGOPTS. For these, this patch is just a
7
simplification.
8
9
For others, this is a change, so they now heed user-specified $IMGOPTS.
10
Some of those tests do not work with all image options, though, so we
11
need to disable them accordingly.
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
15
Message-id: 20191107163708.833192-12-mreitz@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
tests/qemu-iotests/031 | 9 ++++---
19
tests/qemu-iotests/039 | 24 ++++++------------
20
tests/qemu-iotests/059 | 18 ++++++-------
21
tests/qemu-iotests/060 | 6 ++---
22
tests/qemu-iotests/061 | 57 ++++++++++++++++++++++--------------------
23
tests/qemu-iotests/079 | 3 +--
24
tests/qemu-iotests/106 | 2 +-
25
tests/qemu-iotests/108 | 2 +-
26
tests/qemu-iotests/112 | 32 ++++++++++++------------
27
tests/qemu-iotests/115 | 3 +--
28
tests/qemu-iotests/121 | 6 ++---
29
tests/qemu-iotests/125 | 2 +-
30
tests/qemu-iotests/137 | 2 +-
31
tests/qemu-iotests/138 | 3 +--
32
tests/qemu-iotests/175 | 2 +-
33
tests/qemu-iotests/190 | 2 +-
34
tests/qemu-iotests/191 | 3 +--
35
tests/qemu-iotests/220 | 4 ++-
36
tests/qemu-iotests/243 | 6 +++--
37
tests/qemu-iotests/244 | 10 +++++---
38
tests/qemu-iotests/250 | 3 +--
39
tests/qemu-iotests/265 | 2 +-
40
22 files changed, 100 insertions(+), 101 deletions(-)
41
42
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
43
index XXXXXXX..XXXXXXX 100755
44
--- a/tests/qemu-iotests/031
45
+++ b/tests/qemu-iotests/031
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
47
# This tests qcow2-specific low-level functionality
48
_supported_fmt qcow2
49
_supported_proto file
50
+# We want to test compat=0.10, which does not support refcount widths
51
+# other than 16
52
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
53
54
CLUSTER_SIZE=65536
55
56
# qcow2.py output depends on the exact options used, so override the command
57
# line here as an exception
58
-for IMGOPTS in "compat=0.10" "compat=1.1"; do
59
+for compat in "compat=0.10" "compat=1.1"; do
60
61
echo
62
- echo ===== Testing with -o $IMGOPTS =====
63
+ echo ===== Testing with -o $compat =====
64
echo
65
echo === Create image with unknown header extension ===
66
echo
67
- _make_test_img 64M
68
+ _make_test_img -o $compat 64M
69
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
70
$PYTHON qcow2.py "$TEST_IMG" dump-header
71
_check_test_img
72
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
73
index XXXXXXX..XXXXXXX 100755
74
--- a/tests/qemu-iotests/039
75
+++ b/tests/qemu-iotests/039
76
@@ -XXX,XX +XXX,XX @@ size=128M
77
echo
78
echo "== Checking that image is clean on shutdown =="
79
80
-IMGOPTS="compat=1.1,lazy_refcounts=on"
81
-_make_test_img $size
82
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
83
84
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
85
86
@@ -XXX,XX +XXX,XX @@ _check_test_img
87
echo
88
echo "== Creating a dirty image file =="
89
90
-IMGOPTS="compat=1.1,lazy_refcounts=on"
91
-_make_test_img $size
92
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
93
94
_NO_VALGRIND \
95
$QEMU_IO -c "write -P 0x5a 0 512" \
96
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
97
echo
98
echo "== Opening a dirty image read/write should repair it =="
99
100
-IMGOPTS="compat=1.1,lazy_refcounts=on"
101
-_make_test_img $size
102
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
103
104
_NO_VALGRIND \
105
$QEMU_IO -c "write -P 0x5a 0 512" \
106
@@ -XXX,XX +XXX,XX @@ $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
107
echo
108
echo "== Creating an image file with lazy_refcounts=off =="
109
110
-IMGOPTS="compat=1.1,lazy_refcounts=off"
111
-_make_test_img $size
112
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
113
114
_NO_VALGRIND \
115
$QEMU_IO -c "write -P 0x5a 0 512" \
116
@@ -XXX,XX +XXX,XX @@ _check_test_img
117
echo
118
echo "== Committing to a backing file with lazy_refcounts=on =="
119
120
-IMGOPTS="compat=1.1,lazy_refcounts=on"
121
-TEST_IMG="$TEST_IMG".base _make_test_img $size
122
+TEST_IMG="$TEST_IMG".base _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
123
124
-IMGOPTS="compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base"
125
-_make_test_img $size
126
+_make_test_img -o "compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base" $size
127
128
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
129
$QEMU_IMG commit "$TEST_IMG"
130
@@ -XXX,XX +XXX,XX @@ TEST_IMG="$TEST_IMG".base _check_test_img
131
echo
132
echo "== Changing lazy_refcounts setting at runtime =="
133
134
-IMGOPTS="compat=1.1,lazy_refcounts=off"
135
-_make_test_img $size
136
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
137
138
_NO_VALGRIND \
139
$QEMU_IO -c "reopen -o lazy-refcounts=on" \
140
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
141
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
142
_check_test_img
143
144
-IMGOPTS="compat=1.1,lazy_refcounts=on"
145
-_make_test_img $size
146
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
147
148
_NO_VALGRIND \
149
$QEMU_IO -c "reopen -o lazy-refcounts=off" \
150
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
151
index XXXXXXX..XXXXXXX 100755
152
--- a/tests/qemu-iotests/059
153
+++ b/tests/qemu-iotests/059
154
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00"
155
156
echo
157
echo "=== Testing monolithicFlat creation and opening ==="
158
-IMGOPTS="subformat=monolithicFlat" _make_test_img 2G
159
+_make_test_img -o "subformat=monolithicFlat" 2G
160
_img_info
161
_cleanup_test_img
162
163
echo
164
echo "=== Testing monolithicFlat with zeroed_grain ==="
165
-IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
166
+_make_test_img -o "subformat=monolithicFlat,zeroed_grain=on" 2G
167
_cleanup_test_img
168
169
echo
170
echo "=== Testing big twoGbMaxExtentFlat ==="
171
-IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G
172
+_make_test_img -o "subformat=twoGbMaxExtentFlat" 1000G
173
$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/'
174
_cleanup_test_img
175
176
@@ -XXX,XX +XXX,XX @@ _img_info
177
178
echo
179
echo "=== Testing truncated sparse ==="
180
-IMGOPTS="subformat=monolithicSparse" _make_test_img 100G
181
+_make_test_img -o "subformat=monolithicSparse" 100G
182
truncate -s 10M $TEST_IMG
183
_img_info
184
185
echo
186
echo "=== Converting to streamOptimized from image with small cluster size==="
187
-TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G
188
+TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 _make_test_img -o "cluster_size=4096" 1G
189
$QEMU_IO -f qcow2 -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io
190
$QEMU_IO -f qcow2 -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io
191
$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1
192
@@ -XXX,XX +XXX,XX @@ echo "=== Testing monolithicFlat with internally generated JSON file name ==="
193
194
echo '--- blkdebug ---'
195
# Should work, because bdrv_dirname() works fine with blkdebug
196
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
197
+_make_test_img -o "subformat=monolithicFlat" 64M
198
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
199
-c info \
200
2>&1 \
201
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
202
203
echo '--- quorum ---'
204
# Should not work, because bdrv_dirname() does not work with quorum
205
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
206
+_make_test_img -o "subformat=monolithicFlat" 64M
207
cp "$TEST_IMG" "$TEST_IMG.orig"
208
209
filename="json:{
210
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
211
212
echo
213
echo "=== Testing 4TB monolithicFlat creation and IO ==="
214
-IMGOPTS="subformat=monolithicFlat" _make_test_img 4T
215
+_make_test_img -o "subformat=monolithicFlat" 4T
216
_img_info
217
$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io
218
$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io
219
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
220
echo
221
echo "=== Testing qemu-img map on extents ==="
222
for fmt in monolithicSparse twoGbMaxExtentSparse; do
223
- IMGOPTS="subformat=$fmt" _make_test_img 31G
224
+ _make_test_img -o "subformat=$fmt" 31G
225
$QEMU_IO -c "write 65024 1k" "$TEST_IMG" | _filter_qemu_io
226
$QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io
227
$QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io
228
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
229
index XXXXXXX..XXXXXXX 100755
230
--- a/tests/qemu-iotests/060
231
+++ b/tests/qemu-iotests/060
232
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
233
# compat=0.10 is required in order to make the following discard actually
234
# unallocate the sector rather than make it a zero sector - we want COW, after
235
# all.
236
-IMGOPTS='compat=0.10' _make_test_img -b "$BACKING_IMG" 1G
237
+_make_test_img -o 'compat=0.10' -b "$BACKING_IMG" 1G
238
# Write two clusters, the second one enforces creation of an L2 table after
239
# the first data cluster.
240
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
241
@@ -XXX,XX +XXX,XX @@ echo
242
echo "=== Discarding a non-covered in-bounds refblock ==="
243
echo
244
245
-IMGOPTS='refcount_bits=1' _make_test_img 64M
246
+_make_test_img -o 'refcount_bits=1' 64M
247
248
# Pretend there's a refblock somewhere where there is no refblock to
249
# cover it (but the covering refblock has a valid index in the
250
@@ -XXX,XX +XXX,XX @@ echo
251
echo "=== Discarding a refblock covered by an unaligned refblock ==="
252
echo
253
254
-IMGOPTS='refcount_bits=1' _make_test_img 64M
255
+_make_test_img -o 'refcount_bits=1' 64M
256
257
# Same as above
258
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
259
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
260
index XXXXXXX..XXXXXXX 100755
261
--- a/tests/qemu-iotests/061
262
+++ b/tests/qemu-iotests/061
263
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
264
_supported_fmt qcow2
265
_supported_proto file
266
_supported_os Linux
267
+# Conversion between different compat versions can only really work
268
+# with refcount_bits=16
269
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
270
271
echo
272
echo "=== Testing version downgrade with zero expansion ==="
273
echo
274
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
275
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
276
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
277
$PYTHON qcow2.py "$TEST_IMG" dump-header
278
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
279
@@ -XXX,XX +XXX,XX @@ _check_test_img
280
echo
281
echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
282
echo
283
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
284
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
285
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
286
$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
287
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
288
@@ -XXX,XX +XXX,XX @@ _check_test_img
289
echo
290
echo "=== Testing dirty version downgrade ==="
291
echo
292
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
293
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
294
_NO_VALGRIND \
295
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
296
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
297
@@ -XXX,XX +XXX,XX @@ _check_test_img
298
echo
299
echo "=== Testing version downgrade with unknown compat/autoclear flags ==="
300
echo
301
-IMGOPTS="compat=1.1" _make_test_img 64M
302
+_make_test_img -o "compat=1.1" 64M
303
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
304
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
305
$PYTHON qcow2.py "$TEST_IMG" dump-header
306
@@ -XXX,XX +XXX,XX @@ _check_test_img
307
echo
308
echo "=== Testing version upgrade and resize ==="
309
echo
310
-IMGOPTS="compat=0.10" _make_test_img 64M
311
+_make_test_img -o "compat=0.10" 64M
312
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
313
$PYTHON qcow2.py "$TEST_IMG" dump-header
314
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
315
@@ -XXX,XX +XXX,XX @@ _check_test_img
316
echo
317
echo "=== Testing dirty lazy_refcounts=off ==="
318
echo
319
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
320
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
321
_NO_VALGRIND \
322
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
323
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
324
@@ -XXX,XX +XXX,XX @@ _check_test_img
325
echo
326
echo "=== Testing backing file ==="
327
echo
328
-IMGOPTS="compat=1.1" _make_test_img 64M
329
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
330
+_make_test_img -o "compat=1.1" 64M
331
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
332
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
333
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
334
$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" "$TEST_IMG"
335
@@ -XXX,XX +XXX,XX @@ _check_test_img
336
echo
337
echo "=== Testing invalid configurations ==="
338
echo
339
-IMGOPTS="compat=0.10" _make_test_img 64M
340
+_make_test_img -o "compat=0.10" 64M
341
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
342
$QEMU_IMG amend -o "compat=1.1" "$TEST_IMG" # actually valid
343
$QEMU_IMG amend -o "compat=0.10,lazy_refcounts=on" "$TEST_IMG"
344
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG amend -o "preallocation=on" "$TEST_IMG"
345
echo
346
echo "=== Testing correct handling of unset value ==="
347
echo
348
-IMGOPTS="compat=1.1,cluster_size=1k" _make_test_img 64M
349
+_make_test_img -o "compat=1.1,cluster_size=1k" 64M
350
echo "Should work:"
351
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
352
echo "Should not work:" # Just to know which of these tests actually fails
353
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG amend -o "cluster_size=64k" "$TEST_IMG"
354
echo
355
echo "=== Testing zero expansion on inactive clusters ==="
356
echo
357
-IMGOPTS="compat=1.1" _make_test_img 64M
358
+_make_test_img -o "compat=1.1" 64M
359
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
360
$QEMU_IMG snapshot -c foo "$TEST_IMG"
361
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
362
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
363
echo
364
echo "=== Testing zero expansion on shared L2 table ==="
365
echo
366
-IMGOPTS="compat=1.1" _make_test_img 64M
367
+_make_test_img -o "compat=1.1" 64M
368
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
369
$QEMU_IMG snapshot -c foo "$TEST_IMG"
370
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
371
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
372
echo
373
echo "=== Testing zero expansion on backed image ==="
374
echo
375
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
376
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
377
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
378
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
379
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
380
$QEMU_IO -c "read -P 0x2a 0 128k" -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
381
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
382
_check_test_img
383
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
384
echo
385
echo "=== Testing zero expansion on backed inactive clusters ==="
386
echo
387
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
388
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
389
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
390
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
391
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
392
$QEMU_IO -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
393
$QEMU_IMG snapshot -c foo "$TEST_IMG"
394
$QEMU_IO -c "write -P 0x42 0 128k" "$TEST_IMG" | _filter_qemu_io
395
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
396
echo
397
echo "=== Testing zero expansion on backed image with shared L2 table ==="
398
echo
399
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
400
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
401
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
402
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
403
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
404
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
405
$QEMU_IMG snapshot -c foo "$TEST_IMG"
406
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
407
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
408
echo
409
echo "=== Testing preallocated zero expansion on full image ==="
410
echo
411
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG" _make_test_img 64M
412
+TEST_IMG="$TEST_IMG" _make_test_img -o "compat=1.1" 64M
413
$QEMU_IO -c "write -P 0x2a 0 64M" "$TEST_IMG" -c "write -z 0 64M" | _filter_qemu_io
414
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
415
_check_test_img
416
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64M" "$TEST_IMG" | _filter_qemu_io
417
echo
418
echo "=== Testing progress report without snapshot ==="
419
echo
420
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
421
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
422
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
423
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
424
$QEMU_IO -c "write -z 0 64k" \
425
-c "write -z 1G 64k" \
426
-c "write -z 2G 64k" \
427
@@ -XXX,XX +XXX,XX @@ _check_test_img
428
echo
429
echo "=== Testing progress report with snapshot ==="
430
echo
431
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
432
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
433
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
434
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
435
$QEMU_IO -c "write -z 0 64k" \
436
-c "write -z 1G 64k" \
437
-c "write -z 2G 64k" \
438
@@ -XXX,XX +XXX,XX @@ _check_test_img
439
echo
440
echo "=== Testing version downgrade with external data file ==="
441
echo
442
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
443
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
444
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
445
_img_info --format-specific
446
_check_test_img
447
@@ -XXX,XX +XXX,XX @@ _check_test_img
448
echo
449
echo "=== Try changing the external data file ==="
450
echo
451
-IMGOPTS="compat=1.1" _make_test_img 64M
452
+_make_test_img -o "compat=1.1" 64M
453
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
454
455
echo
456
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
457
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
458
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
459
_img_info --format-specific
460
TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
461
@@ -XXX,XX +XXX,XX @@ TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info -
462
echo
463
echo "=== Clearing and setting data-file-raw ==="
464
echo
465
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
466
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" 64M
467
$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG"
468
_img_info --format-specific
469
_check_test_img
470
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
471
index XXXXXXX..XXXXXXX 100755
472
--- a/tests/qemu-iotests/079
473
+++ b/tests/qemu-iotests/079
474
@@ -XXX,XX +XXX,XX @@ echo
475
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
476
477
for s in $cluster_sizes; do
478
- IMGOPTS=$(_optstr_add "$IMGOPTS" "preallocation=metadata,cluster_size=$s") \
479
- _make_test_img 4G
480
+ _make_test_img -o "preallocation=metadata,cluster_size=$s" 4G
481
done
482
483
# success, all done
484
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
485
index XXXXXXX..XXXXXXX 100755
486
--- a/tests/qemu-iotests/106
487
+++ b/tests/qemu-iotests/106
488
@@ -XXX,XX +XXX,XX @@ for create_mode in off falloc full; do
489
echo
490
echo "--- create_mode=$create_mode growth_mode=$growth_mode ---"
491
492
- IMGOPTS="preallocation=$create_mode" _make_test_img ${CREATION_SIZE}K
493
+ _make_test_img -o "preallocation=$create_mode" ${CREATION_SIZE}K
494
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
495
496
expected_size=0
497
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
498
index XXXXXXX..XXXXXXX 100755
499
--- a/tests/qemu-iotests/108
500
+++ b/tests/qemu-iotests/108
501
@@ -XXX,XX +XXX,XX @@ echo
502
echo '=== Repairing unreferenced data cluster in new refblock area ==='
503
echo
504
505
-IMGOPTS='cluster_size=512' _make_test_img 64M
506
+_make_test_img -o 'cluster_size=512' 64M
507
# Allocate the first 128 kB in the image (first refblock)
508
$QEMU_IO -c 'write 0 0x1b200' "$TEST_IMG" | _filter_qemu_io
509
# should be 131072 == 0x20000
510
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
511
index XXXXXXX..XXXXXXX 100755
512
--- a/tests/qemu-iotests/112
513
+++ b/tests/qemu-iotests/112
514
@@ -XXX,XX +XXX,XX @@ echo '=== refcount_bits limits ==='
515
echo
516
517
# Must be positive (non-zero)
518
-IMGOPTS="$IMGOPTS,refcount_bits=0" _make_test_img 64M
519
+_make_test_img -o "refcount_bits=0" 64M
520
# Must be positive (non-negative)
521
-IMGOPTS="$IMGOPTS,refcount_bits=-1" _make_test_img 64M
522
+_make_test_img -o "refcount_bits=-1" 64M
523
# May not exceed 64
524
-IMGOPTS="$IMGOPTS,refcount_bits=128" _make_test_img 64M
525
+_make_test_img -o "refcount_bits=128" 64M
526
# Must be a power of two
527
-IMGOPTS="$IMGOPTS,refcount_bits=42" _make_test_img 64M
528
+_make_test_img -o "refcount_bits=42" 64M
529
530
# 1 is the minimum
531
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
532
+_make_test_img -o "refcount_bits=1" 64M
533
print_refcount_bits
534
535
# 64 is the maximum
536
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
537
+_make_test_img -o "refcount_bits=64" 64M
538
print_refcount_bits
539
540
# 16 is the default
541
@@ -XXX,XX +XXX,XX @@ echo '=== refcount_bits and compat=0.10 ==='
542
echo
543
544
# Should work
545
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=16" _make_test_img 64M
546
+_make_test_img -o "compat=0.10,refcount_bits=16" 64M
547
print_refcount_bits
548
549
# Should not work
550
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=1" _make_test_img 64M
551
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=64" _make_test_img 64M
552
+_make_test_img -o "compat=0.10,refcount_bits=1" 64M
553
+_make_test_img -o "compat=0.10,refcount_bits=64" 64M
554
555
556
echo
557
echo '=== Snapshot limit on refcount_bits=1 ==='
558
echo
559
560
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
561
+_make_test_img -o "refcount_bits=1" 64M
562
print_refcount_bits
563
564
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
565
@@ -XXX,XX +XXX,XX @@ echo
566
echo '=== Snapshot limit on refcount_bits=2 ==='
567
echo
568
569
-IMGOPTS="$IMGOPTS,refcount_bits=2" _make_test_img 64M
570
+_make_test_img -o "refcount_bits=2" 64M
571
print_refcount_bits
572
573
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
574
@@ -XXX,XX +XXX,XX @@ echo
575
echo '=== Compressed clusters with refcount_bits=1 ==='
576
echo
577
578
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
579
+_make_test_img -o "refcount_bits=1" 64M
580
print_refcount_bits
581
582
# Both should fit into a single host cluster; instead of failing to increase the
583
@@ -XXX,XX +XXX,XX @@ echo
584
echo '=== MSb set in 64 bit refcount ==='
585
echo
586
587
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
588
+_make_test_img -o "refcount_bits=64" 64M
589
print_refcount_bits
590
591
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
592
@@ -XXX,XX +XXX,XX @@ echo
593
echo '=== Snapshot on maximum 64 bit refcount value ==='
594
echo
595
596
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
597
+_make_test_img -o "refcount_bits=64" 64M
598
print_refcount_bits
599
600
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
601
@@ -XXX,XX +XXX,XX @@ echo
602
echo '=== Testing too many references for check ==='
603
echo
604
605
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
606
+_make_test_img -o "refcount_bits=1" 64M
607
print_refcount_bits
608
609
# This cluster should be created at 0x50000
610
@@ -XXX,XX +XXX,XX @@ echo
611
echo '=== Multiple walks necessary during amend ==='
612
echo
613
614
-IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k
615
+_make_test_img -o "refcount_bits=1,cluster_size=512" 64k
616
617
# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a
618
# single L2 table, the reftable and a single refblock. This creates 58 data
619
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
620
index XXXXXXX..XXXXXXX 100755
621
--- a/tests/qemu-iotests/115
622
+++ b/tests/qemu-iotests/115
623
@@ -XXX,XX +XXX,XX @@ echo
624
# least 256 MB. We can achieve that by using preallocation=metadata for an image
625
# which has a guest disk size of 256 MB.
626
627
-IMGOPTS="$IMGOPTS,refcount_bits=64,cluster_size=512,preallocation=metadata" \
628
- _make_test_img 256M
629
+_make_test_img -o "refcount_bits=64,cluster_size=512,preallocation=metadata" 256M
630
631
# We know for sure that the L1 and refcount tables do not overlap with any other
632
# structure because the metadata overlap checks would have caught that case.
633
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
634
index XXXXXXX..XXXXXXX 100755
635
--- a/tests/qemu-iotests/121
636
+++ b/tests/qemu-iotests/121
637
@@ -XXX,XX +XXX,XX @@ echo
638
# Preallocation speeds up the write operation, but preallocating everything will
639
# destroy the purpose of the write; so preallocate one KB less than what would
640
# cause a reftable growth...
641
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64512K
642
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64512K
643
# ...and make the image the desired size afterwards.
644
$QEMU_IMG resize "$TEST_IMG" 65M
645
646
@@ -XXX,XX +XXX,XX @@ echo
647
echo '--- Test 2 ---'
648
echo
649
650
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64513K
651
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64513K
652
# This results in an L1 table growth which in turn results in some clusters at
653
# the start of the image becoming free
654
$QEMU_IMG resize "$TEST_IMG" 65M
655
@@ -XXX,XX +XXX,XX @@ echo
656
echo '=== Allocating a new refcount block must not leave holes in the image ==='
657
echo
658
659
-IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M
660
+_make_test_img -o 'cluster_size=512,refcount_bits=16' 1M
661
662
# This results in an image with 256 used clusters: the qcow2 header,
663
# the refcount table, one refcount block, the L1 table, four L2 tables
664
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
665
index XXXXXXX..XXXXXXX 100755
666
--- a/tests/qemu-iotests/125
667
+++ b/tests/qemu-iotests/125
668
@@ -XXX,XX +XXX,XX @@ for GROWTH_SIZE in 16 48 80; do
669
for growth_mode in off metadata falloc full; do
670
echo "--- cluster_size=$cluster_size growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
671
672
- IMGOPTS="preallocation=$create_mode,cluster_size=$cluster_size" _make_test_img ${CREATION_SIZE}
673
+ _make_test_img -o "preallocation=$create_mode,cluster_size=$cluster_size" ${CREATION_SIZE}
674
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
675
676
host_size_0=$(get_image_size_on_host)
677
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
678
index XXXXXXX..XXXXXXX 100755
679
--- a/tests/qemu-iotests/137
680
+++ b/tests/qemu-iotests/137
681
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
682
-c "reopen -o cache-clean-interval=-1" \
683
"$TEST_IMG" | _filter_qemu_io
684
685
-IMGOPTS="cluster_size=256k" _make_test_img 32P
686
+_make_test_img -o "cluster_size=256k" 32P
687
$QEMU_IO \
688
-c "reopen -o l2-cache-entry-size=512,l2-cache-size=1T" \
689
"$TEST_IMG" | _filter_qemu_io
690
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
691
index XXXXXXX..XXXXXXX 100755
692
--- a/tests/qemu-iotests/138
693
+++ b/tests/qemu-iotests/138
694
@@ -XXX,XX +XXX,XX @@ echo
695
echo '=== Check on an image with a multiple of 2^32 clusters ==='
696
echo
697
698
-IMGOPTS=$(_optstr_add "$IMGOPTS" "cluster_size=512") \
699
- _make_test_img 512
700
+_make_test_img -o "cluster_size=512" 512
701
702
# Allocate L2 table
703
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
704
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
705
index XXXXXXX..XXXXXXX 100755
706
--- a/tests/qemu-iotests/175
707
+++ b/tests/qemu-iotests/175
708
@@ -XXX,XX +XXX,XX @@ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_block
709
for mode in off full falloc; do
710
echo
711
echo "== creating image with preallocation $mode =="
712
- IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
713
+ _make_test_img -o preallocation=$mode $size | _filter_imgfmt
714
stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
715
done
716
717
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
718
index XXXXXXX..XXXXXXX 100755
719
--- a/tests/qemu-iotests/190
720
+++ b/tests/qemu-iotests/190
721
@@ -XXX,XX +XXX,XX @@ _supported_proto file
722
echo "== Huge file =="
723
echo
724
725
-IMGOPTS='cluster_size=2M' _make_test_img 2T
726
+_make_test_img -o 'cluster_size=2M' 2T
727
728
$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
729
$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
730
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
731
index XXXXXXX..XXXXXXX 100755
732
--- a/tests/qemu-iotests/191
733
+++ b/tests/qemu-iotests/191
734
@@ -XXX,XX +XXX,XX @@ echo === Preparing and starting VM ===
735
echo
736
737
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
738
-IMGOPTS=$(_optstr_add "$IMGOPTS" "backing_fmt=$IMGFMT") \
739
- TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
740
+TEST_IMG="${TEST_IMG}.mid" _make_test_img -o "backing_fmt=$IMGFMT" -b "${TEST_IMG}.base"
741
_make_test_img -b "${TEST_IMG}.mid"
742
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
743
744
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
745
index XXXXXXX..XXXXXXX 100755
746
--- a/tests/qemu-iotests/220
747
+++ b/tests/qemu-iotests/220
748
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
749
_supported_fmt qcow2
750
_supported_proto file
751
_supported_os Linux
752
+# To use a different refcount width but 16 bits we need compat=1.1
753
+_unsupported_imgopts 'compat=0.10'
754
755
echo "== Creating huge file =="
756
757
@@ -XXX,XX +XXX,XX @@ echo "== Creating huge file =="
758
# of a HUGE (but very sparse) file. tmpfs works, ext4 does not.
759
_require_large_file 513T
760
761
-IMGOPTS='cluster_size=2M,refcount_bits=1' _make_test_img 513T
762
+_make_test_img -o 'cluster_size=2M,refcount_bits=1' 513T
763
764
echo "== Populating refcounts =="
765
# We want an image with 256M refcounts * 2M clusters = 512T referenced.
766
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
767
index XXXXXXX..XXXXXXX 100755
768
--- a/tests/qemu-iotests/243
769
+++ b/tests/qemu-iotests/243
770
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
771
_supported_fmt qcow2
772
_supported_proto file
773
_supported_os Linux
774
+# External data files do not work with compat=0.10
775
+_unsupported_imgopts 'compat=0.10'
776
777
for mode in off metadata falloc full; do
778
779
@@ -XXX,XX +XXX,XX @@ for mode in off metadata falloc full; do
780
echo "=== preallocation=$mode ==="
781
echo
782
783
- IMGOPTS="preallocation=$mode" _make_test_img 64M
784
+ _make_test_img -o "preallocation=$mode" 64M
785
786
printf "File size: "
787
du -b $TEST_IMG | cut -f1
788
@@ -XXX,XX +XXX,XX @@ for mode in off metadata falloc full; do
789
echo "=== External data file: preallocation=$mode ==="
790
echo
791
792
- IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M
793
+ _make_test_img -o "data_file=$TEST_IMG.data,preallocation=$mode" 64M
794
795
echo -n "qcow2 file size: "
796
du -b $TEST_IMG | cut -f1
797
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
798
index XXXXXXX..XXXXXXX 100755
799
--- a/tests/qemu-iotests/244
800
+++ b/tests/qemu-iotests/244
801
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
802
_supported_fmt qcow2
803
_supported_proto file
804
_supported_os Linux
805
+# External data files do not work with compat=0.10
806
+_unsupported_imgopts 'compat=0.10'
807
808
echo
809
echo "=== Create and open image with external data file ==="
810
echo
811
812
echo "With data file name in the image:"
813
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
814
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
815
_check_test_img
816
817
$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
818
@@ -XXX,XX +XXX,XX @@ echo
819
echo "=== Standalone image with external data file (efficient) ==="
820
echo
821
822
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
823
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
824
825
echo -n "qcow2 file size before I/O: "
826
du -b $TEST_IMG | cut -f1
827
@@ -XXX,XX +XXX,XX @@ echo
828
echo "=== Standalone image with external data file (valid raw) ==="
829
echo
830
831
-IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
832
+_make_test_img -o "data_file=$TEST_IMG.data,data_file_raw=on" 64M
833
834
echo -n "qcow2 file size before I/O: "
835
du -b $TEST_IMG | cut -f1
836
@@ -XXX,XX +XXX,XX @@ echo
837
echo "=== bdrv_co_block_status test for file and offset=0 ==="
838
echo
839
840
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
841
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
842
843
$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
844
$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
845
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
846
index XXXXXXX..XXXXXXX 100755
847
--- a/tests/qemu-iotests/250
848
+++ b/tests/qemu-iotests/250
849
@@ -XXX,XX +XXX,XX @@ disk_usage()
850
}
851
852
size=2100M
853
-IMGOPTS="cluster_size=1M,preallocation=metadata"
854
855
-_make_test_img $size
856
+_make_test_img -o "cluster_size=1M,preallocation=metadata" $size
857
$QEMU_IO -c 'discard 0 10M' -c 'discard 2090M 10M' \
858
-c 'write 2090M 10M' -c 'write 0 10M' "$TEST_IMG" | _filter_qemu_io
859
860
diff --git a/tests/qemu-iotests/265 b/tests/qemu-iotests/265
861
index XXXXXXX..XXXXXXX 100755
862
--- a/tests/qemu-iotests/265
863
+++ b/tests/qemu-iotests/265
864
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
865
echo '--- Writing to the image ---'
866
867
# Reduce cluster size so we get more and quicker I/O
868
-IMGOPTS='cluster_size=4096' _make_test_img 1M
869
+_make_test_img -o 'cluster_size=4096' 1M
870
(for ((kb = 1024 - 4; kb >= 0; kb -= 4)); do \
871
echo "aio_write -P 42 $((kb + 1))k 2k"; \
872
done) \
873
--
874
2.24.1
875
876
diff view generated by jsdifflib
New patch
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
3
Message-id: 20191107163708.833192-13-mreitz@redhat.com
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
6
tests/qemu-iotests/071 | 4 ++--
7
tests/qemu-iotests/174 | 2 +-
8
tests/qemu-iotests/178 | 4 ++--
9
tests/qemu-iotests/197 | 4 ++--
10
tests/qemu-iotests/215 | 4 ++--
11
5 files changed, 9 insertions(+), 9 deletions(-)
1
12
13
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/071
16
+++ b/tests/qemu-iotests/071
17
@@ -XXX,XX +XXX,XX @@ echo
18
echo "=== Testing blkverify through filename ==="
19
echo
20
21
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
22
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
23
_filter_imgfmt
24
_make_test_img $IMG_SIZE
25
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \
26
@@ -XXX,XX +XXX,XX @@ echo
27
echo "=== Testing blkverify through file blockref ==="
28
echo
29
30
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
31
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
32
_filter_imgfmt
33
_make_test_img $IMG_SIZE
34
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \
35
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
36
index XXXXXXX..XXXXXXX 100755
37
--- a/tests/qemu-iotests/174
38
+++ b/tests/qemu-iotests/174
39
@@ -XXX,XX +XXX,XX @@ _unsupported_fmt raw
40
41
42
size=256K
43
-IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt
44
+IMGFMT=raw IMGKEYSECRET= _make_test_img --no-opts $size | _filter_imgfmt
45
46
echo
47
echo "== reading wrong format should fail =="
48
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
49
index XXXXXXX..XXXXXXX 100755
50
--- a/tests/qemu-iotests/178
51
+++ b/tests/qemu-iotests/178
52
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format
53
54
make_test_img_with_fmt() {
55
# Shadow global variables within this function
56
- local IMGFMT="$1" IMGOPTS=""
57
- _make_test_img "$2"
58
+ local IMGFMT="$1"
59
+ _make_test_img --no-opts "$2"
60
}
61
62
qemu_io_with_fmt() {
63
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
64
index XXXXXXX..XXXXXXX 100755
65
--- a/tests/qemu-iotests/197
66
+++ b/tests/qemu-iotests/197
67
@@ -XXX,XX +XXX,XX @@ if [ "$IMGFMT" = "vpc" ]; then
68
fi
69
_make_test_img 4G
70
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
71
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
72
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
73
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
74
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
75
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
76
77
# Ensure that a read of two clusters, but where one is already allocated,
78
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/215
81
+++ b/tests/qemu-iotests/215
82
@@ -XXX,XX +XXX,XX @@ if [ "$IMGFMT" = "vpc" ]; then
83
fi
84
_make_test_img 4G
85
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
86
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
87
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
88
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
89
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
90
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
91
92
# Ensure that a read of two clusters, but where one is already allocated,
93
--
94
2.24.1
95
96
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Overwriting IMGOPTS means ignoring all user-supplied options, which is
2
not what we want. Replace the current IMGOPTS use by a new BACKING_FILE
3
variable.
2
4
3
Both the throttling limits set with the throttling.iops-* and
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
throttling.bps-* options and their QMP equivalents defined in the
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
5
BlockIOThrottle struct are integer values.
7
Message-id: 20191107163708.833192-14-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/267 | 12 ++++++++----
11
1 file changed, 8 insertions(+), 4 deletions(-)
6
12
7
Those limits are also reported in the BlockDeviceInfo struct and they
13
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
8
are integers there as well.
14
index XXXXXXX..XXXXXXX 100755
9
15
--- a/tests/qemu-iotests/267
10
Therefore there's no reason to store them internally as double and do
16
+++ b/tests/qemu-iotests/267
11
the conversion everytime we're setting or querying them, so this patch
17
@@ -XXX,XX +XXX,XX @@ size=128M
12
uses uint64_t for those types. Let's also use an unsigned type because
18
13
we don't allow negative values anyway.
19
run_test()
14
20
{
15
LeakyBucket.level and LeakyBucket.burst_level do however remain double
21
- _make_test_img $size
16
because their value changes depending on the fraction of time elapsed
22
+ if [ -n "$BACKING_FILE" ]; then
17
since the previous I/O operation.
23
+ _make_test_img -b "$BACKING_FILE" $size
18
24
+ else
19
Signed-off-by: Alberto Garcia <berto@igalia.com>
25
+ _make_test_img $size
20
Message-id: f29b840422767b5be2c41c2dfdbbbf6c5f8fedf8.1503580370.git.berto@igalia.com
26
+ fi
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
printf "savevm snap0\ninfo snapshots\nloadvm snap0\n" | run_qemu "$@" | _filter_date
22
---
23
include/qemu/throttle.h | 4 ++--
24
tests/test-throttle.c | 3 ++-
25
util/throttle.c | 7 +++----
26
3 files changed, 7 insertions(+), 7 deletions(-)
27
28
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/qemu/throttle.h
31
+++ b/include/qemu/throttle.h
32
@@ -XXX,XX +XXX,XX @@ typedef enum {
33
*/
34
35
typedef struct LeakyBucket {
36
- double avg; /* average goal in units per second */
37
- double max; /* leaky bucket max burst in units */
38
+ uint64_t avg; /* average goal in units per second */
39
+ uint64_t max; /* leaky bucket max burst in units */
40
double level; /* bucket level in units */
41
double burst_level; /* bucket level in units (for computing bursts) */
42
unsigned burst_length; /* max length of the burst period, in seconds */
43
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/tests/test-throttle.c
46
+++ b/tests/test-throttle.c
47
@@ -XXX,XX +XXX,XX @@ static void test_enabled(void)
48
for (i = 0; i < BUCKETS_COUNT; i++) {
49
throttle_config_init(&cfg);
50
set_cfg_value(false, i, 150);
51
+ g_assert(throttle_is_valid(&cfg, NULL));
52
g_assert(throttle_enabled(&cfg));
53
}
54
55
for (i = 0; i < BUCKETS_COUNT; i++) {
56
throttle_config_init(&cfg);
57
set_cfg_value(false, i, -150);
58
- g_assert(!throttle_enabled(&cfg));
59
+ g_assert(!throttle_is_valid(&cfg, NULL));
60
}
61
}
28
}
62
29
63
diff --git a/util/throttle.c b/util/throttle.c
30
@@ -XXX,XX +XXX,XX @@ echo
64
index XXXXXXX..XXXXXXX 100644
31
65
--- a/util/throttle.c
32
TEST_IMG="$TEST_IMG.base" _make_test_img $size
66
+++ b/util/throttle.c
33
67
@@ -XXX,XX +XXX,XX @@ int64_t throttle_compute_wait(LeakyBucket *bkt)
34
-IMGOPTS="backing_file=$TEST_IMG.base" \
68
/* If bkt->max is 0 we still want to allow short bursts of I/O
35
+BACKING_FILE="$TEST_IMG.base" \
69
* from the guest, otherwise every other request will be throttled
36
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
70
* and performance will suffer considerably. */
37
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
71
- bucket_size = bkt->avg / 10;
38
-blockdev driver=$IMGFMT,file=file,backing=backing-file,node-name=fmt
72
+ bucket_size = (double) bkt->avg / 10;
39
73
burst_bucket_size = 0;
40
-IMGOPTS="backing_file=$TEST_IMG.base" \
74
} else {
41
+BACKING_FILE="$TEST_IMG.base" \
75
/* If we have a burst limit then we have to wait until all I/O
42
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
76
* at burst rate has finished before throttling to bkt->avg */
43
-blockdev driver=$IMGFMT,file=backing-file,node-name=backing-fmt \
77
bucket_size = bkt->max * bkt->burst_length;
44
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
78
- burst_bucket_size = bkt->max / 10;
45
@@ -XXX,XX +XXX,XX @@ echo
79
+ burst_bucket_size = (double) bkt->max / 10;
46
echo "=== -blockdev with NBD server on the backing file ==="
80
}
47
echo
81
48
82
/* If the main bucket is full then we have to wait */
49
-IMGOPTS="backing_file=$TEST_IMG.base" _make_test_img $size
83
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
50
+_make_test_img -b "$TEST_IMG.base" $size
84
51
cat <<EOF |
85
for (i = 0; i < BUCKETS_COUNT; i++) {
52
nbd_server_start unix:$SOCK_DIR/nbd
86
LeakyBucket *bkt = &cfg->buckets[i];
53
nbd_server_add -w backing-fmt
87
- if (bkt->avg < 0 || bkt->max < 0 ||
88
- bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
89
+ if (bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
90
error_setg(errp, "bps/iops/max values must be within [0, %lld]",
91
THROTTLE_VALUE_MAX);
92
return false;
93
--
54
--
94
2.13.5
55
2.24.1
95
56
96
57
diff view generated by jsdifflib
New patch
1
Use _make_test_img whenever possible. This way, we will not ignore
2
user-specified image options.
1
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Message-id: 20191107163708.833192-15-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/094 | 2 +-
10
tests/qemu-iotests/111 | 3 +--
11
tests/qemu-iotests/123 | 2 +-
12
tests/qemu-iotests/153 | 2 +-
13
tests/qemu-iotests/200 | 4 ++--
14
5 files changed, 6 insertions(+), 7 deletions(-)
15
16
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/094
19
+++ b/tests/qemu-iotests/094
20
@@ -XXX,XX +XXX,XX @@ _supported_proto nbd
21
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
22
23
_make_test_img 64M
24
-$QEMU_IMG create -f $IMGFMT "$TEST_DIR/source.$IMGFMT" 64M | _filter_img_create
25
+TEST_IMG_FILE="$TEST_DIR/source.$IMGFMT" IMGPROTO=file _make_test_img 64M
26
27
_launch_qemu -drive if=none,id=src,file="$TEST_DIR/source.$IMGFMT",format=raw \
28
-nodefaults
29
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
30
index XXXXXXX..XXXXXXX 100755
31
--- a/tests/qemu-iotests/111
32
+++ b/tests/qemu-iotests/111
33
@@ -XXX,XX +XXX,XX @@ _supported_fmt qed qcow qcow2 vmdk
34
_supported_proto file
35
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
36
37
-$QEMU_IMG create -f $IMGFMT -b "$TEST_IMG.inexistent" "$TEST_IMG" 2>&1 \
38
- | _filter_testdir | _filter_imgfmt
39
+_make_test_img -b "$TEST_IMG.inexistent"
40
41
# success, all done
42
echo '*** done'
43
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
44
index XXXXXXX..XXXXXXX 100755
45
--- a/tests/qemu-iotests/123
46
+++ b/tests/qemu-iotests/123
47
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
48
SRC_IMG="$TEST_DIR/source.$IMGFMT"
49
50
_make_test_img 1M
51
-$QEMU_IMG create -f $IMGFMT "$SRC_IMG" 1M | _filter_img_create
52
+TEST_IMG_FILE=$SRC_IMG IMGPROTO=file _make_test_img 1M
53
54
$QEMU_IO -c 'write -P 42 0 1M' "$SRC_IMG" | _filter_qemu_io
55
56
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
57
index XXXXXXX..XXXXXXX 100755
58
--- a/tests/qemu-iotests/153
59
+++ b/tests/qemu-iotests/153
60
@@ -XXX,XX +XXX,XX @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do
61
62
echo
63
echo "== Creating test image =="
64
- $QEMU_IMG create -f $IMGFMT "${TEST_IMG}" -b ${TEST_IMG}.base | _filter_img_create
65
+ _make_test_img -b "${TEST_IMG}.base"
66
67
echo
68
echo "== Launching QEMU, opts: '$opts1' =="
69
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/200
72
+++ b/tests/qemu-iotests/200
73
@@ -XXX,XX +XXX,XX @@ _supported_proto file
74
BACKING_IMG="${TEST_DIR}/backing.img"
75
TEST_IMG="${TEST_DIR}/test.img"
76
77
-${QEMU_IMG} create -f $IMGFMT "${BACKING_IMG}" 512M | _filter_img_create
78
-${QEMU_IMG} create -f $IMGFMT -F $IMGFMT "${TEST_IMG}" -b "${BACKING_IMG}" 512M | _filter_img_create
79
+TEST_IMG="$BACKING_IMG" _make_test_img 512M
80
+_make_test_img -F $IMGFMT -b "$BACKING_IMG" 512M
81
82
${QEMU_IO} -c "write -P 0xa5 512 300M" "${BACKING_IMG}" | _filter_qemu_io
83
84
--
85
2.24.1
86
87
diff view generated by jsdifflib
New patch
1
Just rm will not delete external data files. Use _rm_test_img every
2
time we delete a test image.
1
3
4
(In the process, clean up the indentation of every _cleanup() this patch
5
touches.)
6
7
((Also, use quotes consistently. I am happy to see unquoted instances
8
like "rm -rf $TEST_DIR/..." go.))
9
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
12
Message-id: 20191107163708.833192-16-mreitz@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
tests/qemu-iotests/019 | 6 +++---
16
tests/qemu-iotests/020 | 6 +++---
17
tests/qemu-iotests/024 | 10 +++++-----
18
tests/qemu-iotests/028 | 2 +-
19
tests/qemu-iotests/029 | 2 +-
20
tests/qemu-iotests/043 | 4 +++-
21
tests/qemu-iotests/048 | 2 +-
22
tests/qemu-iotests/050 | 4 ++--
23
tests/qemu-iotests/053 | 4 ++--
24
tests/qemu-iotests/058 | 2 +-
25
tests/qemu-iotests/059 | 2 +-
26
tests/qemu-iotests/061 | 2 +-
27
tests/qemu-iotests/063 | 6 ++++--
28
tests/qemu-iotests/069 | 2 +-
29
tests/qemu-iotests/074 | 2 +-
30
tests/qemu-iotests/080 | 2 +-
31
tests/qemu-iotests/081 | 6 +++---
32
tests/qemu-iotests/085 | 9 ++++++---
33
tests/qemu-iotests/088 | 2 +-
34
tests/qemu-iotests/092 | 2 +-
35
tests/qemu-iotests/094 | 2 +-
36
tests/qemu-iotests/095 | 5 +++--
37
tests/qemu-iotests/099 | 7 ++++---
38
tests/qemu-iotests/109 | 4 ++--
39
tests/qemu-iotests/110 | 4 ++--
40
tests/qemu-iotests/122 | 6 ++++--
41
tests/qemu-iotests/123 | 2 +-
42
tests/qemu-iotests/141 | 4 +++-
43
tests/qemu-iotests/142 | 2 +-
44
tests/qemu-iotests/144 | 4 +++-
45
tests/qemu-iotests/153 | 10 +++-------
46
tests/qemu-iotests/156 | 8 ++++++--
47
tests/qemu-iotests/159 | 2 +-
48
tests/qemu-iotests/160 | 3 ++-
49
tests/qemu-iotests/161 | 4 ++--
50
tests/qemu-iotests/170 | 2 +-
51
tests/qemu-iotests/172 | 6 +++---
52
tests/qemu-iotests/173 | 3 ++-
53
tests/qemu-iotests/178 | 2 +-
54
tests/qemu-iotests/182 | 2 +-
55
tests/qemu-iotests/183 | 2 +-
56
tests/qemu-iotests/185 | 4 ++--
57
tests/qemu-iotests/187 | 6 +++---
58
tests/qemu-iotests/190 | 2 +-
59
tests/qemu-iotests/191 | 6 +++---
60
tests/qemu-iotests/195 | 2 +-
61
tests/qemu-iotests/197 | 2 +-
62
tests/qemu-iotests/200 | 3 ++-
63
tests/qemu-iotests/215 | 2 +-
64
tests/qemu-iotests/225 | 2 +-
65
tests/qemu-iotests/229 | 3 ++-
66
tests/qemu-iotests/232 | 4 +++-
67
tests/qemu-iotests/243 | 2 +-
68
tests/qemu-iotests/244 | 4 ++--
69
tests/qemu-iotests/247 | 4 +++-
70
tests/qemu-iotests/249 | 4 ++--
71
tests/qemu-iotests/252 | 2 +-
72
57 files changed, 118 insertions(+), 95 deletions(-)
73
74
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
75
index XXXXXXX..XXXXXXX 100755
76
--- a/tests/qemu-iotests/019
77
+++ b/tests/qemu-iotests/019
78
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
79
80
_cleanup()
81
{
82
-    _cleanup_test_img
83
- rm -f "$TEST_IMG.base"
84
- rm -f "$TEST_IMG.orig"
85
+ _cleanup_test_img
86
+ _rm_test_img "$TEST_IMG.base"
87
+ _rm_test_img "$TEST_IMG.orig"
88
}
89
trap "_cleanup; exit \$status" 0 1 2 3 15
90
91
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
92
index XXXXXXX..XXXXXXX 100755
93
--- a/tests/qemu-iotests/020
94
+++ b/tests/qemu-iotests/020
95
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
96
97
_cleanup()
98
{
99
-    _cleanup_test_img
100
- rm -f "$TEST_IMG.base"
101
- rm -f "$TEST_IMG.orig"
102
+ _cleanup_test_img
103
+ _rm_test_img "$TEST_IMG.base"
104
+ _rm_test_img "$TEST_IMG.orig"
105
}
106
trap "_cleanup; exit \$status" 0 1 2 3 15
107
108
diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024
109
index XXXXXXX..XXXXXXX 100755
110
--- a/tests/qemu-iotests/024
111
+++ b/tests/qemu-iotests/024
112
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
113
_cleanup()
114
{
115
_cleanup_test_img
116
- rm -f "$TEST_DIR/t.$IMGFMT.base_old"
117
- rm -f "$TEST_DIR/t.$IMGFMT.base_new"
118
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_old"
119
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_new"
120
121
- rm -f "$TEST_DIR/subdir/t.$IMGFMT"
122
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_old"
123
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_new"
124
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT"
125
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_old"
126
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_new"
127
rmdir "$TEST_DIR/subdir" 2> /dev/null
128
}
129
trap "_cleanup; exit \$status" 0 1 2 3 15
130
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
131
index XXXXXXX..XXXXXXX 100755
132
--- a/tests/qemu-iotests/028
133
+++ b/tests/qemu-iotests/028
134
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
135
_cleanup()
136
{
137
_cleanup_qemu
138
- rm -f "${TEST_IMG}.copy"
139
+ _rm_test_img "${TEST_IMG}.copy"
140
_cleanup_test_img
141
}
142
trap "_cleanup; exit \$status" 0 1 2 3 15
143
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
144
index XXXXXXX..XXXXXXX 100755
145
--- a/tests/qemu-iotests/029
146
+++ b/tests/qemu-iotests/029
147
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
148
149
_cleanup()
150
{
151
- rm -f $TEST_IMG.snap
152
+ _rm_test_img "$TEST_IMG.snap"
153
_cleanup_test_img
154
}
155
trap "_cleanup; exit \$status" 0 1 2 3 15
156
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
157
index XXXXXXX..XXXXXXX 100755
158
--- a/tests/qemu-iotests/043
159
+++ b/tests/qemu-iotests/043
160
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
161
_cleanup()
162
{
163
_cleanup_test_img
164
- rm -f "$TEST_IMG".[123].base
165
+ for img in "$TEST_IMG".[123].base; do
166
+ _rm_test_img "$img"
167
+ done
168
}
169
trap "_cleanup; exit \$status" 0 1 2 3 15
170
171
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
172
index XXXXXXX..XXXXXXX 100755
173
--- a/tests/qemu-iotests/048
174
+++ b/tests/qemu-iotests/048
175
@@ -XXX,XX +XXX,XX @@ _cleanup()
176
{
177
echo "Cleanup"
178
_cleanup_test_img
179
- rm "${TEST_IMG_FILE2}"
180
+ _rm_test_img "${TEST_IMG_FILE2}"
181
}
182
trap "_cleanup; exit \$status" 0 1 2 3 15
183
184
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
185
index XXXXXXX..XXXXXXX 100755
186
--- a/tests/qemu-iotests/050
187
+++ b/tests/qemu-iotests/050
188
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
189
_cleanup()
190
{
191
_cleanup_test_img
192
- rm -f "$TEST_IMG.old"
193
- rm -f "$TEST_IMG.new"
194
+ _rm_test_img "$TEST_IMG.old"
195
+ _rm_test_img "$TEST_IMG.new"
196
}
197
trap "_cleanup; exit \$status" 0 1 2 3 15
198
199
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
200
index XXXXXXX..XXXXXXX 100755
201
--- a/tests/qemu-iotests/053
202
+++ b/tests/qemu-iotests/053
203
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
204
205
_cleanup()
206
{
207
-    rm -f "$TEST_IMG.orig"
208
-    _cleanup_test_img
209
+ _rm_test_img "$TEST_IMG.orig"
210
+ _cleanup_test_img
211
}
212
trap "_cleanup; exit \$status" 0 1 2 3 15
213
214
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
215
index XXXXXXX..XXXXXXX 100755
216
--- a/tests/qemu-iotests/058
217
+++ b/tests/qemu-iotests/058
218
@@ -XXX,XX +XXX,XX @@ _cleanup()
219
{
220
nbd_server_stop
221
_cleanup_test_img
222
- rm -f "$converted_image"
223
+ _rm_test_img "$converted_image"
224
}
225
trap "_cleanup; exit \$status" 0 1 2 3 15
226
227
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
228
index XXXXXXX..XXXXXXX 100755
229
--- a/tests/qemu-iotests/059
230
+++ b/tests/qemu-iotests/059
231
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
232
_cleanup()
233
{
234
_cleanup_test_img
235
- rm -f "$TEST_IMG.qcow2"
236
+ IMGFMT=qcow2 _rm_test_img "$TEST_IMG.qcow2"
237
}
238
trap "_cleanup; exit \$status" 0 1 2 3 15
239
240
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
241
index XXXXXXX..XXXXXXX 100755
242
--- a/tests/qemu-iotests/061
243
+++ b/tests/qemu-iotests/061
244
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
245
_cleanup()
246
{
247
_cleanup_test_img
248
- rm -f $TEST_IMG.data
249
+ _rm_test_img "$TEST_IMG.data"
250
}
251
trap "_cleanup; exit \$status" 0 1 2 3 15
252
253
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
254
index XXXXXXX..XXXXXXX 100755
255
--- a/tests/qemu-iotests/063
256
+++ b/tests/qemu-iotests/063
257
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
258
259
_cleanup()
260
{
261
-    _cleanup_test_img
262
-    rm -f "$TEST_IMG.orig" "$TEST_IMG.raw1" "$TEST_IMG.raw2"
263
+ _cleanup_test_img
264
+ for img in "$TEST_IMG".{orig,raw1,raw2,target}; do
265
+ _rm_test_img "$img"
266
+ done
267
}
268
trap "_cleanup; exit \$status" 0 1 2 3 15
269
270
diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069
271
index XXXXXXX..XXXXXXX 100755
272
--- a/tests/qemu-iotests/069
273
+++ b/tests/qemu-iotests/069
274
@@ -XXX,XX +XXX,XX @@ echo "=== Creating an image with a backing file and deleting that file ==="
275
echo
276
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
277
_make_test_img -b "$TEST_IMG.base" $IMG_SIZE
278
-rm -f "$TEST_IMG.base"
279
+_rm_test_img "$TEST_IMG.base"
280
# Just open the image and close it right again (this should print an error message)
281
$QEMU_IO -c quit "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
282
283
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
284
index XXXXXXX..XXXXXXX 100755
285
--- a/tests/qemu-iotests/074
286
+++ b/tests/qemu-iotests/074
287
@@ -XXX,XX +XXX,XX @@ _cleanup()
288
{
289
echo "Cleanup"
290
_cleanup_test_img
291
- rm "${TEST_IMG2}"
292
+ _rm_test_img "${TEST_IMG2}"
293
rm -f "$TEST_DIR/blkdebug.conf"
294
}
295
trap "_cleanup; exit \$status" 0 1 2 3 15
296
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
297
index XXXXXXX..XXXXXXX 100755
298
--- a/tests/qemu-iotests/080
299
+++ b/tests/qemu-iotests/080
300
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
301
302
_cleanup()
303
{
304
- rm -f $TEST_IMG.snap
305
+ _rm_test_img "$TEST_IMG.snap"
306
_cleanup_test_img
307
}
308
trap "_cleanup; exit \$status" 0 1 2 3 15
309
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
310
index XXXXXXX..XXXXXXX 100755
311
--- a/tests/qemu-iotests/081
312
+++ b/tests/qemu-iotests/081
313
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
314
315
_cleanup()
316
{
317
- rm -rf $TEST_DIR/1.raw
318
- rm -rf $TEST_DIR/2.raw
319
- rm -rf $TEST_DIR/3.raw
320
+ _rm_test_img "$TEST_DIR/1.raw"
321
+ _rm_test_img "$TEST_DIR/2.raw"
322
+ _rm_test_img "$TEST_DIR/3.raw"
323
}
324
trap "_cleanup; exit \$status" 0 1 2 3 15
325
326
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
327
index XXXXXXX..XXXXXXX 100755
328
--- a/tests/qemu-iotests/085
329
+++ b/tests/qemu-iotests/085
330
@@ -XXX,XX +XXX,XX @@ _cleanup()
331
_cleanup_qemu
332
for i in $(seq 1 ${SNAPSHOTS})
333
do
334
- rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
335
- rm -f "${TEST_DIR}/${i}-${snapshot_virt1}"
336
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt0}"
337
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt1}"
338
+ done
339
+ for img in "${TEST_IMG}".{1,2,base}
340
+ do
341
+ _rm_test_img "$img"
342
done
343
- rm -f "${TEST_IMG}" "${TEST_IMG}.1" "${TEST_IMG}.2" "${TEST_IMG}.base"
344
345
}
346
trap "_cleanup; exit \$status" 0 1 2 3 15
347
diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088
348
index XXXXXXX..XXXXXXX 100755
349
--- a/tests/qemu-iotests/088
350
+++ b/tests/qemu-iotests/088
351
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
352
353
_cleanup()
354
{
355
- rm -f $TEST_IMG.snap
356
+ _rm_test_img "$TEST_IMG.snap"
357
_cleanup_test_img
358
}
359
trap "_cleanup; exit \$status" 0 1 2 3 15
360
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
361
index XXXXXXX..XXXXXXX 100755
362
--- a/tests/qemu-iotests/092
363
+++ b/tests/qemu-iotests/092
364
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
365
366
_cleanup()
367
{
368
- rm -f $TEST_IMG.snap
369
+ _rm_test_img "$TEST_IMG.snap"
370
_cleanup_test_img
371
}
372
trap "_cleanup; exit \$status" 0 1 2 3 15
373
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
374
index XXXXXXX..XXXXXXX 100755
375
--- a/tests/qemu-iotests/094
376
+++ b/tests/qemu-iotests/094
377
@@ -XXX,XX +XXX,XX @@ _cleanup()
378
{
379
_cleanup_qemu
380
_cleanup_test_img
381
- rm -f "$TEST_DIR/source.$IMGFMT"
382
+ _rm_test_img "$TEST_DIR/source.$IMGFMT"
383
}
384
385
trap "_cleanup; exit \$status" 0 1 2 3 15
386
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
387
index XXXXXXX..XXXXXXX 100755
388
--- a/tests/qemu-iotests/095
389
+++ b/tests/qemu-iotests/095
390
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
391
_cleanup()
392
{
393
_cleanup_qemu
394
- rm -f "${TEST_IMG}.base" "${TEST_IMG}.snp1"
395
-    _cleanup_test_img
396
+ _rm_test_img "${TEST_IMG}.base"
397
+ _rm_test_img "${TEST_IMG}.snp1"
398
+ _cleanup_test_img
399
}
400
trap "_cleanup; exit \$status" 0 1 2 3 15
401
402
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
403
index XXXXXXX..XXXXXXX 100755
404
--- a/tests/qemu-iotests/099
405
+++ b/tests/qemu-iotests/099
406
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
407
408
_cleanup()
409
{
410
-    _cleanup_test_img
411
+ _cleanup_test_img
412
+ _rm_test_img "$TEST_IMG.compare"
413
+ rm -f "$TEST_DIR/blkdebug.conf"
414
+
415
}
416
trap "_cleanup; exit \$status" 0 1 2 3 15
417
418
@@ -XXX,XX +XXX,XX @@ echo
419
test_qemu "file.driver=blkdebug,file.image.filename=$TEST_IMG"
420
421
422
-rm -f "$TEST_IMG.compare" "$TEST_DIR/blkdebug.conf"
423
-
424
# success, all done
425
echo "*** done"
426
rm -f $seq.full
427
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
428
index XXXXXXX..XXXXXXX 100755
429
--- a/tests/qemu-iotests/109
430
+++ b/tests/qemu-iotests/109
431
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
432
_cleanup()
433
{
434
_cleanup_qemu
435
- rm -f $TEST_IMG.src
436
-    _cleanup_test_img
437
+ _rm_test_img "$TEST_IMG.src"
438
+ _cleanup_test_img
439
}
440
trap "_cleanup; exit \$status" 0 1 2 3 15
441
442
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
443
index XXXXXXX..XXXXXXX 100755
444
--- a/tests/qemu-iotests/110
445
+++ b/tests/qemu-iotests/110
446
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
447
448
_cleanup()
449
{
450
-    _cleanup_test_img
451
- rm -f "$TEST_IMG.copy"
452
+ _cleanup_test_img
453
+ _rm_test_img "$TEST_IMG.copy"
454
}
455
trap "_cleanup; exit \$status" 0 1 2 3 15
456
457
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
458
index XXXXXXX..XXXXXXX 100755
459
--- a/tests/qemu-iotests/122
460
+++ b/tests/qemu-iotests/122
461
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
462
463
_cleanup()
464
{
465
- rm -f "$TEST_IMG".[123]
466
-    _cleanup_test_img
467
+ for img in "$TEST_IMG".[123]; do
468
+ _rm_test_img "$img"
469
+ done
470
+ _cleanup_test_img
471
}
472
trap "_cleanup; exit \$status" 0 1 2 3 15
473
474
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
475
index XXXXXXX..XXXXXXX 100755
476
--- a/tests/qemu-iotests/123
477
+++ b/tests/qemu-iotests/123
478
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
479
_cleanup()
480
{
481
_cleanup_test_img
482
- rm -f "$SRC_IMG"
483
+ _rm_test_img "$SRC_IMG"
484
}
485
trap "_cleanup; exit \$status" 0 1 2 3 15
486
487
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
488
index XXXXXXX..XXXXXXX 100755
489
--- a/tests/qemu-iotests/141
490
+++ b/tests/qemu-iotests/141
491
@@ -XXX,XX +XXX,XX @@ _cleanup()
492
{
493
_cleanup_qemu
494
_cleanup_test_img
495
- rm -f "$TEST_DIR"/{b,m,o}.$IMGFMT
496
+ for img in "$TEST_DIR"/{b,m,o}.$IMGFMT; do
497
+ _rm_test_img "$img"
498
+ done
499
}
500
trap "_cleanup; exit \$status" 0 1 2 3 15
501
502
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
503
index XXXXXXX..XXXXXXX 100755
504
--- a/tests/qemu-iotests/142
505
+++ b/tests/qemu-iotests/142
506
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
507
_cleanup()
508
{
509
_cleanup_test_img
510
- rm -f $TEST_IMG.snap
511
+ _rm_test_img "$TEST_IMG.snap"
512
}
513
trap "_cleanup; exit \$status" 0 1 2 3 15
514
515
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
516
index XXXXXXX..XXXXXXX 100755
517
--- a/tests/qemu-iotests/144
518
+++ b/tests/qemu-iotests/144
519
@@ -XXX,XX +XXX,XX @@ TMP_SNAP2=${TEST_DIR}/tmp2.qcow2
520
_cleanup()
521
{
522
_cleanup_qemu
523
- rm -f "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"
524
+ for img in "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"; do
525
+ _rm_test_img "$img"
526
+ done
527
}
528
529
trap "_cleanup; exit \$status" 0 1 2 3 15
530
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
531
index XXXXXXX..XXXXXXX 100755
532
--- a/tests/qemu-iotests/153
533
+++ b/tests/qemu-iotests/153
534
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
535
_cleanup()
536
{
537
_cleanup_test_img
538
- rm -f "${TEST_IMG}.base"
539
- rm -f "${TEST_IMG}.overlay"
540
- rm -f "${TEST_IMG}.convert"
541
- rm -f "${TEST_IMG}.a"
542
- rm -f "${TEST_IMG}.b"
543
- rm -f "${TEST_IMG}.c"
544
- rm -f "${TEST_IMG}.lnk"
545
+ for img in "${TEST_IMG}".{base,overlay,convert,a,b,c,lnk}; do
546
+ _rm_test_img "$img"
547
+ done
548
}
549
trap "_cleanup; exit \$status" 0 1 2 3 15
550
551
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
552
index XXXXXXX..XXXXXXX 100755
553
--- a/tests/qemu-iotests/156
554
+++ b/tests/qemu-iotests/156
555
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
556
_cleanup()
557
{
558
_cleanup_qemu
559
- rm -f "$TEST_IMG"{,.target}{,.backing,.overlay}
560
+ for img in "$TEST_IMG"{,.target}{,.backing,.overlay}; do
561
+ _rm_test_img "$img"
562
+ done
563
}
564
trap "_cleanup; exit \$status" 0 1 2 3 15
565
566
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
567
'"status": "null"'
568
569
# Remove the source images
570
-rm -f "$TEST_IMG{,.backing,.overlay}"
571
+for img in "$TEST_IMG{,.backing,.overlay}"; do
572
+ _rm_test_img "$img"
573
+done
574
575
echo
576
577
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
578
index XXXXXXX..XXXXXXX 100755
579
--- a/tests/qemu-iotests/159
580
+++ b/tests/qemu-iotests/159
581
@@ -XXX,XX +XXX,XX @@ status=1
582
_cleanup()
583
{
584
_cleanup_test_img
585
- rm -f "$TEST_IMG.out"
586
+ _rm_test_img "$TEST_IMG.out"
587
}
588
trap "_cleanup; exit \$status" 0 1 2 3 15
589
590
diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160
591
index XXXXXXX..XXXXXXX 100755
592
--- a/tests/qemu-iotests/160
593
+++ b/tests/qemu-iotests/160
594
@@ -XXX,XX +XXX,XX @@ status=1
595
_cleanup()
596
{
597
_cleanup_test_img
598
- rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd"
599
+ _rm_test_img "$TEST_IMG.out"
600
+ _rm_test_img "$TEST_IMG.out.dd"
601
}
602
trap "_cleanup; exit \$status" 0 1 2 3 15
603
604
diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
605
index XXXXXXX..XXXXXXX 100755
606
--- a/tests/qemu-iotests/161
607
+++ b/tests/qemu-iotests/161
608
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
609
_cleanup()
610
{
611
_cleanup_test_img
612
- rm -f "$TEST_IMG.base"
613
- rm -f "$TEST_IMG.int"
614
+ _rm_test_img "$TEST_IMG.base"
615
+ _rm_test_img "$TEST_IMG.int"
616
}
617
trap "_cleanup; exit \$status" 0 1 2 3 15
618
619
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
620
index XXXXXXX..XXXXXXX 100755
621
--- a/tests/qemu-iotests/170
622
+++ b/tests/qemu-iotests/170
623
@@ -XXX,XX +XXX,XX @@ status=1
624
_cleanup()
625
{
626
_cleanup_test_img
627
- rm -f "$TEST_IMG.out"
628
+ _rm_test_img "$TEST_IMG.out"
629
}
630
trap "_cleanup; exit \$status" 0 1 2 3 15
631
632
diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172
633
index XXXXXXX..XXXXXXX 100755
634
--- a/tests/qemu-iotests/172
635
+++ b/tests/qemu-iotests/172
636
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
637
638
_cleanup()
639
{
640
-    _cleanup_test_img
641
- rm -f "$TEST_IMG.2"
642
- rm -f "$TEST_IMG.3"
643
+ _cleanup_test_img
644
+ _rm_test_img "$TEST_IMG.2"
645
+ _rm_test_img "$TEST_IMG.3"
646
}
647
trap "_cleanup; exit \$status" 0 1 2 3 15
648
649
diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173
650
index XXXXXXX..XXXXXXX 100755
651
--- a/tests/qemu-iotests/173
652
+++ b/tests/qemu-iotests/173
653
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
654
_cleanup()
655
{
656
_cleanup_qemu
657
- rm -f "${QEMU_TEST_DIR}/image.base" "${QEMU_TEST_DIR}/image.snp1"
658
+ _rm_test_img "${TEST_DIR}/image.base"
659
+ _rm_test_img "${TEST_DIR}/image.snp1"
660
_cleanup_test_img
661
}
662
trap "_cleanup; exit \$status" 0 1 2 3 15
663
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
664
index XXXXXXX..XXXXXXX 100755
665
--- a/tests/qemu-iotests/178
666
+++ b/tests/qemu-iotests/178
667
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
668
_cleanup()
669
{
670
_cleanup_test_img
671
- rm -f "$TEST_IMG.converted"
672
+ _rm_test_img "$TEST_IMG.converted"
673
}
674
trap "_cleanup; exit \$status" 0 1 2 3 15
675
676
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
677
index XXXXXXX..XXXXXXX 100755
678
--- a/tests/qemu-iotests/182
679
+++ b/tests/qemu-iotests/182
680
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
681
_cleanup()
682
{
683
_cleanup_test_img
684
- rm -f "$TEST_IMG.overlay"
685
+ _rm_test_img "$TEST_IMG.overlay"
686
rm -f "$SOCK_DIR/nbd.socket"
687
}
688
trap "_cleanup; exit \$status" 0 1 2 3 15
689
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
690
index XXXXXXX..XXXXXXX 100755
691
--- a/tests/qemu-iotests/183
692
+++ b/tests/qemu-iotests/183
693
@@ -XXX,XX +XXX,XX @@ MIG_SOCKET="${SOCK_DIR}/migrate"
694
_cleanup()
695
{
696
rm -f "${MIG_SOCKET}"
697
- rm -f "${TEST_IMG}.dest"
698
+ _rm_test_img "${TEST_IMG}.dest"
699
_cleanup_test_img
700
_cleanup_qemu
701
}
702
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
703
index XXXXXXX..XXXXXXX 100755
704
--- a/tests/qemu-iotests/185
705
+++ b/tests/qemu-iotests/185
706
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
707
708
_cleanup()
709
{
710
- rm -f "${TEST_IMG}.mid"
711
- rm -f "${TEST_IMG}.copy"
712
+ _rm_test_img "${TEST_IMG}.mid"
713
+ _rm_test_img "${TEST_IMG}.copy"
714
_cleanup_test_img
715
_cleanup_qemu
716
}
717
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
718
index XXXXXXX..XXXXXXX 100755
719
--- a/tests/qemu-iotests/187
720
+++ b/tests/qemu-iotests/187
721
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
722
723
_cleanup()
724
{
725
-    _cleanup_test_img
726
- rm -f "$TEST_IMG.2"
727
- rm -f "$TEST_IMG.3"
728
+ _cleanup_test_img
729
+ _rm_test_img "$TEST_IMG.2"
730
+ _rm_test_img "$TEST_IMG.3"
731
}
732
trap "_cleanup; exit \$status" 0 1 2 3 15
733
734
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
735
index XXXXXXX..XXXXXXX 100755
736
--- a/tests/qemu-iotests/190
737
+++ b/tests/qemu-iotests/190
738
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
739
_cleanup()
740
{
741
_cleanup_test_img
742
- rm -f "$TEST_IMG.converted"
743
+ _rm_test_img "$TEST_IMG.converted"
744
}
745
trap "_cleanup; exit \$status" 0 1 2 3 15
746
747
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
748
index XXXXXXX..XXXXXXX 100755
749
--- a/tests/qemu-iotests/191
750
+++ b/tests/qemu-iotests/191
751
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
752
753
_cleanup()
754
{
755
- rm -f "${TEST_IMG}.mid"
756
- rm -f "${TEST_IMG}.ovl2"
757
- rm -f "${TEST_IMG}.ovl3"
758
+ _rm_test_img "${TEST_IMG}.mid"
759
+ _rm_test_img "${TEST_IMG}.ovl2"
760
+ _rm_test_img "${TEST_IMG}.ovl3"
761
_cleanup_test_img
762
_cleanup_qemu
763
}
764
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
765
index XXXXXXX..XXXXXXX 100755
766
--- a/tests/qemu-iotests/195
767
+++ b/tests/qemu-iotests/195
768
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
769
_cleanup()
770
{
771
_cleanup_test_img
772
- rm -f "$TEST_IMG.mid"
773
+ _rm_test_img "$TEST_IMG.mid"
774
}
775
trap "_cleanup; exit \$status" 0 1 2 3 15
776
777
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
778
index XXXXXXX..XXXXXXX 100755
779
--- a/tests/qemu-iotests/197
780
+++ b/tests/qemu-iotests/197
781
@@ -XXX,XX +XXX,XX @@ esac
782
_cleanup()
783
{
784
_cleanup_test_img
785
- rm -f "$TEST_WRAP"
786
+ _rm_test_img "$TEST_WRAP"
787
rm -f "$BLKDBG_CONF"
788
}
789
trap "_cleanup; exit \$status" 0 1 2 3 15
790
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
791
index XXXXXXX..XXXXXXX 100755
792
--- a/tests/qemu-iotests/200
793
+++ b/tests/qemu-iotests/200
794
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
795
_cleanup()
796
{
797
_cleanup_qemu
798
- rm -f "${TEST_IMG}" "${BACKING_IMG}"
799
+ _rm_test_img "${TEST_IMG}"
800
+ _rm_test_img "${BACKING_IMG}"
801
}
802
trap "_cleanup; exit \$status" 0 1 2 3 15
803
804
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
805
index XXXXXXX..XXXXXXX 100755
806
--- a/tests/qemu-iotests/215
807
+++ b/tests/qemu-iotests/215
808
@@ -XXX,XX +XXX,XX @@ esac
809
_cleanup()
810
{
811
_cleanup_test_img
812
- rm -f "$TEST_WRAP"
813
+ _rm_test_img "$TEST_WRAP"
814
rm -f "$BLKDBG_CONF"
815
}
816
trap "_cleanup; exit \$status" 0 1 2 3 15
817
diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225
818
index XXXXXXX..XXXXXXX 100755
819
--- a/tests/qemu-iotests/225
820
+++ b/tests/qemu-iotests/225
821
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
822
_cleanup()
823
{
824
_cleanup_test_img
825
- rm -f "$TEST_IMG.not_base"
826
+ _rm_test_img "$TEST_IMG.not_base"
827
}
828
trap "_cleanup; exit \$status" 0 1 2 3 15
829
830
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
831
index XXXXXXX..XXXXXXX 100755
832
--- a/tests/qemu-iotests/229
833
+++ b/tests/qemu-iotests/229
834
@@ -XXX,XX +XXX,XX @@ _cleanup()
835
{
836
_cleanup_qemu
837
_cleanup_test_img
838
- rm -f "$TEST_IMG" "$DEST_IMG"
839
+ _rm_test_img "$TEST_IMG"
840
+ _rm_test_img "$DEST_IMG"
841
}
842
trap "_cleanup; exit \$status" 0 1 2 3 15
843
844
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
845
index XXXXXXX..XXXXXXX 100755
846
--- a/tests/qemu-iotests/232
847
+++ b/tests/qemu-iotests/232
848
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
849
_cleanup()
850
{
851
_cleanup_test_img
852
- rm -f $TEST_IMG.[01234]
853
+ for img in "$TEST_IMG".[01234]; do
854
+ _rm_test_img "$img"
855
+ done
856
}
857
trap "_cleanup; exit \$status" 0 1 2 3 15
858
859
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
860
index XXXXXXX..XXXXXXX 100755
861
--- a/tests/qemu-iotests/243
862
+++ b/tests/qemu-iotests/243
863
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
864
_cleanup()
865
{
866
_cleanup_test_img
867
- rm -f $TEST_IMG.data
868
+ _rm_test_img "$TEST_IMG.data"
869
}
870
trap "_cleanup; exit \$status" 0 1 2 3 15
871
872
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
873
index XXXXXXX..XXXXXXX 100755
874
--- a/tests/qemu-iotests/244
875
+++ b/tests/qemu-iotests/244
876
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
877
_cleanup()
878
{
879
_cleanup_test_img
880
- rm -f $TEST_IMG.data
881
- rm -f $TEST_IMG.src
882
+ _rm_test_img "$TEST_IMG.data"
883
+ _rm_test_img "$TEST_IMG.src"
884
}
885
trap "_cleanup; exit \$status" 0 1 2 3 15
886
887
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
888
index XXXXXXX..XXXXXXX 100755
889
--- a/tests/qemu-iotests/247
890
+++ b/tests/qemu-iotests/247
891
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
892
_cleanup()
893
{
894
_cleanup_test_img
895
- rm -f $TEST_IMG.[01234]
896
+ for img in "$TEST_IMG".[01234]; do
897
+ _rm_test_img "$img"
898
+ done
899
}
900
trap "_cleanup; exit \$status" 0 1 2 3 15
901
902
diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249
903
index XXXXXXX..XXXXXXX 100755
904
--- a/tests/qemu-iotests/249
905
+++ b/tests/qemu-iotests/249
906
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
907
_cleanup()
908
{
909
_cleanup_test_img
910
- rm -f "$TEST_IMG.base"
911
- rm -f "$TEST_IMG.int"
912
+ _rm_test_img "$TEST_IMG.base"
913
+ _rm_test_img "$TEST_IMG.int"
914
}
915
trap "_cleanup; exit \$status" 0 1 2 3 15
916
917
diff --git a/tests/qemu-iotests/252 b/tests/qemu-iotests/252
918
index XXXXXXX..XXXXXXX 100755
919
--- a/tests/qemu-iotests/252
920
+++ b/tests/qemu-iotests/252
921
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
922
_cleanup()
923
{
924
_cleanup_test_img
925
- rm -f "$TEST_IMG.base_new"
926
+ _rm_test_img "$TEST_IMG.base_new"
927
}
928
trap "_cleanup; exit \$status" 0 1 2 3 15
929
930
--
931
2.24.1
932
933
diff view generated by jsdifflib
New patch
1
This will not work with external data files, so try to get tests working
2
without it as far as possible.
1
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Message-id: 20191107163708.833192-17-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/063 | 12 ++++--------
10
tests/qemu-iotests/063.out | 3 ++-
11
tests/qemu-iotests/085 | 9 +++------
12
tests/qemu-iotests/085.out | 8 ++++----
13
4 files changed, 13 insertions(+), 19 deletions(-)
14
15
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/063
18
+++ b/tests/qemu-iotests/063
19
@@ -XXX,XX +XXX,XX @@ _unsupported_imgopts "subformat=monolithicFlat" \
20
_make_test_img 4M
21
22
echo "== Testing conversion with -n fails with no target file =="
23
-# check .orig file does not exist
24
-rm -f "$TEST_IMG.orig"
25
if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" >/dev/null 2>&1; then
26
exit 1
27
fi
28
29
echo "== Testing conversion with -n succeeds with a target file =="
30
-rm -f "$TEST_IMG.orig"
31
-cp "$TEST_IMG" "$TEST_IMG.orig"
32
+_rm_test_img "$TEST_IMG.orig"
33
+TEST_IMG="$TEST_IMG.orig" _make_test_img 4M
34
if ! $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" ; then
35
exit 1
36
fi
37
@@ -XXX,XX +XXX,XX @@ fi
38
_check_test_img
39
40
echo "== Testing conversion to a smaller file fails =="
41
-rm -f "$TEST_IMG.orig"
42
-mv "$TEST_IMG" "$TEST_IMG.orig"
43
-_make_test_img 2M
44
-if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev/null 2>&1; then
45
+TEST_IMG="$TEST_IMG.target" _make_test_img 2M
46
+if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.target" >/dev/null 2>&1; then
47
exit 1
48
fi
49
50
diff --git a/tests/qemu-iotests/063.out b/tests/qemu-iotests/063.out
51
index XXXXXXX..XXXXXXX 100644
52
--- a/tests/qemu-iotests/063.out
53
+++ b/tests/qemu-iotests/063.out
54
@@ -XXX,XX +XXX,XX @@ QA output created by 063
55
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
56
== Testing conversion with -n fails with no target file ==
57
== Testing conversion with -n succeeds with a target file ==
58
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=4194304
59
== Testing conversion to raw is the same after conversion with -n ==
60
== Testing conversion back to original format ==
61
No errors were found on the image.
62
== Testing conversion to a smaller file fails ==
63
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
64
+Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=2097152
65
== Regression testing for copy offloading bug ==
66
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
67
Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=1048576
68
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
69
index XXXXXXX..XXXXXXX 100755
70
--- a/tests/qemu-iotests/085
71
+++ b/tests/qemu-iotests/085
72
@@ -XXX,XX +XXX,XX @@ add_snapshot_image()
73
{
74
base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}"
75
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
76
- _make_test_img -u -b "${base_image}" "$size"
77
- mv "${TEST_IMG}" "${snapshot_file}"
78
+ TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" "$size"
79
do_blockdev_add "$1" "'backing': null, " "${snapshot_file}"
80
}
81
82
@@ -XXX,XX +XXX,XX @@ blockdev_snapshot()
83
84
size=128M
85
86
-_make_test_img $size
87
-mv "${TEST_IMG}" "${TEST_IMG}.1"
88
-_make_test_img $size
89
-mv "${TEST_IMG}" "${TEST_IMG}.2"
90
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
91
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
92
93
echo
94
echo === Running QEMU ===
95
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
96
index XXXXXXX..XXXXXXX 100644
97
--- a/tests/qemu-iotests/085.out
98
+++ b/tests/qemu-iotests/085.out
99
@@ -XXX,XX +XXX,XX @@
100
QA output created by 085
101
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
102
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
103
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
104
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
105
106
=== Running QEMU ===
107
108
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_fil
109
110
=== Create a couple of snapshots using blockdev-snapshot ===
111
112
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
113
+Formatting 'TEST_DIR/11-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
114
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_11', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/11-snapshot-v0.IMGFMT', 'node-name': 'file_11' } } }
115
{"return": {}}
116
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } }
117
{"return": {}}
118
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
119
+Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
120
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_12', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/12-snapshot-v0.IMGFMT', 'node-name': 'file_12' } } }
121
{"return": {}}
122
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_12' } }
123
--
124
2.24.1
125
126
diff view generated by jsdifflib
New patch
1
The image end offset as reported by qemu-img check is different when
2
using an external data file; we do not care about its value here, so we
3
can just filter it. Incidentally, common.rc already has _check_test_img
4
for us which does exactly that.
1
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Message-id: 20191107163708.833192-18-mreitz@redhat.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/091 | 2 +-
12
tests/qemu-iotests/091.out | 2 --
13
2 files changed, 1 insertion(+), 3 deletions(-)
14
15
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/091
18
+++ b/tests/qemu-iotests/091
19
@@ -XXX,XX +XXX,XX @@ echo "Check image pattern"
20
${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
21
22
echo "Running 'qemu-img check -r all \$TEST_IMG'"
23
-"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu
24
+_check_test_img -r all
25
26
echo "*** done"
27
rm -f $seq.full
28
diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out
29
index XXXXXXX..XXXXXXX 100644
30
--- a/tests/qemu-iotests/091.out
31
+++ b/tests/qemu-iotests/091.out
32
@@ -XXX,XX +XXX,XX @@ read 4194304/4194304 bytes at offset 0
33
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
34
Running 'qemu-img check -r all $TEST_IMG'
35
No errors were found on the image.
36
-80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters
37
-Image end offset: 5570560
38
*** done
39
--
40
2.24.1
41
42
diff view generated by jsdifflib
1
From: Fred Rolland <rollandf@gmail.com>
1
The only difference is that the json:{} filename of the image looks
2
different. We actually do not care about that filename in this test, we
3
are only interested in (1) that there is a json:{} filename, and (2)
4
whether the backing filename can be constructed.
2
5
3
Update doc with the usage of UUID for initiator name.
6
So just filter out the json:{} data, thus making this test pass both
7
with and without data_file.
4
8
5
Related-To: https://bugzilla.redhat.com/1006468
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Fred Rolland <frolland@redhat.com>
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
7
Message-id: 20170823084830.30500-1-frolland@redhat.com
11
Message-id: 20191107163708.833192-19-mreitz@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
13
---
10
qemu-doc.texi | 5 +++--
14
tests/qemu-iotests/110 | 7 +++++--
11
1 file changed, 3 insertions(+), 2 deletions(-)
15
tests/qemu-iotests/110.out | 4 ++--
16
2 files changed, 7 insertions(+), 4 deletions(-)
12
17
13
diff --git a/qemu-doc.texi b/qemu-doc.texi
18
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/110
21
+++ b/tests/qemu-iotests/110
22
@@ -XXX,XX +XXX,XX @@ echo
23
# Across blkdebug without a config file, you cannot reconstruct filenames, so
24
# qemu is incapable of knowing the directory of the top image from the filename
25
# alone. However, using bdrv_dirname(), it should still work.
26
+# (Filter out the json:{} filename so this test works with external data files)
27
TEST_IMG="json:{
28
'driver': '$IMGFMT',
29
'file': {
30
@@ -XXX,XX +XXX,XX @@ TEST_IMG="json:{
31
}
32
]
33
}
34
-}" _img_info | _filter_img_info | grep -v 'backing file format'
35
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
36
+ | _filter_json_filename
37
38
echo
39
echo '=== Backing name is always relative to the backed image ==='
40
@@ -XXX,XX +XXX,XX @@ TEST_IMG="json:{
41
}
42
]
43
}
44
-}" _img_info | _filter_img_info | grep -v 'backing file format'
45
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
46
+ | _filter_json_filename
47
48
49
# success, all done
50
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
14
index XXXXXXX..XXXXXXX 100644
51
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-doc.texi
52
--- a/tests/qemu-iotests/110.out
16
+++ b/qemu-doc.texi
53
+++ b/tests/qemu-iotests/110.out
17
@@ -XXX,XX +XXX,XX @@ in a configuration file provided via '-readconfig' or directly on the
54
@@ -XXX,XX +XXX,XX @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
18
command line.
55
19
56
=== Non-reconstructable filename ===
20
If the initiator-name is not specified qemu will use a default name
57
21
-of 'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
58
-image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
22
+of 'iqn.2008-11.org.linux-kvm[:<uuid>'] where <uuid> is the UUID of the
59
+image: json:{ /* filtered */ }
23
+virtual machine. If the UUID is not specified qemu will use
60
file format: IMGFMT
24
+'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
61
virtual size: 64 MiB (67108864 bytes)
25
virtual machine.
62
backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
26
63
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.b
27
-
64
28
@example
65
=== Nodes without a common directory ===
29
Setting a specific initiator name to use when logging in to the target
66
30
-iscsi initiator-name=iqn.qemu.test:my-initiator
67
-image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}}
68
+image: json:{ /* filtered */ }
69
file format: IMGFMT
70
virtual size: 64 MiB (67108864 bytes)
71
backing file: t.IMGFMT.base (cannot determine actual path)
31
--
72
--
32
2.13.5
73
2.24.1
33
74
34
75
diff view generated by jsdifflib
1
Add the scripts/ directory to sys.path so Python 2.6 will be able to
1
When using an external data file, there are no refcounts for data
2
import argparse.
2
clusters. We thus have to adjust the corruption test in this patch to
3
not be based around a data cluster allocation, but the L2 table
4
allocation (L2 tables are still refcounted with external data files).
3
5
4
Cc: Daniel P. Berrange <berrange@redhat.com>
6
Furthermore, we should not print qcow2.py's list of incompatible
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
features because it differs depending on whether there is an external
6
Acked-by: John Snow <jsnow@redhat.com>
8
data file or not.
7
Acked-by: Fam Zheng <famz@redhat.com>
9
8
Message-id: 20170825155732.15665-4-stefanha@redhat.com
10
With those two changes, the test will work both with and without
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
external data files (once that options works with the iotests at all).
12
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
15
Message-id: 20191107163708.833192-20-mreitz@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
17
---
11
tests/migration/guestperf/shell.py | 8 +++++---
18
tests/qemu-iotests/137 | 15 +++++++++++----
12
1 file changed, 5 insertions(+), 3 deletions(-)
19
tests/qemu-iotests/137.out | 6 ++----
20
2 files changed, 13 insertions(+), 8 deletions(-)
13
21
14
diff --git a/tests/migration/guestperf/shell.py b/tests/migration/guestperf/shell.py
22
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/137
25
+++ b/tests/qemu-iotests/137
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
27
"$TEST_IMG" 2>&1 | _filter_qemu_io
28
29
# The dirty bit must not be set
30
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
31
+# (Filter the external data file bit)
32
+if $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features \
33
+ | grep -q '\<0\>'
34
+then
35
+ echo 'ERROR: Dirty bit set'
36
+else
37
+ echo 'OK: Dirty bit not set'
38
+fi
39
40
# Similarly we can test whether corruption detection has been enabled:
41
-# Create L1/L2, overwrite first entry in refcount block, allocate something.
42
+# Create L1, overwrite refcounts, force allocation of L2 by writing
43
+# data.
44
# Disabling the checks should fail, so the corruption must be detected.
45
_make_test_img 64M
46
-$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
47
-poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00"
48
+poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00\x00\x00\x00\x00\x00\x00"
49
$QEMU_IO \
50
-c "reopen -o overlap-check=none,lazy-refcounts=42" \
51
-c "write 64k 64k" \
52
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
15
index XXXXXXX..XXXXXXX 100644
53
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/migration/guestperf/shell.py
54
--- a/tests/qemu-iotests/137.out
17
+++ b/tests/migration/guestperf/shell.py
55
+++ b/tests/qemu-iotests/137.out
18
@@ -XXX,XX +XXX,XX @@
56
@@ -XXX,XX +XXX,XX @@ qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are
19
#
57
wrote 512/512 bytes at offset 0
20
58
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
21
59
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
22
-import argparse
60
-incompatible_features []
23
-import fnmatch
61
+OK: Dirty bit not set
24
import os
62
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
25
import os.path
63
-wrote 65536/65536 bytes at offset 0
26
-import platform
64
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
27
import sys
65
qemu-io: Parameter 'lazy-refcounts' expects 'on' or 'off'
28
+sys.path.append(os.path.join(os.path.dirname(__file__),
66
-qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed
29
+ '..', '..', '..', 'scripts'))
67
+qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed
30
+import argparse
68
write failed: Input/output error
31
+import fnmatch
69
*** done
32
+import platform
33
34
from guestperf.hardware import Hardware
35
from guestperf.engine import Engine
36
--
70
--
37
2.13.5
71
2.24.1
38
72
39
73
diff view generated by jsdifflib
1
Add the scripts/ directory to sys.path so Python 2.6 will be able to
1
We do not care about the json:{} filenames here, so we can just filter
2
import argparse.
2
them out and thus make the test work both with and without external data
3
files.
3
4
4
Cc: Fam Zheng <famz@redhat.com>
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Acked-by: John Snow <jsnow@redhat.com>
7
Message-id: 20191107163708.833192-21-mreitz@redhat.com
7
Acked-by: Fam Zheng <famz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20170825155732.15665-3-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
9
---
11
tests/docker/docker.py | 4 +++-
10
tests/qemu-iotests/198 | 6 ++++--
12
1 file changed, 3 insertions(+), 1 deletion(-)
11
tests/qemu-iotests/198.out | 4 ++--
12
2 files changed, 6 insertions(+), 4 deletions(-)
13
13
14
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
14
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
15
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/docker/docker.py
16
--- a/tests/qemu-iotests/198
17
+++ b/tests/docker/docker.py
17
+++ b/tests/qemu-iotests/198
18
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ echo
19
19
echo "== checking image base =="
20
import os
20
$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info --format-specific \
21
import sys
21
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
22
+sys.path.append(os.path.join(os.path.dirname(__file__),
22
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
23
+ '..', '..', 'scripts'))
23
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
24
+import argparse
24
+ | _filter_json_filename
25
import subprocess
25
26
import json
26
echo
27
import hashlib
27
echo "== checking image layer =="
28
import atexit
28
$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info --format-specific \
29
import uuid
29
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
30
-import argparse
30
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
31
import tempfile
31
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
32
import re
32
+ | _filter_json_filename
33
import signal
33
34
35
# success, all done
36
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/198.out
39
+++ b/tests/qemu-iotests/198.out
40
@@ -XXX,XX +XXX,XX @@ read 16777216/16777216 bytes at offset 0
41
16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
42
43
== checking image base ==
44
-image: json:{"encrypt.key-secret": "sec0", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.base"}}
45
+image: json:{ /* filtered */ }
46
file format: IMGFMT
47
virtual size: 16 MiB (16777216 bytes)
48
Format specific information:
49
@@ -XXX,XX +XXX,XX @@ Format specific information:
50
master key iters: 1024
51
52
== checking image layer ==
53
-image: json:{"encrypt.key-secret": "sec1", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}
54
+image: json:{ /* filtered */ }
55
file format: IMGFMT
56
virtual size: 16 MiB (16777216 bytes)
57
backing file: TEST_DIR/t.IMGFMT.base
34
--
58
--
35
2.13.5
59
2.24.1
36
60
37
61
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Message-id: 20191107163708.833192-22-mreitz@redhat.com
3
[mreitz: Also disable 273]
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
6
tests/qemu-iotests/007 | 5 +++--
7
tests/qemu-iotests/014 | 2 ++
8
tests/qemu-iotests/015 | 5 +++--
9
tests/qemu-iotests/026 | 5 ++++-
10
tests/qemu-iotests/029 | 5 +++--
11
tests/qemu-iotests/031 | 6 +++---
12
tests/qemu-iotests/036 | 5 +++--
13
tests/qemu-iotests/039 | 3 +++
14
tests/qemu-iotests/046 | 2 ++
15
tests/qemu-iotests/048 | 2 ++
16
tests/qemu-iotests/051 | 5 +++--
17
tests/qemu-iotests/058 | 5 +++--
18
tests/qemu-iotests/060 | 6 ++++--
19
tests/qemu-iotests/061 | 6 ++++--
20
tests/qemu-iotests/062 | 2 +-
21
tests/qemu-iotests/066 | 4 +++-
22
tests/qemu-iotests/067 | 6 ++++--
23
tests/qemu-iotests/068 | 5 +++--
24
tests/qemu-iotests/071 | 3 +++
25
tests/qemu-iotests/073 | 4 ++++
26
tests/qemu-iotests/074 | 2 ++
27
tests/qemu-iotests/080 | 5 +++--
28
tests/qemu-iotests/090 | 2 ++
29
tests/qemu-iotests/098 | 6 ++++--
30
tests/qemu-iotests/099 | 3 ++-
31
tests/qemu-iotests/103 | 5 +++--
32
tests/qemu-iotests/108 | 6 ++++--
33
tests/qemu-iotests/112 | 5 +++--
34
tests/qemu-iotests/114 | 2 ++
35
tests/qemu-iotests/121 | 3 +++
36
tests/qemu-iotests/138 | 3 +++
37
tests/qemu-iotests/156 | 2 ++
38
tests/qemu-iotests/176 | 7 +++++--
39
tests/qemu-iotests/191 | 2 ++
40
tests/qemu-iotests/201 | 6 +++---
41
tests/qemu-iotests/214 | 3 ++-
42
tests/qemu-iotests/217 | 3 ++-
43
tests/qemu-iotests/220 | 5 +++--
44
tests/qemu-iotests/243 | 6 ++++--
45
tests/qemu-iotests/244 | 5 +++--
46
tests/qemu-iotests/250 | 2 ++
47
tests/qemu-iotests/261 | 3 ++-
48
tests/qemu-iotests/267 | 5 +++--
49
tests/qemu-iotests/273 | 3 +++
50
44 files changed, 127 insertions(+), 53 deletions(-)
2
51
3
LeakyBucket.burst_length is defined as an unsigned integer but the
52
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
4
code never checks for overflows and it only makes sure that the value
53
index XXXXXXX..XXXXXXX 100755
5
is not 0.
54
--- a/tests/qemu-iotests/007
6
55
+++ b/tests/qemu-iotests/007
7
In practice this means that the user can set something like
56
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
8
throttling.iops-total-max-length=4294967300 despite being larger than
57
_supported_fmt qcow2
9
UINT_MAX and the final value after casting to unsigned int will be 4.
58
_supported_proto generic
10
59
# refcount_bits must be at least 4 so we can create ten internal snapshots
11
This patch changes the data type to uint64_t. This does not increase
60
-# (1 bit supports none, 2 bits support two, 4 bits support 14)
12
the storage size of LeakyBucket, and allows us to assign the value
61
-_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]'
13
directly from qemu_opt_get_number() or BlockIOThrottle and then do the
62
+# (1 bit supports none, 2 bits support two, 4 bits support 14);
14
checks directly in throttle_is_valid().
63
+# snapshot are generally impossible with external data files
15
64
+_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]' data_file
16
The value of burst_length does not have a specific upper limit,
65
17
but since the bucket size is defined by max * burst_length we have
66
echo
18
to prevent overflows. Instead of going for UINT64_MAX or something
67
echo "creating image"
19
similar this patch reuses THROTTLE_VALUE_MAX, which allows I/O bursts
68
diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014
20
of 1 GiB/s for 10 days in a row.
69
index XXXXXXX..XXXXXXX 100755
21
70
--- a/tests/qemu-iotests/014
22
Signed-off-by: Alberto Garcia <berto@igalia.com>
71
+++ b/tests/qemu-iotests/014
23
Message-id: 1b2e3049803f71cafb2e1fa1be4fb47147a0d398.1503580370.git.berto@igalia.com
72
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
73
_supported_fmt qcow2
25
---
74
_supported_proto file
26
include/qemu/throttle.h | 2 +-
75
_supported_os Linux
27
util/throttle.c | 5 +++++
76
+# Compression and snapshots do not work with external data files
28
2 files changed, 6 insertions(+), 1 deletion(-)
77
+_unsupported_imgopts data_file
29
78
30
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
79
TEST_OFFSETS="0 4294967296"
31
index XXXXXXX..XXXXXXX 100644
80
TEST_OPS="writev read write readv"
32
--- a/include/qemu/throttle.h
81
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
33
+++ b/include/qemu/throttle.h
82
index XXXXXXX..XXXXXXX 100755
34
@@ -XXX,XX +XXX,XX @@ typedef struct LeakyBucket {
83
--- a/tests/qemu-iotests/015
35
uint64_t max; /* leaky bucket max burst in units */
84
+++ b/tests/qemu-iotests/015
36
double level; /* bucket level in units */
85
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
37
double burst_level; /* bucket level in units (for computing bursts) */
86
# actually any format that supports snapshots
38
- unsigned burst_length; /* max length of the burst period, in seconds */
87
_supported_fmt qcow2
39
+ uint64_t burst_length; /* max length of the burst period, in seconds */
88
_supported_proto generic
40
} LeakyBucket;
89
-# Internal snapshots are (currently) impossible with refcount_bits=1
41
90
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
42
/* The following structure is used to configure a ThrottleState
91
+# Internal snapshots are (currently) impossible with refcount_bits=1,
43
diff --git a/util/throttle.c b/util/throttle.c
92
+# and generally impossible with external data files
44
index XXXXXXX..XXXXXXX 100644
93
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
45
--- a/util/throttle.c
94
46
+++ b/util/throttle.c
95
echo
47
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
96
echo "creating image"
48
return false;
97
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
49
}
98
index XXXXXXX..XXXXXXX 100755
50
99
--- a/tests/qemu-iotests/026
51
+ if (bkt->max && bkt->burst_length > THROTTLE_VALUE_MAX / bkt->max) {
100
+++ b/tests/qemu-iotests/026
52
+ error_setg(errp, "burst length too high for this burst rate");
101
@@ -XXX,XX +XXX,XX @@ _supported_cache_modes writethrough none
53
+ return false;
102
# 32 and 64 bits do not work either, however, due to different leaked cluster
54
+ }
103
# count on error.
55
+
104
# Thus, the only remaining option is refcount_bits=16.
56
if (bkt->max && !bkt->avg) {
105
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
57
error_setg(errp, "bps_max/iops_max require corresponding"
106
+#
58
" bps/iops values");
107
+# As for data_file, none of the refcount tests can work for it.
108
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' \
109
+ data_file
110
111
echo "Errors while writing 128 kB"
112
echo
113
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
114
index XXXXXXX..XXXXXXX 100755
115
--- a/tests/qemu-iotests/029
116
+++ b/tests/qemu-iotests/029
117
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
118
_supported_fmt qcow2
119
_supported_proto generic
120
_unsupported_proto vxhs
121
-# Internal snapshots are (currently) impossible with refcount_bits=1
122
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
123
+# Internal snapshots are (currently) impossible with refcount_bits=1,
124
+# and generally impossible with external data files
125
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
126
127
offset_size=24
128
offset_l1_size=36
129
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
130
index XXXXXXX..XXXXXXX 100755
131
--- a/tests/qemu-iotests/031
132
+++ b/tests/qemu-iotests/031
133
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
134
# This tests qcow2-specific low-level functionality
135
_supported_fmt qcow2
136
_supported_proto file
137
-# We want to test compat=0.10, which does not support refcount widths
138
-# other than 16
139
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
140
+# We want to test compat=0.10, which does not support external data
141
+# files or refcount widths other than 16
142
+_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
143
144
CLUSTER_SIZE=65536
145
146
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
147
index XXXXXXX..XXXXXXX 100755
148
--- a/tests/qemu-iotests/036
149
+++ b/tests/qemu-iotests/036
150
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
151
# This tests qcow2-specific low-level functionality
152
_supported_fmt qcow2
153
_supported_proto file
154
-# Only qcow2v3 and later supports feature bits
155
-_unsupported_imgopts 'compat=0.10'
156
+# Only qcow2v3 and later supports feature bits;
157
+# qcow2.py does not support external data files
158
+_unsupported_imgopts 'compat=0.10' data_file
159
160
echo
161
echo === Image with unknown incompatible feature bit ===
162
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
163
index XXXXXXX..XXXXXXX 100755
164
--- a/tests/qemu-iotests/039
165
+++ b/tests/qemu-iotests/039
166
@@ -XXX,XX +XXX,XX @@ _supported_proto file
167
_supported_os Linux
168
_default_cache_mode writethrough
169
_supported_cache_modes writethrough
170
+# Some of these test cases expect no external data file so that all
171
+# clusters are part of the qcow2 image and refcounted
172
+_unsupported_imgopts data_file
173
174
size=128M
175
176
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
177
index XXXXXXX..XXXXXXX 100755
178
--- a/tests/qemu-iotests/046
179
+++ b/tests/qemu-iotests/046
180
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
181
182
_supported_fmt qcow2
183
_supported_proto file
184
+# data_file does not support compressed clusters
185
+_unsupported_imgopts data_file
186
187
CLUSTER_SIZE=64k
188
size=128M
189
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
190
index XXXXXXX..XXXXXXX 100755
191
--- a/tests/qemu-iotests/048
192
+++ b/tests/qemu-iotests/048
193
@@ -XXX,XX +XXX,XX @@ _compare()
194
_supported_fmt raw qcow2 qed luks
195
_supported_proto file
196
_supported_os Linux
197
+# Using 'cp' is incompatible with external data files
198
+_unsupported_imgopts data_file
199
200
# Remove once all tests are fixed to use TEST_IMG_FILE
201
# correctly and common.rc sets it unconditionally
202
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
203
index XXXXXXX..XXXXXXX 100755
204
--- a/tests/qemu-iotests/051
205
+++ b/tests/qemu-iotests/051
206
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
207
_supported_fmt qcow2
208
_supported_proto file
209
# A compat=0.10 image is created in this test which does not support anything
210
-# other than refcount_bits=16
211
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
212
+# other than refcount_bits=16;
213
+# it also will not support an external data file
214
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
215
_require_drivers nbd
216
217
do_run_qemu()
218
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
219
index XXXXXXX..XXXXXXX 100755
220
--- a/tests/qemu-iotests/058
221
+++ b/tests/qemu-iotests/058
222
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
223
_supported_proto file
224
_supported_os Linux
225
_require_command QEMU_NBD
226
-# Internal snapshots are (currently) impossible with refcount_bits=1
227
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
228
+# Internal snapshots are (currently) impossible with refcount_bits=1,
229
+# and generally impossible with external data files
230
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
231
232
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
233
234
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
235
index XXXXXXX..XXXXXXX 100755
236
--- a/tests/qemu-iotests/060
237
+++ b/tests/qemu-iotests/060
238
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
239
_supported_fmt qcow2
240
_supported_proto file
241
_supported_os Linux
242
-# These tests only work for compat=1.1 images with refcount_bits=16
243
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
244
+# These tests only work for compat=1.1 images without an external
245
+# data file with refcount_bits=16
246
+_unsupported_imgopts 'compat=0.10' data_file \
247
+ 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
248
249
# The repair process will create a large file - so check for availability first
250
_require_large_file 64G
251
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
252
index XXXXXXX..XXXXXXX 100755
253
--- a/tests/qemu-iotests/061
254
+++ b/tests/qemu-iotests/061
255
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
256
_supported_proto file
257
_supported_os Linux
258
# Conversion between different compat versions can only really work
259
-# with refcount_bits=16
260
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
261
+# with refcount_bits=16;
262
+# we have explicit tests for data_file here, but the whole test does
263
+# not work with it
264
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
265
266
echo
267
echo "=== Testing version downgrade with zero expansion ==="
268
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
269
index XXXXXXX..XXXXXXX 100755
270
--- a/tests/qemu-iotests/062
271
+++ b/tests/qemu-iotests/062
272
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
273
_supported_fmt qcow2
274
_supported_proto generic
275
# We need zero clusters and snapshots
276
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
277
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
278
279
IMG_SIZE=64M
280
281
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
282
index XXXXXXX..XXXXXXX 100755
283
--- a/tests/qemu-iotests/066
284
+++ b/tests/qemu-iotests/066
285
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
286
_supported_fmt qcow2
287
_supported_proto generic
288
# We need zero clusters and snapshots
289
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
290
+# (TODO: Consider splitting the snapshot part into a separate test
291
+# file, so this one runs with refcount_bits=1 and data_file)
292
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
293
294
# Intentionally create an unaligned image
295
IMG_SIZE=$((64 * 1024 * 1024 + 512))
296
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
297
index XXXXXXX..XXXXXXX 100755
298
--- a/tests/qemu-iotests/067
299
+++ b/tests/qemu-iotests/067
300
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
301
302
_supported_fmt qcow2
303
_supported_proto file
304
-# Because anything other than 16 would change the output of query-block
305
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
306
+# Because anything other than 16 would change the output of query-block,
307
+# and external data files would change the output of
308
+# query-named-block-nodes
309
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
310
311
do_run_qemu()
312
{
313
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
314
index XXXXXXX..XXXXXXX 100755
315
--- a/tests/qemu-iotests/068
316
+++ b/tests/qemu-iotests/068
317
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
318
# This tests qcow2-specific low-level functionality
319
_supported_fmt qcow2
320
_supported_proto generic
321
-# Internal snapshots are (currently) impossible with refcount_bits=1
322
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
323
+# Internal snapshots are (currently) impossible with refcount_bits=1,
324
+# and generally impossible with external data files
325
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
326
327
IMG_SIZE=128K
328
329
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
330
index XXXXXXX..XXXXXXX 100755
331
--- a/tests/qemu-iotests/071
332
+++ b/tests/qemu-iotests/071
333
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
334
_supported_fmt qcow2
335
_supported_proto file
336
_require_drivers blkdebug blkverify
337
+# blkdebug can only inject errors on bs->file, not on the data_file,
338
+# so thie test does not work with external data files
339
+_unsupported_imgopts data_file
340
341
do_run_qemu()
342
{
343
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
344
index XXXXXXX..XXXXXXX 100755
345
--- a/tests/qemu-iotests/073
346
+++ b/tests/qemu-iotests/073
347
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
348
_supported_fmt qcow2
349
_supported_proto generic
350
_unsupported_proto vxhs
351
+# External data files do not support compressed clusters
352
+# (TODO: Consider writing a version for external data files that does
353
+# not test compressed clusters)
354
+_unsupported_imgopts data_file
355
356
CLUSTER_SIZE=64k
357
size=128M
358
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
359
index XXXXXXX..XXXXXXX 100755
360
--- a/tests/qemu-iotests/074
361
+++ b/tests/qemu-iotests/074
362
@@ -XXX,XX +XXX,XX @@ _compare()
363
_supported_fmt qcow2
364
_supported_proto file
365
_supported_os Linux
366
+# blkdebug can only inject errors on bs->file
367
+_unsupported_imgopts data_file
368
369
# Setup test basic parameters
370
TEST_IMG2=$TEST_IMG.2
371
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
372
index XXXXXXX..XXXXXXX 100755
373
--- a/tests/qemu-iotests/080
374
+++ b/tests/qemu-iotests/080
375
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
376
_supported_fmt qcow2
377
_supported_proto file
378
_supported_os Linux
379
-# - Internal snapshots are (currently) impossible with refcount_bits=1
380
+# - Internal snapshots are (currently) impossible with refcount_bits=1,
381
+# and generally impossible with external data files
382
# - This is generally a test for compat=1.1 images
383
-_unsupported_imgopts 'refcount_bits=1[^0-9]' 'compat=0.10'
384
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file 'compat=0.10'
385
386
header_size=104
387
388
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
389
index XXXXXXX..XXXXXXX 100755
390
--- a/tests/qemu-iotests/090
391
+++ b/tests/qemu-iotests/090
392
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
393
394
_supported_fmt qcow2
395
_supported_proto file nfs
396
+# External data files do not support compressed clusters
397
+_unsupported_imgopts data_file
398
399
IMG_SIZE=128K
400
401
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
402
index XXXXXXX..XXXXXXX 100755
403
--- a/tests/qemu-iotests/098
404
+++ b/tests/qemu-iotests/098
405
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
406
407
_supported_fmt qcow2
408
_supported_proto file
409
-# The code path we want to test here only works for compat=1.1 images
410
-_unsupported_imgopts 'compat=0.10'
411
+# The code path we want to test here only works for compat=1.1 images;
412
+# blkdebug can only inject errors on bs->file, so external data files
413
+# do not work with this test
414
+_unsupported_imgopts 'compat=0.10' data_file
415
416
for event in l1_update empty_image_prepare reftable_update refblock_alloc; do
417
418
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
419
index XXXXXXX..XXXXXXX 100755
420
--- a/tests/qemu-iotests/099
421
+++ b/tests/qemu-iotests/099
422
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
423
_supported_proto file
424
_supported_os Linux
425
_require_drivers blkdebug blkverify
426
+# data_file would change the json:{} filenames
427
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
428
- "subformat=twoGbMaxExtentSparse"
429
+ "subformat=twoGbMaxExtentSparse" data_file
430
431
do_run_qemu()
432
{
433
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
434
index XXXXXXX..XXXXXXX 100755
435
--- a/tests/qemu-iotests/103
436
+++ b/tests/qemu-iotests/103
437
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
438
439
_supported_fmt qcow2
440
_supported_proto file nfs
441
-# Internal snapshots are (currently) impossible with refcount_bits=1
442
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
443
+# Internal snapshots are (currently) impossible with refcount_bits=1,
444
+# and generally impossible with external data files
445
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
446
447
IMG_SIZE=64K
448
449
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
450
index XXXXXXX..XXXXXXX 100755
451
--- a/tests/qemu-iotests/108
452
+++ b/tests/qemu-iotests/108
453
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
454
_supported_fmt qcow2
455
_supported_proto file
456
_supported_os Linux
457
-# This test directly modifies a refblock so it relies on refcount_bits being 16
458
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
459
+# This test directly modifies a refblock so it relies on refcount_bits being 16;
460
+# and the low-level modification it performs are not tuned for external data
461
+# files
462
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
463
464
echo
465
echo '=== Repairing an image without any refcount table ==='
466
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
467
index XXXXXXX..XXXXXXX 100755
468
--- a/tests/qemu-iotests/112
469
+++ b/tests/qemu-iotests/112
470
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
471
_supported_fmt qcow2
472
_supported_proto file
473
# This test will set refcount_bits on its own which would conflict with the
474
-# manual setting; compat will be overridden as well
475
-_unsupported_imgopts refcount_bits 'compat=0.10'
476
+# manual setting; compat will be overridden as well;
477
+# and external data files do not work well with our refcount testing
478
+_unsupported_imgopts refcount_bits 'compat=0.10' data_file
479
480
print_refcount_bits()
481
{
482
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
483
index XXXXXXX..XXXXXXX 100755
484
--- a/tests/qemu-iotests/114
485
+++ b/tests/qemu-iotests/114
486
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
487
_supported_fmt qcow2
488
_supported_proto generic
489
_unsupported_proto vxhs
490
+# qcow2.py does not work too well with external data files
491
+_unsupported_imgopts data_file
492
493
494
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
495
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
496
index XXXXXXX..XXXXXXX 100755
497
--- a/tests/qemu-iotests/121
498
+++ b/tests/qemu-iotests/121
499
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
500
_supported_fmt qcow2
501
_supported_proto file
502
_supported_os Linux
503
+# Refcount structures are used much differently with external data
504
+# files
505
+_unsupported_imgopts data_file
506
507
echo
508
echo '=== New refcount structures may not conflict with existing structures ==='
509
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
510
index XXXXXXX..XXXXXXX 100755
511
--- a/tests/qemu-iotests/138
512
+++ b/tests/qemu-iotests/138
513
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
514
_supported_fmt qcow2
515
_supported_proto file
516
_supported_os Linux
517
+# With an external data file, data clusters are not refcounted
518
+# (and so qemu-img check does not check their refcount)
519
+_unsupported_imgopts data_file
520
521
echo
522
echo '=== Check on an image with a multiple of 2^32 clusters ==='
523
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
524
index XXXXXXX..XXXXXXX 100755
525
--- a/tests/qemu-iotests/156
526
+++ b/tests/qemu-iotests/156
527
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
528
_supported_fmt qcow2 qed
529
_supported_proto generic
530
_unsupported_proto vxhs
531
+# Copying files around with cp does not work with external data files
532
+_unsupported_imgopts data_file
533
534
# Create source disk
535
TEST_IMG="$TEST_IMG.backing" _make_test_img 1M
536
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
537
index XXXXXXX..XXXXXXX 100755
538
--- a/tests/qemu-iotests/176
539
+++ b/tests/qemu-iotests/176
540
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
541
_supported_fmt qcow2
542
_supported_proto file
543
_supported_os Linux
544
-# Persistent dirty bitmaps require compat=1.1
545
-_unsupported_imgopts 'compat=0.10'
546
+# Persistent dirty bitmaps require compat=1.1;
547
+# Internal snapshots forbid using an external data file
548
+# (they work with refcount_bits=1 here, though, because there actually
549
+# is no data when creating the snapshot)
550
+_unsupported_imgopts 'compat=0.10' data_file
551
552
run_qemu()
553
{
554
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
555
index XXXXXXX..XXXXXXX 100755
556
--- a/tests/qemu-iotests/191
557
+++ b/tests/qemu-iotests/191
558
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
559
560
_supported_fmt qcow2
561
_supported_proto file
562
+# An external data file would change the query-named-block-nodes output
563
+_unsupported_imgopts data_file
564
565
size=64M
566
567
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
568
index XXXXXXX..XXXXXXX 100755
569
--- a/tests/qemu-iotests/201
570
+++ b/tests/qemu-iotests/201
571
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
572
_supported_proto generic
573
_supported_os Linux
574
575
-# Internal snapshots are (currently) impossible with refcount_bits=1
576
-# This was taken from test 080
577
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
578
+# Internal snapshots are (currently) impossible with refcount_bits=1,
579
+# and generally impossible with external data files
580
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
581
582
size=64M
583
_make_test_img $size
584
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
585
index XXXXXXX..XXXXXXX 100755
586
--- a/tests/qemu-iotests/214
587
+++ b/tests/qemu-iotests/214
588
@@ -XXX,XX +XXX,XX @@ _supported_proto file
589
590
# Repairing the corrupted image requires qemu-img check to store a
591
# refcount up to 3, which requires at least two refcount bits.
592
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
593
+# External data files do not support compressed clusters.
594
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
595
596
597
echo
598
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
599
index XXXXXXX..XXXXXXX 100755
600
--- a/tests/qemu-iotests/217
601
+++ b/tests/qemu-iotests/217
602
@@ -XXX,XX +XXX,XX @@ _supported_proto file
603
604
# This test needs clusters with at least a refcount of 2 so that
605
# OFLAG_COPIED is not set. refcount_bits=1 is therefore unsupported.
606
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
607
+# (As are external data files.)
608
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
609
610
echo
611
echo '=== Simulating an I/O error during snapshot deletion ==='
612
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
613
index XXXXXXX..XXXXXXX 100755
614
--- a/tests/qemu-iotests/220
615
+++ b/tests/qemu-iotests/220
616
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
617
_supported_fmt qcow2
618
_supported_proto file
619
_supported_os Linux
620
-# To use a different refcount width but 16 bits we need compat=1.1
621
-_unsupported_imgopts 'compat=0.10'
622
+# To use a different refcount width but 16 bits we need compat=1.1,
623
+# and external data files do not support compressed clusters.
624
+_unsupported_imgopts 'compat=0.10' data_file
625
626
echo "== Creating huge file =="
627
628
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
629
index XXXXXXX..XXXXXXX 100755
630
--- a/tests/qemu-iotests/243
631
+++ b/tests/qemu-iotests/243
632
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
633
_supported_fmt qcow2
634
_supported_proto file
635
_supported_os Linux
636
-# External data files do not work with compat=0.10
637
-_unsupported_imgopts 'compat=0.10'
638
+# External data files do not work with compat=0.10, and because there
639
+# is an explicit case for external data files here, we cannot allow
640
+# the user to specify whether to use one
641
+_unsupported_imgopts 'compat=0.10' data_file
642
643
for mode in off metadata falloc full; do
644
645
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
646
index XXXXXXX..XXXXXXX 100755
647
--- a/tests/qemu-iotests/244
648
+++ b/tests/qemu-iotests/244
649
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
650
_supported_fmt qcow2
651
_supported_proto file
652
_supported_os Linux
653
-# External data files do not work with compat=0.10
654
-_unsupported_imgopts 'compat=0.10'
655
+# External data files do not work with compat=0.10, and because we use
656
+# our own external data file, we cannot let the user specify one
657
+_unsupported_imgopts 'compat=0.10' data_file
658
659
echo
660
echo "=== Create and open image with external data file ==="
661
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
662
index XXXXXXX..XXXXXXX 100755
663
--- a/tests/qemu-iotests/250
664
+++ b/tests/qemu-iotests/250
665
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
666
_supported_fmt qcow2
667
_supported_proto file
668
_supported_os Linux
669
+# This test does not make much sense with external data files
670
+_unsupported_imgopts data_file
671
672
# This test checks that qcow2_process_discards does not truncate a discard
673
# request > 2G.
674
diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261
675
index XXXXXXX..XXXXXXX 100755
676
--- a/tests/qemu-iotests/261
677
+++ b/tests/qemu-iotests/261
678
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
679
# (1) We create a v2 image that supports nothing but refcount_bits=16
680
# (2) We do some refcount management on our own which expects
681
# refcount_bits=16
682
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
683
+# As for data files, they do not support snapshots at all.
684
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
685
686
# Parameters:
687
# $1: image filename
688
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
689
index XXXXXXX..XXXXXXX 100755
690
--- a/tests/qemu-iotests/267
691
+++ b/tests/qemu-iotests/267
692
@@ -XXX,XX +XXX,XX @@ _supported_proto file
693
_supported_os Linux
694
_require_drivers copy-on-read
695
696
-# Internal snapshots are (currently) impossible with refcount_bits=1
697
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
698
+# Internal snapshots are (currently) impossible with refcount_bits=1,
699
+# and generally impossible with external data files
700
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
701
702
do_run_qemu()
703
{
704
diff --git a/tests/qemu-iotests/273 b/tests/qemu-iotests/273
705
index XXXXXXX..XXXXXXX 100755
706
--- a/tests/qemu-iotests/273
707
+++ b/tests/qemu-iotests/273
708
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
709
_supported_fmt qcow2
710
_supported_proto file
711
_supported_os Linux
712
+# External data files would add nodes to the block graph, so it would
713
+# not match the reference output
714
+_unsupported_imgopts data_file
715
716
do_run_qemu()
717
{
59
--
718
--
60
2.13.5
719
2.24.1
61
720
62
721
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The problem with allowing the data_file option is that you want to use a
2
different data file per image used in the test. Therefore, we need to
3
allow patterns like -o data_file='$TEST_IMG.data_file'.
2
4
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
5
Then, we need to filter it out from qemu-img map, qemu-img create, and
4
Message-id: a57dd6274e1b6dc9c28769fec4c7ea543be5c5e3.1503580370.git.berto@igalia.com
6
remove the data file in _rm_test_img.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
10
Message-id: 20191107163708.833192-23-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
12
---
7
tests/test-throttle.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
13
tests/qemu-iotests/common.filter | 23 +++++++++++++++++++++--
8
1 file changed, 77 insertions(+)
14
tests/qemu-iotests/common.rc | 22 +++++++++++++++++++++-
15
2 files changed, 42 insertions(+), 3 deletions(-)
9
16
10
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
17
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
11
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-throttle.c
19
--- a/tests/qemu-iotests/common.filter
13
+++ b/tests/test-throttle.c
20
+++ b/tests/qemu-iotests/common.filter
14
@@ -XXX,XX +XXX,XX @@ static void test_is_valid(void)
21
@@ -XXX,XX +XXX,XX @@ _filter_actual_image_size()
15
test_is_valid_for_value(1, true);
22
# replace driver-specific options in the "Formatting..." line
23
_filter_img_create()
24
{
25
- $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
26
+ data_file_filter=()
27
+ if data_file=$(_get_data_file "$TEST_IMG"); then
28
+ data_file_filter=(-e "s# data_file=$data_file##")
29
+ fi
30
+
31
+ $SED "${data_file_filter[@]}" \
32
+ -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
33
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
34
-e "s#$TEST_DIR#TEST_DIR#g" \
35
-e "s#$SOCK_DIR#SOCK_DIR#g" \
36
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
37
# human and json output
38
_filter_qemu_img_map()
39
{
40
+ # Assuming the data_file value in $IMGOPTS contains a '$TEST_IMG',
41
+ # create a filter that replaces the data file name by $TEST_IMG.
42
+ # Example:
43
+ # In $IMGOPTS: 'data_file=$TEST_IMG.data_file'
44
+ # Then data_file_pattern == '\(.*\).data_file'
45
+ # And data_file_filter == -e 's#\(.*\).data_file#\1#
46
+ data_file_filter=()
47
+ if data_file_pattern=$(_get_data_file '\\(.*\\)'); then
48
+ data_file_filter=(-e "s#$data_file_pattern#\\1#")
49
+ fi
50
+
51
$SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \
52
-e 's/"offset": [0-9]\+/"offset": OFFSET/g' \
53
- -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt
54
+ -e 's/Mapped to *//' \
55
+ "${data_file_filter[@]}" \
56
+ | _filter_testdir | _filter_imgfmt
16
}
57
}
17
58
18
+static void test_ranges(void)
59
_filter_nbd()
60
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/qemu-iotests/common.rc
63
+++ b/tests/qemu-iotests/common.rc
64
@@ -XXX,XX +XXX,XX @@ _stop_nbd_server()
65
fi
66
}
67
68
+# Gets the data_file value from IMGOPTS and replaces the '$TEST_IMG'
69
+# pattern by '$1'
70
+# Caution: The replacement is done with sed, so $1 must be escaped
71
+# properly. (The delimiter is '#'.)
72
+_get_data_file()
19
+{
73
+{
20
+ int i;
74
+ if ! echo "$IMGOPTS" | grep -q 'data_file='; then
75
+ return 1
76
+ fi
21
+
77
+
22
+ for (i = 0; i < BUCKETS_COUNT; i++) {
78
+ echo "$IMGOPTS" | sed -e 's/.*data_file=\([^,]*\).*/\1/' \
23
+ LeakyBucket *b = &cfg.buckets[i];
79
+ | sed -e "s#\\\$TEST_IMG#$1#"
24
+ throttle_config_init(&cfg);
25
+
26
+ /* avg = 0 means throttling is disabled, but the config is valid */
27
+ b->avg = 0;
28
+ g_assert(throttle_is_valid(&cfg, NULL));
29
+ g_assert(!throttle_enabled(&cfg));
30
+
31
+ /* These are valid configurations (values <= THROTTLE_VALUE_MAX) */
32
+ b->avg = 1;
33
+ g_assert(throttle_is_valid(&cfg, NULL));
34
+
35
+ b->avg = THROTTLE_VALUE_MAX;
36
+ g_assert(throttle_is_valid(&cfg, NULL));
37
+
38
+ b->avg = THROTTLE_VALUE_MAX;
39
+ b->max = THROTTLE_VALUE_MAX;
40
+ g_assert(throttle_is_valid(&cfg, NULL));
41
+
42
+ /* Values over THROTTLE_VALUE_MAX are not allowed */
43
+ b->avg = THROTTLE_VALUE_MAX + 1;
44
+ g_assert(!throttle_is_valid(&cfg, NULL));
45
+
46
+ b->avg = THROTTLE_VALUE_MAX;
47
+ b->max = THROTTLE_VALUE_MAX + 1;
48
+ g_assert(!throttle_is_valid(&cfg, NULL));
49
+
50
+ /* burst_length must be between 1 and THROTTLE_VALUE_MAX */
51
+ b->avg = 1;
52
+ b->max = 1;
53
+ b->burst_length = 0;
54
+ g_assert(!throttle_is_valid(&cfg, NULL));
55
+
56
+ b->avg = 1;
57
+ b->max = 1;
58
+ b->burst_length = 1;
59
+ g_assert(throttle_is_valid(&cfg, NULL));
60
+
61
+ b->avg = 1;
62
+ b->max = 1;
63
+ b->burst_length = THROTTLE_VALUE_MAX;
64
+ g_assert(throttle_is_valid(&cfg, NULL));
65
+
66
+ b->avg = 1;
67
+ b->max = 1;
68
+ b->burst_length = THROTTLE_VALUE_MAX + 1;
69
+ g_assert(!throttle_is_valid(&cfg, NULL));
70
+
71
+ /* burst_length * max cannot exceed THROTTLE_VALUE_MAX */
72
+ b->avg = 1;
73
+ b->max = 2;
74
+ b->burst_length = THROTTLE_VALUE_MAX / 2;
75
+ g_assert(throttle_is_valid(&cfg, NULL));
76
+
77
+ b->avg = 1;
78
+ b->max = 3;
79
+ b->burst_length = THROTTLE_VALUE_MAX / 2;
80
+ g_assert(!throttle_is_valid(&cfg, NULL));
81
+
82
+ b->avg = 1;
83
+ b->max = THROTTLE_VALUE_MAX;
84
+ b->burst_length = 1;
85
+ g_assert(throttle_is_valid(&cfg, NULL));
86
+
87
+ b->avg = 1;
88
+ b->max = THROTTLE_VALUE_MAX;
89
+ b->burst_length = 2;
90
+ g_assert(!throttle_is_valid(&cfg, NULL));
91
+ }
92
+}
80
+}
93
+
81
+
94
static void test_max_is_missing_limit(void)
82
_make_test_img()
95
{
83
{
96
int i;
84
# extra qemu-img options can be added by tests
97
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
85
@@ -XXX,XX +XXX,XX @@ _make_test_img()
98
g_test_add_func("/throttle/config/enabled", test_enabled);
86
fi
99
g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
87
100
g_test_add_func("/throttle/config/is_valid", test_is_valid);
88
if [ -n "$IMGOPTS" ]; then
101
+ g_test_add_func("/throttle/config/ranges", test_ranges);
89
- optstr=$(_optstr_add "$optstr" "$IMGOPTS")
102
g_test_add_func("/throttle/config/max", test_max_is_missing_limit);
90
+ imgopts_expanded=$(echo "$IMGOPTS" | sed -e "s#\\\$TEST_IMG#$img_name#")
103
g_test_add_func("/throttle/config/iops_size",
91
+ optstr=$(_optstr_add "$optstr" "$imgopts_expanded")
104
test_iops_size_is_missing_limit);
92
fi
93
if [ -n "$IMGKEYSECRET" ]; then
94
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
95
@@ -XXX,XX +XXX,XX @@ _rm_test_img()
96
# Remove all the extents for vmdk
97
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
98
| xargs -I {} rm -f "{}"
99
+ elif [ "$IMGFMT" = "qcow2" ]; then
100
+ # Remove external data file
101
+ if data_file=$(_get_data_file "$img"); then
102
+ rm -f "$data_file"
103
+ fi
104
fi
105
rm -f "$img"
106
}
105
--
107
--
106
2.13.5
108
2.24.1
107
109
108
110
diff view generated by jsdifflib
New patch
1
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
3
Allow writing all the data compressed through the filter driver.
4
The written data will be aligned by the cluster size.
5
Based on the QEMU current implementation, that data can be written to
6
unallocated clusters only. May be used for a backup job.
7
8
Suggested-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-id: 1575288906-551879-2-git-send-email-andrey.shinkevich@virtuozzo.com
12
[mreitz: Replace NULL bdrv_get_format_name() by "(no format)"]
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/Makefile.objs | 1 +
16
block/filter-compress.c | 168 ++++++++++++++++++++++++++++++++++++++++
17
qapi/block-core.json | 10 ++-
18
3 files changed, 175 insertions(+), 4 deletions(-)
19
create mode 100644 block/filter-compress.c
20
21
diff --git a/block/Makefile.objs b/block/Makefile.objs
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/Makefile.objs
24
+++ b/block/Makefile.objs
25
@@ -XXX,XX +XXX,XX @@ block-obj-y += crypto.o
26
27
block-obj-y += aio_task.o
28
block-obj-y += backup-top.o
29
+block-obj-y += filter-compress.o
30
31
common-obj-y += stream.o
32
33
diff --git a/block/filter-compress.c b/block/filter-compress.c
34
new file mode 100644
35
index XXXXXXX..XXXXXXX
36
--- /dev/null
37
+++ b/block/filter-compress.c
38
@@ -XXX,XX +XXX,XX @@
39
+/*
40
+ * Compress filter block driver
41
+ *
42
+ * Copyright (c) 2019 Virtuozzo International GmbH
43
+ *
44
+ * Author:
45
+ * Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
46
+ * (based on block/copy-on-read.c by Max Reitz)
47
+ *
48
+ * This program is free software; you can redistribute it and/or
49
+ * modify it under the terms of the GNU General Public License as
50
+ * published by the Free Software Foundation; either version 2 or
51
+ * (at your option) any later version of the License.
52
+ *
53
+ * This program is distributed in the hope that it will be useful,
54
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
55
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56
+ * GNU General Public License for more details.
57
+ *
58
+ * You should have received a copy of the GNU General Public License
59
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
60
+ */
61
+
62
+#include "qemu/osdep.h"
63
+#include "block/block_int.h"
64
+#include "qemu/module.h"
65
+#include "qapi/error.h"
66
+
67
+
68
+static int compress_open(BlockDriverState *bs, QDict *options, int flags,
69
+ Error **errp)
70
+{
71
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
72
+ errp);
73
+ if (!bs->file) {
74
+ return -EINVAL;
75
+ }
76
+
77
+ if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
78
+ error_setg(errp,
79
+ "Compression is not supported for underlying format: %s",
80
+ bdrv_get_format_name(bs->file->bs) ?: "(no format)");
81
+
82
+ return -ENOTSUP;
83
+ }
84
+
85
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
86
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
87
+
88
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
89
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
90
+ bs->file->bs->supported_zero_flags);
91
+
92
+ return 0;
93
+}
94
+
95
+
96
+static int64_t compress_getlength(BlockDriverState *bs)
97
+{
98
+ return bdrv_getlength(bs->file->bs);
99
+}
100
+
101
+
102
+static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
103
+ uint64_t offset, uint64_t bytes,
104
+ QEMUIOVector *qiov,
105
+ size_t qiov_offset,
106
+ int flags)
107
+{
108
+ return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
109
+ flags);
110
+}
111
+
112
+
113
+static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
114
+ uint64_t offset,
115
+ uint64_t bytes,
116
+ QEMUIOVector *qiov,
117
+ size_t qiov_offset, int flags)
118
+{
119
+ return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
120
+ flags | BDRV_REQ_WRITE_COMPRESSED);
121
+}
122
+
123
+
124
+static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
125
+ int64_t offset, int bytes,
126
+ BdrvRequestFlags flags)
127
+{
128
+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
129
+}
130
+
131
+
132
+static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
133
+ int64_t offset, int bytes)
134
+{
135
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
136
+}
137
+
138
+
139
+static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
140
+{
141
+ BlockDriverInfo bdi;
142
+ int ret;
143
+
144
+ if (!bs->file) {
145
+ return;
146
+ }
147
+
148
+ ret = bdrv_get_info(bs->file->bs, &bdi);
149
+ if (ret < 0 || bdi.cluster_size == 0) {
150
+ return;
151
+ }
152
+
153
+ bs->bl.request_alignment = bdi.cluster_size;
154
+}
155
+
156
+
157
+static void compress_eject(BlockDriverState *bs, bool eject_flag)
158
+{
159
+ bdrv_eject(bs->file->bs, eject_flag);
160
+}
161
+
162
+
163
+static void compress_lock_medium(BlockDriverState *bs, bool locked)
164
+{
165
+ bdrv_lock_medium(bs->file->bs, locked);
166
+}
167
+
168
+
169
+static bool compress_recurse_is_first_non_filter(BlockDriverState *bs,
170
+ BlockDriverState *candidate)
171
+{
172
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
173
+}
174
+
175
+
176
+static BlockDriver bdrv_compress = {
177
+ .format_name = "compress",
178
+
179
+ .bdrv_open = compress_open,
180
+ .bdrv_child_perm = bdrv_filter_default_perms,
181
+
182
+ .bdrv_getlength = compress_getlength,
183
+
184
+ .bdrv_co_preadv_part = compress_co_preadv_part,
185
+ .bdrv_co_pwritev_part = compress_co_pwritev_part,
186
+ .bdrv_co_pwrite_zeroes = compress_co_pwrite_zeroes,
187
+ .bdrv_co_pdiscard = compress_co_pdiscard,
188
+ .bdrv_refresh_limits = compress_refresh_limits,
189
+
190
+ .bdrv_eject = compress_eject,
191
+ .bdrv_lock_medium = compress_lock_medium,
192
+
193
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
194
+
195
+ .bdrv_recurse_is_first_non_filter = compress_recurse_is_first_non_filter,
196
+
197
+ .has_variable_length = true,
198
+ .is_filter = true,
199
+};
200
+
201
+static void bdrv_compress_init(void)
202
+{
203
+ bdrv_register(&bdrv_compress);
204
+}
205
+
206
+block_init(bdrv_compress_init);
207
diff --git a/qapi/block-core.json b/qapi/block-core.json
208
index XXXXXXX..XXXXXXX 100644
209
--- a/qapi/block-core.json
210
+++ b/qapi/block-core.json
211
@@ -XXX,XX +XXX,XX @@
212
# @copy-on-read: Since 3.0
213
# @blklogwrites: Since 3.0
214
# @blkreplay: Since 4.2
215
+# @compress: Since 5.0
216
#
217
# Since: 2.9
218
##
219
{ 'enum': 'BlockdevDriver',
220
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
221
- 'cloop', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
222
- 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
223
- 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
224
- 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
225
+ 'cloop', 'compress', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps',
226
+ 'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi',
227
+ 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
228
+ 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
229
{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
230
'sheepdog',
231
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
232
@@ -XXX,XX +XXX,XX @@
233
'blkreplay': 'BlockdevOptionsBlkreplay',
234
'bochs': 'BlockdevOptionsGenericFormat',
235
'cloop': 'BlockdevOptionsGenericFormat',
236
+ 'compress': 'BlockdevOptionsGenericFormat',
237
'copy-on-read':'BlockdevOptionsGenericFormat',
238
'dmg': 'BlockdevOptionsGenericFormat',
239
'file': 'BlockdevOptionsFile',
240
--
241
2.24.1
242
243
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
2
3
There's a few cases which we're passing an Error pointer to a function
3
QEMU currently supports writing compressed data of the size equal to
4
only to discard it immediately afterwards without checking it. In
4
one cluster. This patch allows writing QCOW2 compressed data that
5
these cases we can simply remove the variable and pass NULL instead.
5
exceed one cluster. Now, we split buffered data into separate clusters
6
and write them compressed using the block/aio_task API.
6
7
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Suggested-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
10
Message-id: 20170829120836.16091-1-berto@igalia.com
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-id: 1575288906-551879-3-git-send-email-andrey.shinkevich@virtuozzo.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
15
---
13
block/qcow.c | 12 +++---------
16
block/qcow2.c | 102 +++++++++++++++++++++++++++++++++++++-------------
14
block/qcow2.c | 8 ++------
17
1 file changed, 75 insertions(+), 27 deletions(-)
15
dump.c | 4 +---
16
3 files changed, 6 insertions(+), 18 deletions(-)
17
18
18
diff --git a/block/qcow.c b/block/qcow.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow.c
21
+++ b/block/qcow.c
22
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
23
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
24
for(i = 0; i < s->cluster_sectors; i++) {
25
if (i < n_start || i >= n_end) {
26
- Error *err = NULL;
27
memset(s->cluster_data, 0x00, 512);
28
if (qcrypto_block_encrypt(s->crypto, start_sect + i,
29
s->cluster_data,
30
BDRV_SECTOR_SIZE,
31
- &err) < 0) {
32
- error_free(err);
33
+ NULL) < 0) {
34
errno = EIO;
35
return -1;
36
}
37
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
38
QEMUIOVector hd_qiov;
39
uint8_t *buf;
40
void *orig_buf;
41
- Error *err = NULL;
42
43
if (qiov->niov > 1) {
44
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
45
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
46
if (bs->encrypted) {
47
assert(s->crypto);
48
if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
49
- n * BDRV_SECTOR_SIZE, &err) < 0) {
50
+ n * BDRV_SECTOR_SIZE, NULL) < 0) {
51
goto fail;
52
}
53
}
54
@@ -XXX,XX +XXX,XX @@ done:
55
return ret;
56
57
fail:
58
- error_free(err);
59
ret = -EIO;
60
goto done;
61
}
62
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
63
break;
64
}
65
if (bs->encrypted) {
66
- Error *err = NULL;
67
assert(s->crypto);
68
if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
69
- n * BDRV_SECTOR_SIZE, &err) < 0) {
70
- error_free(err);
71
+ n * BDRV_SECTOR_SIZE, NULL) < 0) {
72
ret = -EIO;
73
break;
74
}
75
diff --git a/block/qcow2.c b/block/qcow2.c
19
diff --git a/block/qcow2.c b/block/qcow2.c
76
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
77
--- a/block/qcow2.c
21
--- a/block/qcow2.c
78
+++ b/block/qcow2.c
22
+++ b/block/qcow2.c
79
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
23
@@ -XXX,XX +XXX,XX @@ fail:
80
assert(s->crypto);
24
return ret;
81
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
25
}
82
assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
26
83
- Error *err = NULL;
27
-/* XXX: put compressed sectors first, then all the cluster aligned
84
if (qcrypto_block_decrypt(s->crypto,
28
- tables to avoid losing bytes in alignment */
85
(s->crypt_physical_offset ?
29
static coroutine_fn int
86
cluster_offset + offset_in_cluster :
30
-qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
87
offset) >> BDRV_SECTOR_BITS,
31
+qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
88
cluster_data,
32
uint64_t offset, uint64_t bytes,
89
cur_bytes,
33
QEMUIOVector *qiov, size_t qiov_offset)
90
- &err) < 0) {
91
- error_free(err);
92
+ NULL) < 0) {
93
ret = -EIO;
94
goto fail;
95
}
96
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
97
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
98
99
if (bs->encrypted) {
100
- Error *err = NULL;
101
assert(s->crypto);
102
if (!cluster_data) {
103
cluster_data = qemu_try_blockalign(bs->file->bs,
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
105
cluster_offset + offset_in_cluster :
106
offset) >> BDRV_SECTOR_BITS,
107
cluster_data,
108
- cur_bytes, &err) < 0) {
109
- error_free(err);
110
+ cur_bytes, NULL) < 0) {
111
ret = -EIO;
112
goto fail;
113
}
114
diff --git a/dump.c b/dump.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/dump.c
117
+++ b/dump.c
118
@@ -XXX,XX +XXX,XX @@ static void dump_process(DumpState *s, Error **errp)
119
120
static void *dump_thread(void *data)
121
{
34
{
122
- Error *err = NULL;
35
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
123
DumpState *s = (DumpState *)data;
36
uint8_t *buf, *out_buf;
124
- dump_process(s, &err);
37
uint64_t cluster_offset;
125
- error_free(err);
38
126
+ dump_process(s, NULL);
39
- if (has_data_file(bs)) {
127
return NULL;
40
- return -ENOTSUP;
41
- }
42
-
43
- if (bytes == 0) {
44
- /* align end of file to a sector boundary to ease reading with
45
- sector based I/Os */
46
- int64_t len = bdrv_getlength(bs->file->bs);
47
- if (len < 0) {
48
- return len;
49
- }
50
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
51
- }
52
-
53
- if (offset_into_cluster(s, offset)) {
54
- return -EINVAL;
55
- }
56
+ assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
57
+ (offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
58
59
buf = qemu_blockalign(bs, s->cluster_size);
60
- if (bytes != s->cluster_size) {
61
- if (bytes > s->cluster_size ||
62
- offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
63
- {
64
- qemu_vfree(buf);
65
- return -EINVAL;
66
- }
67
+ if (bytes < s->cluster_size) {
68
/* Zero-pad last write if image size is not cluster aligned */
69
memset(buf + bytes, 0, s->cluster_size - bytes);
70
}
71
@@ -XXX,XX +XXX,XX @@ fail:
72
return ret;
128
}
73
}
129
74
75
+static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
76
+{
77
+ Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
78
+
79
+ assert(!t->cluster_type && !t->l2meta);
80
+
81
+ return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
82
+ t->qiov_offset);
83
+}
84
+
85
+/*
86
+ * XXX: put compressed sectors first, then all the cluster aligned
87
+ * tables to avoid losing bytes in alignment
88
+ */
89
+static coroutine_fn int
90
+qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
91
+ uint64_t offset, uint64_t bytes,
92
+ QEMUIOVector *qiov, size_t qiov_offset)
93
+{
94
+ BDRVQcow2State *s = bs->opaque;
95
+ AioTaskPool *aio = NULL;
96
+ int ret = 0;
97
+
98
+ if (has_data_file(bs)) {
99
+ return -ENOTSUP;
100
+ }
101
+
102
+ if (bytes == 0) {
103
+ /*
104
+ * align end of file to a sector boundary to ease reading with
105
+ * sector based I/Os
106
+ */
107
+ int64_t len = bdrv_getlength(bs->file->bs);
108
+ if (len < 0) {
109
+ return len;
110
+ }
111
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
112
+ }
113
+
114
+ if (offset_into_cluster(s, offset)) {
115
+ return -EINVAL;
116
+ }
117
+
118
+ while (bytes && aio_task_pool_status(aio) == 0) {
119
+ uint64_t chunk_size = MIN(bytes, s->cluster_size);
120
+
121
+ if (!aio && chunk_size != bytes) {
122
+ aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
123
+ }
124
+
125
+ ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
126
+ 0, 0, offset, chunk_size, qiov, qiov_offset, NULL);
127
+ if (ret < 0) {
128
+ break;
129
+ }
130
+ qiov_offset += chunk_size;
131
+ offset += chunk_size;
132
+ bytes -= chunk_size;
133
+ }
134
+
135
+ if (aio) {
136
+ aio_task_pool_wait_all(aio);
137
+ if (ret == 0) {
138
+ ret = aio_task_pool_status(aio);
139
+ }
140
+ g_free(aio);
141
+ }
142
+
143
+ return ret;
144
+}
145
+
146
static int coroutine_fn
147
qcow2_co_preadv_compressed(BlockDriverState *bs,
148
uint64_t file_cluster_offset,
130
--
149
--
131
2.13.5
150
2.24.1
132
151
133
152
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
2
3
The way the throttling algorithm works is that requests start being
3
Add the case to the iotest #214 that checks possibility of writing
4
throttled once the bucket level exceeds the burst limit. When we get
4
compressed data of more than one cluster size. The test case involves
5
there the bucket leaks at the level set by the user (bkt->avg), and
5
the compress filter driver showing a sample usage of that.
6
that leak rate is what prevents guest I/O from exceeding the desired
7
limit.
8
6
9
If we don't allow bursts (i.e. bkt->max == 0) then we can start
7
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
10
throttling requests immediately. The problem with keeping the
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
threshold at 0 is that it only allows one request at a time, and as
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
soon as there's a bit of I/O from the guest every other request will
10
Message-id: 1575288906-551879-4-git-send-email-andrey.shinkevich@virtuozzo.com
13
be throttled and performance will suffer considerably. That can even
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
make the guest unable to reach the throttle limit if that limit is
12
---
15
high enough, and that happens regardless of the block scheduler used
13
tests/qemu-iotests/214 | 43 ++++++++++++++++++++++++++++++++++++++
16
by the guest.
14
tests/qemu-iotests/214.out | 14 +++++++++++++
15
2 files changed, 57 insertions(+)
17
16
18
Increasing that threshold gives flexibility to the guest, allowing it
17
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
19
to perform short bursts of I/O before being throttled. Increasing the
18
index XXXXXXX..XXXXXXX 100755
20
threshold too much does not make a difference in the long run (because
19
--- a/tests/qemu-iotests/214
21
it's the leak rate what defines the actual throughput) but it does
20
+++ b/tests/qemu-iotests/214
22
allow the guest to perform longer initial bursts and exceed the
21
@@ -XXX,XX +XXX,XX @@ _check_test_img -r all
23
throttle limit for a short while.
22
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
24
23
$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
25
A burst value of bkt->avg / 10 allows the guest to perform 100ms'
24
26
worth of I/O at the target rate without being throttled.
25
+echo
27
26
+echo "=== Write compressed data of multiple clusters ==="
28
Signed-off-by: Alberto Garcia <berto@igalia.com>
27
+echo
29
Message-id: 31aae6645f0d1fbf3860fb2b528b757236f0c0a7.1503580370.git.berto@igalia.com
28
+cluster_size=0x10000
30
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29
+_make_test_img 2M -o cluster_size=$cluster_size
31
---
30
+
32
util/throttle.c | 11 +++--------
31
+echo "Write uncompressed data:"
33
1 file changed, 3 insertions(+), 8 deletions(-)
32
+let data_size="8 * $cluster_size"
34
33
+$QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \
35
diff --git a/util/throttle.c b/util/throttle.c
34
+ 2>&1 | _filter_qemu_io | _filter_testdir
35
+sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" |
36
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
37
+
38
+_make_test_img 2M -o cluster_size=$cluster_size
39
+echo "Write compressed data:"
40
+let data_size="3 * $cluster_size + $cluster_size / 2"
41
+# Set compress on. That will align the written data
42
+# by the cluster size and will write them compressed.
43
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
44
+$QEMU_IO -c "write -P 0xbb 0 $data_size" --image-opts \
45
+ "driver=compress,file.driver=$IMGFMT,file.file.driver=file,file.file.filename=$TEST_IMG" \
46
+ 2>&1 | _filter_qemu_io | _filter_testdir
47
+
48
+let offset="4 * $cluster_size + $cluster_size / 4"
49
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
50
+$QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\
51
+ 'driver': 'compress',
52
+ 'file': {'driver': '$IMGFMT',
53
+ 'file': {'driver': 'file',
54
+ 'filename': '$TEST_IMG'}}}" | \
55
+ _filter_qemu_io | _filter_testdir
56
+
57
+sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" |
58
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
59
+
60
+if [ $sizeA -le $sizeB ]
61
+then
62
+ echo "Compression ERROR"
63
+fi
64
+
65
+$QEMU_IMG check --output=json "$TEST_IMG" |
66
+ sed -n 's/,$//; /"compressed-clusters":/ s/^ *//p'
67
+
68
# success, all done
69
echo '*** done'
70
rm -f $seq.full
71
diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out
36
index XXXXXXX..XXXXXXX 100644
72
index XXXXXXX..XXXXXXX 100644
37
--- a/util/throttle.c
73
--- a/tests/qemu-iotests/214.out
38
+++ b/util/throttle.c
74
+++ b/tests/qemu-iotests/214.out
39
@@ -XXX,XX +XXX,XX @@ static void throttle_fix_bucket(LeakyBucket *bkt)
75
@@ -XXX,XX +XXX,XX @@ read 4194304/4194304 bytes at offset 0
40
/* zero bucket level */
76
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
41
bkt->level = bkt->burst_level = 0;
77
read 4194304/4194304 bytes at offset 4194304
42
78
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
43
- /* The following is done to cope with the Linux CFQ block scheduler
79
+
44
- * which regroup reads and writes by block of 100ms in the guest.
80
+=== Write compressed data of multiple clusters ===
45
- * When they are two process one making reads and one making writes cfq
81
+
46
- * make a pattern looking like the following:
82
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
47
- * WWWWWWWWWWWRRRRRRRRRRRRRRWWWWWWWWWWWWWwRRRRRRRRRRRRRRRRR
83
+Write uncompressed data:
48
- * Having a max burst value of 100ms of the average will help smooth the
84
+wrote 524288/524288 bytes at offset 0
49
- * throttling
85
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
50
- */
86
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
51
+ /* If bkt->max is 0 we still want to allow short bursts of I/O
87
+Write compressed data:
52
+ * from the guest, otherwise every other request will be throttled
88
+wrote 229376/229376 bytes at offset 0
53
+ * and performance will suffer considerably. */
89
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
54
min = bkt->avg / 10;
90
+wrote 229376/229376 bytes at offset 278528
55
if (bkt->avg && !bkt->max) {
91
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
56
bkt->max = min;
92
+"compressed-clusters": 8
93
*** done
57
--
94
--
58
2.13.5
95
2.24.1
59
96
60
97
diff view generated by jsdifflib
1
From: Eduardo Habkost <ehabkost@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
If QEMU is running on a system that's out of memory and mmap()
3
Commit 6f6e1698a6 desugarized "-machine accel=" to a list
4
fails, QEMU aborts with no error message at all, making it hard
4
of "-accel" options. Since now "-machine accel" and "-accel"
5
to debug the reason for the failure.
5
became incompatible, update the iotests to the new format.
6
6
7
Add perror() calls that will print error information before
7
Error reported here:
8
aborting.
8
https://gitlab.com/qemu-project/qemu/-/jobs/385801004#L3400
9
9
10
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
10
Reported-by: GitLab CI
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Fixes: 6f6e1698a6 (vl: configure accelerators from -accel options)
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
Message-id: 20170829212053.6003-1-ehabkost@redhat.com
13
Message-id: 20200106130951.29873-1-philmd@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
15
---
16
util/oslib-posix.c | 2 ++
16
tests/qemu-iotests/235 | 2 +-
17
1 file changed, 2 insertions(+)
17
tests/qemu-iotests/check | 6 +++---
18
2 files changed, 4 insertions(+), 4 deletions(-)
18
19
19
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
20
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
20
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100755
21
--- a/util/oslib-posix.c
22
--- a/tests/qemu-iotests/235
22
+++ b/util/oslib-posix.c
23
+++ b/tests/qemu-iotests/235
23
@@ -XXX,XX +XXX,XX @@ void *qemu_alloc_stack(size_t *sz)
24
@@ -XXX,XX +XXX,XX @@ qemu_img_create('-f', iotests.imgfmt, '-o', 'preallocation=metadata', disk,
24
ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE,
25
str(size))
25
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
26
26
if (ptr == MAP_FAILED) {
27
vm = QEMUMachine(iotests.qemu_prog)
27
+ perror("failed to allocate memory for stack");
28
-vm.add_args('-machine', 'accel=kvm:tcg')
28
abort();
29
+vm.add_args('-accel', 'kvm', '-accel', 'tcg')
29
}
30
if iotests.qemu_default_machine == 's390-ccw-virtio':
30
31
vm.add_args('-no-shutdown')
31
@@ -XXX,XX +XXX,XX @@ void *qemu_alloc_stack(size_t *sz)
32
vm.add_args('-drive', 'id=src,file=' + disk)
32
guardpage = ptr;
33
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
33
#endif
34
index XXXXXXX..XXXXXXX 100755
34
if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
35
--- a/tests/qemu-iotests/check
35
+ perror("failed to set up stack guard page");
36
+++ b/tests/qemu-iotests/check
36
abort();
37
@@ -XXX,XX +XXX,XX @@ export QEMU_PROG="$(type -p "$QEMU_PROG")"
37
}
38
39
case "$QEMU_PROG" in
40
*qemu-system-arm|*qemu-system-aarch64)
41
- export QEMU_OPTIONS="-nodefaults -display none -machine virt,accel=qtest"
42
+ export QEMU_OPTIONS="-nodefaults -display none -machine virt -accel qtest"
43
;;
44
*qemu-system-tricore)
45
- export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard,accel=qtest"
46
+ export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard -accel qtest"
47
;;
48
*)
49
- export QEMU_OPTIONS="-nodefaults -display none -machine accel=qtest"
50
+ export QEMU_OPTIONS="-nodefaults -display none -accel qtest"
51
;;
52
esac
38
53
39
--
54
--
40
2.13.5
55
2.24.1
41
56
42
57
diff view generated by jsdifflib
1
From: Dan Aloni <dan@kernelim.com>
1
When dropping backup-top, we need to drain the node before freeing the
2
BlockCopyState. Otherwise, requests may still be in flight and then the
3
assertion in shres_destroy() will fail.
2
4
3
The number of queues that should be return by the admin command should:
5
(This becomes visible in intermittent failure of 056.)
4
6
5
1) Only mention the number of non-admin queues.
7
Cc: qemu-stable@nongnu.org
6
2) It is zero-based, meaning that '0 == one non-admin queue',
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
'1 == two non-admin queues', and so forth.
9
Message-id: 20191219182638.104621-1-mreitz@redhat.com
8
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Because our `num_queues` means the number of queues _plus_ the admin
10
queue, then the right calculation for the number returned from the admin
11
command is `num_queues - 2`, combining the two requirements mentioned.
12
13
The issue was discovered by reducing num_queues from 64 to 8 and running
14
a Linux VM with an SMP parameter larger than that (e.g. 22). It tries to
15
utilize all queues, and therefore fails with an invalid queue number
16
when trying to queue I/Os on the last queue.
17
18
Signed-off-by: Dan Aloni <dan@kernelim.com>
19
CC: Alex Friedman <alex@e8storage.com>
20
CC: Keith Busch <keith.busch@intel.com>
21
CC: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: Keith Busch <keith.busch@intel.com>
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
---
11
---
25
hw/block/nvme.c | 4 ++--
12
block/backup-top.c | 4 ++--
26
1 file changed, 2 insertions(+), 2 deletions(-)
13
1 file changed, 2 insertions(+), 2 deletions(-)
27
14
28
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
15
diff --git a/block/backup-top.c b/block/backup-top.c
29
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/block/nvme.c
17
--- a/block/backup-top.c
31
+++ b/hw/block/nvme.c
18
+++ b/block/backup-top.c
32
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
19
@@ -XXX,XX +XXX,XX @@ void bdrv_backup_top_drop(BlockDriverState *bs)
33
result = blk_enable_write_cache(n->conf.blk);
20
BDRVBackupTopState *s = bs->opaque;
34
break;
21
AioContext *aio_context = bdrv_get_aio_context(bs);
35
case NVME_NUMBER_OF_QUEUES:
22
36
- result = cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
23
- block_copy_state_free(s->bcs);
37
+ result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
24
-
38
break;
25
aio_context_acquire(aio_context);
39
default:
26
40
return NVME_INVALID_FIELD | NVME_DNR;
27
bdrv_drained_begin(bs);
41
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
28
42
break;
29
+ block_copy_state_free(s->bcs);
43
case NVME_NUMBER_OF_QUEUES:
30
+
44
req->cqe.result =
31
s->active = false;
45
- cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
32
bdrv_child_refresh_perms(bs, bs->backing, &error_abort);
46
+ cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
33
bdrv_replace_node(bs, backing_bs(bs), &error_abort);
47
break;
48
default:
49
return NVME_INVALID_FIELD | NVME_DNR;
50
--
34
--
51
2.13.5
35
2.24.1
52
36
53
37
diff view generated by jsdifflib