1
The following changes since commit 411ad78115ebeb3411cf4b7622784b93dfabe259:
1
The following changes since commit 96662996eda78c48aadddd4e76d8615c7eb72d80:
2
2
3
Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2017-12-15-1' into staging (2017-12-17 15:27:41 +0000)
3
Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20210513a' into staging (2021-05-14 12:03:47 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2021-05-14
8
8
9
for you to fetch changes up to 996922de45299878cdc4c15b72b19edf2bc618a4:
9
for you to fetch changes up to c61ebf362d0abf288ce266845519d5a550a1d89f:
10
10
11
block/curl: fix minor memory leaks (2017-12-18 15:44:39 -0500)
11
write-threshold: deal with includes (2021-05-14 16:14:10 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Blockjob and protocol patches
14
Block patches:
15
- drop block/io write notifiers
16
- qemu-iotests enhancements to make debugging easier
17
- rbd parsing fix
18
- HMP qemu-io fix (for iothreads)
19
- mirror job cancel relaxation (do not cancel in-flight requests when a
20
READY mirror job is canceled with force=false)
21
- document qcow2's data_file and data_file_raw features
22
- fix iotest 297 for pylint 2.8
23
- block/copy-on-read refactoring
24
15
----------------------------------------------------------------
25
----------------------------------------------------------------
26
Connor Kuehl (3):
27
iotests/231: Update expected deprecation message
28
block/rbd: Add an escape-aware strchr helper
29
Document qemu-img options data_file and data_file_raw
16
30
17
Jeff Cody (4):
31
Emanuele Giuseppe Esposito (1):
18
block/sheepdog: remove spurious NULL check
32
qemu-iotests: fix pylint 2.8 consider-using-with error
19
block/sheepdog: code beautification
20
block/curl: check error return of curl_global_init()
21
block/curl: fix minor memory leaks
22
33
23
John Snow (1):
34
Paolo Bonzini (5):
24
blockjob: kick jobs on set-speed
35
qemu-iotests: do not buffer the test output
36
qemu-iotests: allow passing unittest.main arguments to the test
37
scripts
38
qemu-iotests: move command line and environment handling from
39
TestRunner to TestEnv
40
qemu-iotests: let "check" spawn an arbitrary test command
41
qemu-iotests: fix case of SOCK_DIR already in the environment
25
42
26
Vladimir Sementsov-Ogievskiy (5):
43
Vladimir Sementsov-Ogievskiy (10):
27
hbitmap: add next_zero function
44
monitor: hmp_qemu_io: acquire aio contex, fix crash
28
backup: move from done_bitmap to copy_bitmap
45
mirror: stop cancelling in-flight requests on non-force cancel in
29
backup: init copy_bitmap from sync_bitmap for incremental
46
READY
30
backup: simplify non-dirty bits progress processing
47
block/copy-on-read: use bdrv_drop_filter() and drop s->active
31
backup: use copy_bitmap in incremental backup
48
block/write-threshold: don't use write notifiers
49
block: drop write notifiers
50
test-write-threshold: rewrite test_threshold_(not_)trigger tests
51
block/write-threshold: drop extra APIs
52
test-write-threshold: drop extra tests
53
test-write-threshold: drop extra TestStruct structure
54
write-threshold: deal with includes
32
55
33
block/backup.c | 116 +++++++++++++++++-------------
56
docs/tools/qemu-img.rst | 31 +++++++
34
block/curl.c | 24 +++++--
57
include/block/block_int.h | 15 +---
35
block/dirty-bitmap.c | 5 ++
58
include/block/write-threshold.h | 27 ++----
36
block/sheepdog.c | 166 +++++++++++++++++++++----------------------
59
include/qemu/job.h | 2 +-
37
blockjob.c | 30 +++++++-
60
block.c | 1 -
38
include/block/dirty-bitmap.h | 1 +
61
block/backup.c | 2 +-
39
include/qemu/hbitmap.h | 8 +++
62
block/copy-on-read.c | 33 +------
40
tests/test-hbitmap.c | 61 ++++++++++++++++
63
block/io.c | 11 +--
41
util/hbitmap.c | 39 ++++++++++
64
block/mirror.c | 6 +-
42
9 files changed, 309 insertions(+), 141 deletions(-)
65
block/monitor/block-hmp-cmds.c | 31 ++++---
66
block/rbd.c | 32 ++++---
67
block/write-threshold.c | 91 ++++---------------
68
job.c | 2 +-
69
qemu-io-cmds.c | 8 +-
70
qemu-io.c | 17 +++-
71
tests/unit/test-write-threshold.c | 90 ++-----------------
72
tests/qemu-iotests/231 | 4 +
73
tests/qemu-iotests/231.out | 7 +-
74
tests/qemu-iotests/240.out | 8 +-
75
tests/qemu-iotests/245.out | 8 +-
76
tests/qemu-iotests/264 | 2 +-
77
tests/qemu-iotests/295.out | 6 +-
78
tests/qemu-iotests/296.out | 8 +-
79
tests/qemu-iotests/check | 19 +++-
80
tests/qemu-iotests/iotests.py | 145 +++++++++++++++++-------------
81
tests/qemu-iotests/pylintrc | 3 +
82
tests/qemu-iotests/testenv.py | 22 ++++-
83
tests/qemu-iotests/testrunner.py | 37 +++-----
84
28 files changed, 289 insertions(+), 379 deletions(-)
43
85
44
--
86
--
45
2.9.5
87
2.31.1
46
88
47
89
diff view generated by jsdifflib
New patch
1
From: Connor Kuehl <ckuehl@redhat.com>
1
2
3
The deprecation message in the expected output has technically been
4
wrong since the wrong version of a patch was applied to it. Because of
5
this, the test fails. Correct the expected output so that it passes.
6
7
Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
10
Message-Id: <20210421212343.85524-2-ckuehl@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/qemu-iotests/231.out | 4 +---
14
1 file changed, 1 insertion(+), 3 deletions(-)
15
16
diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/231.out
19
+++ b/tests/qemu-iotests/231.out
20
@@ -XXX,XX +XXX,XX @@
21
QA output created by 231
22
-qemu-img: RBD options encoded in the filename as keyvalue pairs is deprecated. Future versions may cease to parse these options in the future.
23
+qemu-img: warning: RBD options encoded in the filename as keyvalue pairs is deprecated
24
unable to get monitor info from DNS SRV with service name: ceph-mon
25
-no monitors specified to connect to.
26
qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory
27
unable to get monitor info from DNS SRV with service name: ceph-mon
28
-no monitors specified to connect to.
29
qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory
30
*** done
31
--
32
2.31.1
33
34
diff view generated by jsdifflib
1
If curl_global_init() fails, per the documentation no other curl
1
From: Connor Kuehl <ckuehl@redhat.com>
2
functions may be called, so make sure to check the return value.
3
2
4
Also, some minor changes to the initialization latch variable 'inited':
3
Sometimes the parser needs to further split a token it has collected
4
from the token input stream. Right now, it does a cursory check to see
5
if the relevant characters appear in the token to determine if it should
6
break it down further.
5
7
6
- Make it static in the file, for clarity
8
However, qemu_rbd_next_tok() will escape characters as it removes tokens
7
- Change the name for clarity
9
from the token stream and plain strchr() won't. This can make the
8
- Make it a bool
10
initial strchr() check slightly misleading since it implies
11
qemu_rbd_next_tok() will find the token and split on it, except the
12
reality is that qemu_rbd_next_tok() will pass over it if it is escaped.
9
13
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
14
Use a custom strchr to avoid mixing escaped and unescaped string
11
Reviewed-by: Eric Blake <eblake@redhat.com>
15
operations. Furthermore, this code is identical to how
12
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
16
qemu_rbd_next_tok() seeks its next token, so incorporate this custom
13
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
17
strchr into the body of that function to reduce duplication.
14
Signed-off-by: Jeff Cody <jcody@redhat.com>
18
19
Reported-by: Han Han <hhan@redhat.com>
20
Fixes: https://bugzilla.redhat.com/1873913
21
Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
22
Message-Id: <20210421212343.85524-3-ckuehl@redhat.com>
23
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
25
---
16
block/curl.c | 18 ++++++++++++------
26
block/rbd.c | 32 +++++++++++++++++++++-----------
17
1 file changed, 12 insertions(+), 6 deletions(-)
27
tests/qemu-iotests/231 | 4 ++++
28
tests/qemu-iotests/231.out | 3 +++
29
3 files changed, 28 insertions(+), 11 deletions(-)
18
30
19
diff --git a/block/curl.c b/block/curl.c
31
diff --git a/block/rbd.c b/block/rbd.c
20
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
21
--- a/block/curl.c
33
--- a/block/rbd.c
22
+++ b/block/curl.c
34
+++ b/block/rbd.c
23
@@ -XXX,XX +XXX,XX @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
35
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
24
36
const char *keypairs, const char *secretid,
25
struct BDRVCURLState;
37
Error **errp);
26
38
27
+static bool libcurl_initialized;
39
+static char *qemu_rbd_strchr(char *src, char delim)
40
+{
41
+ char *p;
28
+
42
+
29
typedef struct CURLAIOCB {
43
+ for (p = src; *p; ++p) {
30
Coroutine *co;
44
+ if (*p == delim) {
31
QEMUIOVector *qiov;
45
+ return p;
32
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
33
double d;
34
const char *secretid;
35
const char *protocol_delimiter;
36
+ int ret;
37
38
- static int inited = 0;
39
40
if (flags & BDRV_O_RDWR) {
41
error_setg(errp, "curl block device does not support writes");
42
return -EROFS;
43
}
44
45
+ if (!libcurl_initialized) {
46
+ ret = curl_global_init(CURL_GLOBAL_ALL);
47
+ if (ret) {
48
+ error_setg(errp, "libcurl initialization failed with %d", ret);
49
+ return -EIO;
50
+ }
46
+ }
51
+ libcurl_initialized = true;
47
+ if (*p == '\\' && p[1] != '\0') {
48
+ ++p;
49
+ }
52
+ }
50
+ }
53
+
51
+
54
qemu_mutex_init(&s->mutex);
52
+ return NULL;
55
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
53
+}
56
qemu_opts_absorb_qdict(opts, options, &local_err);
54
+
57
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
55
+
58
}
56
static char *qemu_rbd_next_tok(char *src, char delim, char **p)
57
{
58
char *end;
59
60
*p = NULL;
61
62
- for (end = src; *end; ++end) {
63
- if (*end == delim) {
64
- break;
65
- }
66
- if (*end == '\\' && end[1] != '\0') {
67
- end++;
68
- }
69
- }
70
- if (*end == delim) {
71
+ end = qemu_rbd_strchr(src, delim);
72
+ if (end) {
73
*p = end + 1;
74
*end = '\0';
59
}
75
}
60
76
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
61
- if (!inited) {
77
qemu_rbd_unescape(found_str);
62
- curl_global_init(CURL_GLOBAL_ALL);
78
qdict_put_str(options, "pool", found_str);
63
- inited = 1;
79
64
- }
80
- if (strchr(p, '@')) {
65
-
81
+ if (qemu_rbd_strchr(p, '@')) {
66
DPRINTF("CURL: Opening %s\n", file);
82
image_name = qemu_rbd_next_tok(p, '@', &p);
67
QSIMPLEQ_INIT(&s->free_state_waitq);
83
68
s->aio_context = bdrv_get_aio_context(bs);
84
found_str = qemu_rbd_next_tok(p, ':', &p);
85
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
86
image_name = qemu_rbd_next_tok(p, ':', &p);
87
}
88
/* Check for namespace in the image_name */
89
- if (strchr(image_name, '/')) {
90
+ if (qemu_rbd_strchr(image_name, '/')) {
91
found_str = qemu_rbd_next_tok(image_name, '/', &image_name);
92
qemu_rbd_unescape(found_str);
93
qdict_put_str(options, "namespace", found_str);
94
diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231
95
index XXXXXXX..XXXXXXX 100755
96
--- a/tests/qemu-iotests/231
97
+++ b/tests/qemu-iotests/231
98
@@ -XXX,XX +XXX,XX @@ _filter_conf()
99
$QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf
100
$QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf
101
102
+# Regression test: the qemu-img invocation is expected to fail, but it should
103
+# not seg fault the parser.
104
+$QEMU_IMG create "rbd:rbd/aa\/bb:conf=${BOGUS_CONF}" 1M 2>&1 | _filter_conf
105
+
106
# success, all done
107
echo "*** done"
108
rm -f $seq.full
109
diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out
110
index XXXXXXX..XXXXXXX 100644
111
--- a/tests/qemu-iotests/231.out
112
+++ b/tests/qemu-iotests/231.out
113
@@ -XXX,XX +XXX,XX @@ unable to get monitor info from DNS SRV with service name: ceph-mon
114
qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory
115
unable to get monitor info from DNS SRV with service name: ceph-mon
116
qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory
117
+Formatting 'rbd:rbd/aa\/bb:conf=BOGUS_CONF', fmt=raw size=1048576
118
+unable to get monitor info from DNS SRV with service name: ceph-mon
119
+qemu-img: rbd:rbd/aa\/bb:conf=BOGUS_CONF: error connecting: No such file or directory
120
*** done
69
--
121
--
70
2.9.5
122
2.31.1
71
123
72
124
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Max reported the following bug:
4
5
$ ./qemu-img create -f raw src.img 1G
6
$ ./qemu-img create -f raw dst.img 1G
7
8
$ (echo '
9
{"execute":"qmp_capabilities"}
10
{"execute":"blockdev-mirror",
11
"arguments":{"job-id":"mirror",
12
"device":"source",
13
"target":"target",
14
"sync":"full",
15
"filter-node-name":"mirror-top"}}
16
'; sleep 3; echo '
17
{"execute":"human-monitor-command",
18
"arguments":{"command-line":
19
"qemu-io mirror-top \"write 0 1G\""}}') \
20
| x86_64-softmmu/qemu-system-x86_64 \
21
-qmp stdio \
22
-blockdev file,node-name=source,filename=src.img \
23
-blockdev file,node-name=target,filename=dst.img \
24
-object iothread,id=iothr0 \
25
-device virtio-blk,drive=source,iothread=iothr0
26
27
crashes:
28
29
0 raise () at /usr/lib/libc.so.6
30
1 abort () at /usr/lib/libc.so.6
31
2 error_exit
32
(err=<optimized out>,
33
msg=msg@entry=0x55fbb1634790 <__func__.27> "qemu_mutex_unlock_impl")
34
at ../util/qemu-thread-posix.c:37
35
3 qemu_mutex_unlock_impl
36
(mutex=mutex@entry=0x55fbb25ab6e0,
37
file=file@entry=0x55fbb1636957 "../util/async.c",
38
line=line@entry=650)
39
at ../util/qemu-thread-posix.c:109
40
4 aio_context_release (ctx=ctx@entry=0x55fbb25ab680) at ../util/async.c:650
41
5 bdrv_do_drained_begin
42
(bs=bs@entry=0x55fbb3a87000, recursive=recursive@entry=false,
43
parent=parent@entry=0x0,
44
ignore_bds_parents=ignore_bds_parents@entry=false,
45
poll=poll@entry=true) at ../block/io.c:441
46
6 bdrv_do_drained_begin
47
(poll=true, ignore_bds_parents=false, parent=0x0, recursive=false,
48
bs=0x55fbb3a87000) at ../block/io.c:448
49
7 blk_drain (blk=0x55fbb26c5a00) at ../block/block-backend.c:1718
50
8 blk_unref (blk=0x55fbb26c5a00) at ../block/block-backend.c:498
51
9 blk_unref (blk=0x55fbb26c5a00) at ../block/block-backend.c:491
52
10 hmp_qemu_io (mon=0x7fffaf3fc7d0, qdict=<optimized out>)
53
at ../block/monitor/block-hmp-cmds.c:628
54
55
man pthread_mutex_unlock
56
...
57
EPERM The mutex type is PTHREAD_MUTEX_ERRORCHECK or
58
PTHREAD_MUTEX_RECURSIVE, or the mutex is a robust mutex, and the
59
current thread does not own the mutex.
60
61
So, thread doesn't own the mutex. And we have iothread here.
62
63
Next, note that AIO_WAIT_WHILE() documents that ctx must be acquired
64
exactly once by caller. But where is it acquired in the call stack?
65
Seems nowhere.
66
67
qemuio_command do acquire aio context.. But we need context acquired
68
around blk_unref() as well and actually around blk_insert_bs() too.
69
70
Let's refactor qemuio_command so that it doesn't acquire aio context
71
but callers do that instead. This way we can cleanly acquire aio
72
context in hmp_qemu_io() around all three calls.
73
74
Reported-by: Max Reitz <mreitz@redhat.com>
75
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
76
Message-Id: <20210423134233.51495-1-vsementsov@virtuozzo.com>
77
[mreitz: Fixed comment]
78
Signed-off-by: Max Reitz <mreitz@redhat.com>
79
---
80
block/monitor/block-hmp-cmds.c | 31 +++++++++++++++++++++----------
81
qemu-io-cmds.c | 8 ++++----
82
qemu-io.c | 17 +++++++++++++++--
83
3 files changed, 40 insertions(+), 16 deletions(-)
84
85
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/block/monitor/block-hmp-cmds.c
88
+++ b/block/monitor/block-hmp-cmds.c
89
@@ -XXX,XX +XXX,XX @@ void hmp_eject(Monitor *mon, const QDict *qdict)
90
91
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
92
{
93
- BlockBackend *blk;
94
+ BlockBackend *blk = NULL;
95
+ BlockDriverState *bs = NULL;
96
BlockBackend *local_blk = NULL;
97
+ AioContext *ctx = NULL;
98
bool qdev = qdict_get_try_bool(qdict, "qdev", false);
99
const char *device = qdict_get_str(qdict, "device");
100
const char *command = qdict_get_str(qdict, "command");
101
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
102
} else {
103
blk = blk_by_name(device);
104
if (!blk) {
105
- BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
106
- if (bs) {
107
- blk = local_blk = blk_new(bdrv_get_aio_context(bs),
108
- 0, BLK_PERM_ALL);
109
- ret = blk_insert_bs(blk, bs, &err);
110
- if (ret < 0) {
111
- goto fail;
112
- }
113
- } else {
114
+ bs = bdrv_lookup_bs(NULL, device, &err);
115
+ if (!bs) {
116
goto fail;
117
}
118
}
119
}
120
121
+ ctx = blk ? blk_get_aio_context(blk) : bdrv_get_aio_context(bs);
122
+ aio_context_acquire(ctx);
123
+
124
+ if (bs) {
125
+ blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL);
126
+ ret = blk_insert_bs(blk, bs, &err);
127
+ if (ret < 0) {
128
+ goto fail;
129
+ }
130
+ }
131
+
132
/*
133
* Notably absent: Proper permission management. This is sad, but it seems
134
* almost impossible to achieve without changing the semantics and thereby
135
@@ -XXX,XX +XXX,XX @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
136
137
fail:
138
blk_unref(local_blk);
139
+
140
+ if (ctx) {
141
+ aio_context_release(ctx);
142
+ }
143
+
144
hmp_handle_error(mon, err);
145
}
146
147
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/qemu-io-cmds.c
150
+++ b/qemu-io-cmds.c
151
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t help_cmd = {
152
.oneline = "help for one or all commands",
153
};
154
155
+/*
156
+ * Called with aio context of blk acquired. Or with qemu_get_aio_context()
157
+ * context acquired if blk is NULL.
158
+ */
159
int qemuio_command(BlockBackend *blk, const char *cmd)
160
{
161
- AioContext *ctx;
162
char *input;
163
const cmdinfo_t *ct;
164
char **v;
165
@@ -XXX,XX +XXX,XX @@ int qemuio_command(BlockBackend *blk, const char *cmd)
166
if (c) {
167
ct = find_command(v[0]);
168
if (ct) {
169
- ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context();
170
- aio_context_acquire(ctx);
171
ret = command(blk, ct, c, v);
172
- aio_context_release(ctx);
173
} else {
174
fprintf(stderr, "command \"%s\" not found\n", v[0]);
175
ret = -EINVAL;
176
diff --git a/qemu-io.c b/qemu-io.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/qemu-io.c
179
+++ b/qemu-io.c
180
@@ -XXX,XX +XXX,XX @@ static void prep_fetchline(void *opaque)
181
*fetchable= 1;
182
}
183
184
+static int do_qemuio_command(const char *cmd)
185
+{
186
+ int ret;
187
+ AioContext *ctx =
188
+ qemuio_blk ? blk_get_aio_context(qemuio_blk) : qemu_get_aio_context();
189
+
190
+ aio_context_acquire(ctx);
191
+ ret = qemuio_command(qemuio_blk, cmd);
192
+ aio_context_release(ctx);
193
+
194
+ return ret;
195
+}
196
+
197
static int command_loop(void)
198
{
199
int i, fetchable = 0, prompted = 0;
200
@@ -XXX,XX +XXX,XX @@ static int command_loop(void)
201
char *input;
202
203
for (i = 0; !quit_qemu_io && i < ncmdline; i++) {
204
- ret = qemuio_command(qemuio_blk, cmdline[i]);
205
+ ret = do_qemuio_command(cmdline[i]);
206
if (ret < 0) {
207
last_error = ret;
208
}
209
@@ -XXX,XX +XXX,XX @@ static int command_loop(void)
210
if (input == NULL) {
211
break;
212
}
213
- ret = qemuio_command(qemuio_blk, input);
214
+ ret = do_qemuio_command(input);
215
g_free(input);
216
217
if (ret < 0) {
218
--
219
2.31.1
220
221
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We should not copy non-dirty clusters in write notifiers. So,
3
If mirror is READY than cancel operation is not discarding the whole
4
initialize copy_bitmap from sync_bitmap.
4
result of the operation, but instead it's a documented way get a
5
point-in-time snapshot of source disk.
5
6
7
So, we should not cancel any requests if mirror is READ and
8
force=false. Let's fix that case.
9
10
Note, that bug that we have before this commit is not critical, as the
11
only .bdrv_cancel_in_flight implementation is nbd_cancel_in_flight()
12
and it cancels only requests waiting for reconnection, so it should be
13
rare case.
14
15
Fixes: 521ff8b779b11c394dbdc43f02e158dd99df308a
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
17
Message-Id: <20210421075858.40197-1-vsementsov@virtuozzo.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: 20171012135313.227864-4-vsementsov@virtuozzo.com
11
Signed-off-by: Jeff Cody <jcody@redhat.com>
12
---
19
---
13
block/backup.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
20
include/block/block_int.h | 2 +-
14
1 file changed, 43 insertions(+), 1 deletion(-)
21
include/qemu/job.h | 2 +-
22
block/backup.c | 2 +-
23
block/mirror.c | 6 ++++--
24
job.c | 2 +-
25
tests/qemu-iotests/264 | 2 +-
26
6 files changed, 9 insertions(+), 7 deletions(-)
15
27
28
diff --git a/include/block/block_int.h b/include/block/block_int.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block_int.h
31
+++ b/include/block/block_int.h
32
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
33
* of in-flight requests, so don't waste the time if possible.
34
*
35
* One example usage is to avoid waiting for an nbd target node reconnect
36
- * timeout during job-cancel.
37
+ * timeout during job-cancel with force=true.
38
*/
39
void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
40
41
diff --git a/include/qemu/job.h b/include/qemu/job.h
42
index XXXXXXX..XXXXXXX 100644
43
--- a/include/qemu/job.h
44
+++ b/include/qemu/job.h
45
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
46
/**
47
* If the callback is not NULL, it will be invoked in job_cancel_async
48
*/
49
- void (*cancel)(Job *job);
50
+ void (*cancel)(Job *job, bool force);
51
52
53
/** Called when the job is freed */
16
diff --git a/block/backup.c b/block/backup.c
54
diff --git a/block/backup.c b/block/backup.c
17
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
18
--- a/block/backup.c
56
--- a/block/backup.c
19
+++ b/block/backup.c
57
+++ b/block/backup.c
20
@@ -XXX,XX +XXX,XX @@ out:
58
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
21
return ret;
59
}
22
}
60
}
23
61
24
+/* init copy_bitmap from sync_bitmap */
62
-static void backup_cancel(Job *job)
25
+static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
63
+static void backup_cancel(Job *job, bool force)
26
+{
64
{
27
+ BdrvDirtyBitmapIter *dbi;
65
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
28
+ int64_t offset;
66
29
+ int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap),
67
diff --git a/block/mirror.c b/block/mirror.c
30
+ job->cluster_size);
68
index XXXXXXX..XXXXXXX 100644
31
+
69
--- a/block/mirror.c
32
+ dbi = bdrv_dirty_iter_new(job->sync_bitmap);
70
+++ b/block/mirror.c
33
+ while ((offset = bdrv_dirty_iter_next(dbi)) != -1) {
71
@@ -XXX,XX +XXX,XX @@ static bool mirror_drained_poll(BlockJob *job)
34
+ int64_t cluster = offset / job->cluster_size;
72
return !!s->in_flight;
35
+ int64_t next_cluster;
73
}
36
+
74
37
+ offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap);
75
-static void mirror_cancel(Job *job)
38
+ if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) {
76
+static void mirror_cancel(Job *job, bool force)
39
+ hbitmap_set(job->copy_bitmap, cluster, end - cluster);
77
{
40
+ break;
78
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
41
+ }
79
BlockDriverState *target = blk_bs(s->target);
42
+
80
43
+ offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset);
81
- bdrv_cancel_in_flight(target);
44
+ if (offset == -1) {
82
+ if (force || !job_is_ready(job)) {
45
+ hbitmap_set(job->copy_bitmap, cluster, end - cluster);
83
+ bdrv_cancel_in_flight(target);
46
+ break;
47
+ }
48
+
49
+ next_cluster = DIV_ROUND_UP(offset, job->cluster_size);
50
+ hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster);
51
+ if (next_cluster >= end) {
52
+ break;
53
+ }
54
+
55
+ bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
56
+ }
84
+ }
57
+
85
}
58
+ bdrv_dirty_iter_free(dbi);
86
59
+}
87
static const BlockJobDriver mirror_job_driver = {
60
+
88
diff --git a/job.c b/job.c
61
static void coroutine_fn backup_run(void *opaque)
89
index XXXXXXX..XXXXXXX 100644
90
--- a/job.c
91
+++ b/job.c
92
@@ -XXX,XX +XXX,XX @@ static int job_finalize_single(Job *job)
93
static void job_cancel_async(Job *job, bool force)
62
{
94
{
63
BackupBlockJob *job = opaque;
95
if (job->driver->cancel) {
64
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
96
- job->driver->cancel(job);
65
97
+ job->driver->cancel(job, force);
66
nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size);
98
}
67
job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
99
if (job->user_paused) {
68
- hbitmap_set(job->copy_bitmap, 0, nb_clusters);
100
/* Do not call job_enter here, the caller will handle it. */
69
+ if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
101
diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264
70
+ backup_incremental_init_copy_bitmap(job);
102
index XXXXXXX..XXXXXXX 100755
71
+ } else {
103
--- a/tests/qemu-iotests/264
72
+ hbitmap_set(job->copy_bitmap, 0, nb_clusters);
104
+++ b/tests/qemu-iotests/264
73
+ }
105
@@ -XXX,XX +XXX,XX @@ class TestNbdReconnect(iotests.QMPTestCase):
74
+
106
self.assert_qmp(result, 'return', {})
75
107
76
job->before_write.notify = backup_before_write_notify;
108
def cancel_job(self):
77
bdrv_add_before_write_notifier(bs, &job->before_write);
109
- result = self.vm.qmp('block-job-cancel', device='drive0')
110
+ result = self.vm.qmp('block-job-cancel', device='drive0', force=True)
111
self.assert_qmp(result, 'return', {})
112
113
start_t = time.time()
78
--
114
--
79
2.9.5
115
2.31.1
80
116
81
117
diff view generated by jsdifflib
New patch
1
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
3
Instead of buffering the test output into a StringIO, patch it on
4
the fly by wrapping sys.stdout's write method. This can be
5
done unconditionally, even if using -d, which makes execute_unittest
6
a bit simpler.
7
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20210323181928.311862-2-pbonzini@redhat.com>
12
Message-Id: <20210503110110.476887-2-pbonzini@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
tests/qemu-iotests/240.out | 8 ++--
16
tests/qemu-iotests/245.out | 8 ++--
17
tests/qemu-iotests/295.out | 6 +--
18
tests/qemu-iotests/296.out | 8 ++--
19
tests/qemu-iotests/iotests.py | 70 ++++++++++++++++++++---------------
20
5 files changed, 56 insertions(+), 44 deletions(-)
21
22
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
23
index XXXXXXX..XXXXXXX 100644
24
--- a/tests/qemu-iotests/240.out
25
+++ b/tests/qemu-iotests/240.out
26
@@ -XXX,XX +XXX,XX @@
27
{"return": {}}
28
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
29
{"return": {}}
30
-==Attach two SCSI disks using the same block device and the same iothread==
31
+.==Attach two SCSI disks using the same block device and the same iothread==
32
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
33
{"return": {}}
34
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
35
@@ -XXX,XX +XXX,XX @@
36
{"return": {}}
37
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
38
{"return": {}}
39
-==Attach two SCSI disks using the same block device but different iothreads==
40
+.==Attach two SCSI disks using the same block device but different iothreads==
41
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
42
{"return": {}}
43
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
44
@@ -XXX,XX +XXX,XX @@
45
{"return": {}}
46
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
47
{"return": {}}
48
-==Attach a SCSI disks using the same block device as a NBD server==
49
+.==Attach a SCSI disks using the same block device as a NBD server==
50
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
51
{"return": {}}
52
{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
53
@@ -XXX,XX +XXX,XX @@
54
{"return": {}}
55
{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
56
{"return": {}}
57
-....
58
+.
59
----------------------------------------------------------------------
60
Ran 4 tests
61
62
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/245.out
65
+++ b/tests/qemu-iotests/245.out
66
@@ -XXX,XX +XXX,XX @@
67
-{"execute": "job-finalize", "arguments": {"id": "commit0"}}
68
+..{"execute": "job-finalize", "arguments": {"id": "commit0"}}
69
{"return": {}}
70
{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
71
{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
72
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
73
+...{"execute": "job-finalize", "arguments": {"id": "stream0"}}
74
{"return": {}}
75
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
76
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
77
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
78
+.{"execute": "job-finalize", "arguments": {"id": "stream0"}}
79
{"return": {}}
80
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
81
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
82
-.....................
83
+...............
84
----------------------------------------------------------------------
85
Ran 21 tests
86
87
diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out
88
index XXXXXXX..XXXXXXX 100644
89
--- a/tests/qemu-iotests/295.out
90
+++ b/tests/qemu-iotests/295.out
91
@@ -XXX,XX +XXX,XX @@
92
{"return": {}}
93
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
94
{"return": {}}
95
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
96
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
97
{"return": {}}
98
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
99
{"return": {}}
100
@@ -XXX,XX +XXX,XX @@ Job failed: Invalid password, cannot unlock any keyslot
101
{"return": {}}
102
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
103
{"return": {}}
104
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
105
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
106
{"return": {}}
107
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
108
{"return": {}}
109
@@ -XXX,XX +XXX,XX @@ Job failed: All the active keyslots match the (old) password that was given and
110
{"return": {}}
111
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
112
{"return": {}}
113
-...
114
+.
115
----------------------------------------------------------------------
116
Ran 3 tests
117
118
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
119
index XXXXXXX..XXXXXXX 100644
120
--- a/tests/qemu-iotests/296.out
121
+++ b/tests/qemu-iotests/296.out
122
@@ -XXX,XX +XXX,XX @@ Job failed: Failed to get shared "consistent read" lock
123
qemu-img: Failed to get shared "consistent read" lock
124
Is another process using the image [TEST_DIR/test.img]?
125
126
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
127
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
128
129
Job failed: Block node is read-only
130
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
131
@@ -XXX,XX +XXX,XX @@ Job failed: Failed to get shared "consistent read" lock
132
{"return": {}}
133
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
134
{"return": {}}
135
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
136
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
137
138
{"return": {}}
139
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
140
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
141
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
142
143
{"return": {}}
144
{"return": {}}
145
-....
146
+.
147
----------------------------------------------------------------------
148
Ran 4 tests
149
150
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
151
index XXXXXXX..XXXXXXX 100644
152
--- a/tests/qemu-iotests/iotests.py
153
+++ b/tests/qemu-iotests/iotests.py
154
@@ -XXX,XX +XXX,XX @@
155
import bz2
156
from collections import OrderedDict
157
import faulthandler
158
-import io
159
import json
160
import logging
161
import os
162
@@ -XXX,XX +XXX,XX @@
163
import sys
164
import time
165
from typing import (Any, Callable, Dict, Iterable,
166
- List, Optional, Sequence, Tuple, TypeVar)
167
+ List, Optional, Sequence, TextIO, Tuple, Type, TypeVar)
168
import unittest
169
170
from contextlib import contextmanager
171
@@ -XXX,XX +XXX,XX @@ def func_wrapper(*args, **kwargs):
172
return func(*args, **kwargs)
173
return func_wrapper
174
175
+# We need to filter out the time taken from the output so that
176
+# qemu-iotest can reliably diff the results against master output,
177
+# and hide skipped tests from the reference output.
178
+
179
+class ReproducibleTestResult(unittest.TextTestResult):
180
+ def addSkip(self, test, reason):
181
+ # Same as TextTestResult, but print dot instead of "s"
182
+ unittest.TestResult.addSkip(self, test, reason)
183
+ if self.showAll:
184
+ self.stream.writeln("skipped {0!r}".format(reason))
185
+ elif self.dots:
186
+ self.stream.write(".")
187
+ self.stream.flush()
188
+
189
+class ReproducibleStreamWrapper:
190
+ def __init__(self, stream: TextIO):
191
+ self.stream = stream
192
+
193
+ def __getattr__(self, attr):
194
+ if attr in ('stream', '__getstate__'):
195
+ raise AttributeError(attr)
196
+ return getattr(self.stream, attr)
197
+
198
+ def write(self, arg=None):
199
+ arg = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', arg)
200
+ arg = re.sub(r' \(skipped=\d+\)', r'', arg)
201
+ self.stream.write(arg)
202
+
203
+class ReproducibleTestRunner(unittest.TextTestRunner):
204
+ def __init__(self, stream: Optional[TextIO] = None,
205
+ resultclass: Type[unittest.TestResult] = ReproducibleTestResult,
206
+ **kwargs: Any) -> None:
207
+ rstream = ReproducibleStreamWrapper(stream or sys.stdout)
208
+ super().__init__(stream=rstream, # type: ignore
209
+ descriptions=True,
210
+ resultclass=resultclass,
211
+ **kwargs)
212
+
213
def execute_unittest(debug=False):
214
"""Executes unittests within the calling module."""
215
216
verbosity = 2 if debug else 1
217
-
218
- if debug:
219
- output = sys.stdout
220
- else:
221
- # We need to filter out the time taken from the output so that
222
- # qemu-iotest can reliably diff the results against master output.
223
- output = io.StringIO()
224
-
225
- runner = unittest.TextTestRunner(stream=output, descriptions=True,
226
- verbosity=verbosity)
227
- try:
228
- # unittest.main() will use sys.exit(); so expect a SystemExit
229
- # exception
230
- unittest.main(testRunner=runner)
231
- finally:
232
- # We need to filter out the time taken from the output so that
233
- # qemu-iotest can reliably diff the results against master output.
234
- if not debug:
235
- out = output.getvalue()
236
- out = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', out)
237
-
238
- # Hide skipped tests from the reference output
239
- out = re.sub(r'OK \(skipped=\d+\)', 'OK', out)
240
- out_first_line, out_rest = out.split('\n', 1)
241
- out = out_first_line.replace('s', '.') + '\n' + out_rest
242
-
243
- sys.stderr.write(out)
244
+ runner = ReproducibleTestRunner(verbosity=verbosity)
245
+ unittest.main(testRunner=runner)
246
247
def execute_setup_common(supported_fmts: Sequence[str] = (),
248
supported_platforms: Sequence[str] = (),
249
--
250
2.31.1
251
252
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
Python test scripts that use unittest consist of multiple tests.
4
unittest.main allows selecting which tests to run, but currently this
5
is not possible because the iotests wrapper ignores sys.argv.
6
7
unittest.main command line options also allow the user to pick the
8
desired options for verbosity, failfast mode, etc. While "-d" is
9
currently translated to "-v", it also enables extra debug output,
10
and other options are not available at all.
11
12
These command line options only work if the unittest.main testRunner
13
argument is a type, rather than a TestRunner instance. Therefore, pass
14
the class name and "verbosity" argument to unittest.main, and adjust for
15
the different default warnings between TextTestRunner and unittest.main.
16
17
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
18
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
19
Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
20
Message-Id: <20210323181928.311862-3-pbonzini@redhat.com>
21
Message-Id: <20210503110110.476887-3-pbonzini@redhat.com>
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
tests/qemu-iotests/iotests.py | 14 +++++++++-----
25
1 file changed, 9 insertions(+), 5 deletions(-)
26
27
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
28
index XXXXXXX..XXXXXXX 100644
29
--- a/tests/qemu-iotests/iotests.py
30
+++ b/tests/qemu-iotests/iotests.py
31
@@ -XXX,XX +XXX,XX @@ def __init__(self, stream: Optional[TextIO] = None,
32
resultclass=resultclass,
33
**kwargs)
34
35
-def execute_unittest(debug=False):
36
+def execute_unittest(argv: List[str], debug: bool = False) -> None:
37
"""Executes unittests within the calling module."""
38
39
- verbosity = 2 if debug else 1
40
- runner = ReproducibleTestRunner(verbosity=verbosity)
41
- unittest.main(testRunner=runner)
42
+ # Some tests have warnings, especially ResourceWarnings for unclosed
43
+ # files and sockets. Ignore them for now to ensure reproducibility of
44
+ # the test output.
45
+ unittest.main(argv=argv,
46
+ testRunner=ReproducibleTestRunner,
47
+ verbosity=2 if debug else 1,
48
+ warnings=None if sys.warnoptions else 'ignore')
49
50
def execute_setup_common(supported_fmts: Sequence[str] = (),
51
supported_platforms: Sequence[str] = (),
52
@@ -XXX,XX +XXX,XX @@ def execute_test(*args, test_function=None, **kwargs):
53
54
debug = execute_setup_common(*args, **kwargs)
55
if not test_function:
56
- execute_unittest(debug)
57
+ execute_unittest(sys.argv, debug)
58
else:
59
test_function()
60
61
--
62
2.31.1
63
64
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
In the next patch, "check" will learn how to execute a test script without
4
going through TestRunner. To enable this, keep only the text output
5
and subprocess handling in the TestRunner; move into TestEnv the logic
6
to prepare for running a subprocess.
7
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20210323181928.311862-4-pbonzini@redhat.com>
12
Message-Id: <20210503110110.476887-4-pbonzini@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
tests/qemu-iotests/testenv.py | 17 ++++++++++++++++-
16
tests/qemu-iotests/testrunner.py | 14 +-------------
17
2 files changed, 17 insertions(+), 14 deletions(-)
18
19
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/testenv.py
22
+++ b/tests/qemu-iotests/testenv.py
23
@@ -XXX,XX +XXX,XX @@
24
import random
25
import subprocess
26
import glob
27
-from typing import Dict, Any, Optional, ContextManager
28
+from typing import List, Dict, Any, Optional, ContextManager
29
30
31
def isxfile(path: str) -> bool:
32
@@ -XXX,XX +XXX,XX @@ class TestEnv(ContextManager['TestEnv']):
33
'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX',
34
'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_']
35
36
+ def prepare_subprocess(self, args: List[str]) -> Dict[str, str]:
37
+ if self.debug:
38
+ args.append('-d')
39
+
40
+ with open(args[0], encoding="utf-8") as f:
41
+ try:
42
+ if f.readline().rstrip() == '#!/usr/bin/env python3':
43
+ args.insert(0, self.python)
44
+ except UnicodeDecodeError: # binary test? for future.
45
+ pass
46
+
47
+ os_env = os.environ.copy()
48
+ os_env.update(self.get_env())
49
+ return os_env
50
+
51
def get_env(self) -> Dict[str, str]:
52
env = {}
53
for v in self.env_variables:
54
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
55
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/testrunner.py
57
+++ b/tests/qemu-iotests/testrunner.py
58
@@ -XXX,XX +XXX,XX @@ class TestRunner(ContextManager['TestRunner']):
59
def __init__(self, env: TestEnv, makecheck: bool = False,
60
color: str = 'auto') -> None:
61
self.env = env
62
- self.test_run_env = self.env.get_env()
63
self.makecheck = makecheck
64
self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env)
65
66
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
67
silent_unlink(p)
68
69
args = [str(f_test.resolve())]
70
- if self.env.debug:
71
- args.append('-d')
72
-
73
- with f_test.open(encoding="utf-8") as f:
74
- try:
75
- if f.readline().rstrip() == '#!/usr/bin/env python3':
76
- args.insert(0, self.env.python)
77
- except UnicodeDecodeError: # binary test? for future.
78
- pass
79
-
80
- env = os.environ.copy()
81
- env.update(self.test_run_env)
82
+ env = self.env.prepare_subprocess(args)
83
84
t0 = time.time()
85
with f_bad.open('w', encoding="utf-8") as f:
86
--
87
2.31.1
88
89
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
Right now there is no easy way for "check" to print a reproducer command.
4
Because such a reproducer command line would be huge, we can instead teach
5
check to start a command of our choice. This can be for example a Python
6
unit test with arguments to only run a specific subtest.
7
8
Move the trailing empty line to print_env(), since it always looks better
9
and one caller was not adding it.
10
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
14
Message-Id: <20210323181928.311862-5-pbonzini@redhat.com>
15
Message-Id: <20210503110110.476887-5-pbonzini@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
tests/qemu-iotests/check | 19 ++++++++++++++++++-
19
tests/qemu-iotests/testenv.py | 3 ++-
20
tests/qemu-iotests/testrunner.py | 1 -
21
3 files changed, 20 insertions(+), 3 deletions(-)
22
23
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
24
index XXXXXXX..XXXXXXX 100755
25
--- a/tests/qemu-iotests/check
26
+++ b/tests/qemu-iotests/check
27
@@ -XXX,XX +XXX,XX @@
28
import os
29
import sys
30
import argparse
31
+import shutil
32
+from pathlib import Path
33
+
34
from findtests import TestFinder
35
from testenv import TestEnv
36
from testrunner import TestRunner
37
@@ -XXX,XX +XXX,XX @@ def make_argparser() -> argparse.ArgumentParser:
38
'rerun failed ./check command, starting from the '
39
'middle of the process.')
40
g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*',
41
- help='tests to run')
42
+ help='tests to run, or "--" followed by a command')
43
44
return p
45
46
@@ -XXX,XX +XXX,XX @@ if __name__ == '__main__':
47
imgopts=args.imgopts, misalign=args.misalign,
48
debug=args.debug, valgrind=args.valgrind)
49
50
+ if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--':
51
+ if not args.tests:
52
+ sys.exit("missing command after '--'")
53
+ cmd = args.tests
54
+ env.print_env()
55
+ exec_pathstr = shutil.which(cmd[0])
56
+ if exec_pathstr is None:
57
+ sys.exit('command not found: ' + cmd[0])
58
+ exec_path = Path(exec_pathstr).resolve()
59
+ cmd[0] = str(exec_path)
60
+ full_env = env.prepare_subprocess(cmd)
61
+ os.chdir(exec_path.parent)
62
+ os.execve(cmd[0], cmd, full_env)
63
+
64
testfinder = TestFinder(test_dir=env.source_iotests)
65
66
groups = args.groups.split(',') if args.groups else None
67
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/testenv.py
70
+++ b/tests/qemu-iotests/testenv.py
71
@@ -XXX,XX +XXX,XX @@ def print_env(self) -> None:
72
PLATFORM -- {platform}
73
TEST_DIR -- {TEST_DIR}
74
SOCK_DIR -- {SOCK_DIR}
75
-SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}"""
76
+SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}
77
+"""
78
79
args = collections.defaultdict(str, self.get_env())
80
81
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
82
index XXXXXXX..XXXXXXX 100644
83
--- a/tests/qemu-iotests/testrunner.py
84
+++ b/tests/qemu-iotests/testrunner.py
85
@@ -XXX,XX +XXX,XX @@ def run_tests(self, tests: List[str]) -> bool:
86
87
if not self.makecheck:
88
self.env.print_env()
89
- print()
90
91
test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
92
93
--
94
2.31.1
95
96
diff view generated by jsdifflib
1
'tag' is already checked in the lines immediately preceding this check,
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
and set to non-NULL if NULL. No need to check again, it hasn't changed.
3
2
4
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
Due to a typo, in this case the SOCK_DIR was not being created.
5
Reviewed-by: Eric Blake <eblake@redhat.com>
4
6
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Message-Id: <20210323181928.311862-6-pbonzini@redhat.com>
9
Message-Id: <20210503110110.476887-6-pbonzini@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
11
---
9
block/sheepdog.c | 2 +-
12
tests/qemu-iotests/testenv.py | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 1 insertion(+), 1 deletion(-)
11
14
12
diff --git a/block/sheepdog.c b/block/sheepdog.c
15
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/block/sheepdog.c
17
--- a/tests/qemu-iotests/testenv.py
15
+++ b/block/sheepdog.c
18
+++ b/tests/qemu-iotests/testenv.py
16
@@ -XXX,XX +XXX,XX @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
19
@@ -XXX,XX +XXX,XX @@ def init_directories(self) -> None:
17
if (!tag) {
20
try:
18
tag = "";
21
self.sock_dir = os.environ['SOCK_DIR']
19
}
22
self.tmp_sock_dir = False
20
- if (tag && strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
23
- Path(self.test_dir).mkdir(parents=True, exist_ok=True)
21
+ if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
24
+ Path(self.sock_dir).mkdir(parents=True, exist_ok=True)
22
error_setg(errp, "value of parameter 'tag' is too long");
25
except KeyError:
23
ret = -EINVAL;
26
self.sock_dir = tempfile.mkdtemp()
24
goto err_no_fd;
27
self.tmp_sock_dir = True
25
--
28
--
26
2.9.5
29
2.31.1
27
30
28
31
diff view generated by jsdifflib
New patch
1
From: Connor Kuehl <ckuehl@redhat.com>
1
2
3
The contents of this patch were initially developed and posted by Han
4
Han[1], however, it appears the original patch was not applied. Since
5
then, the relevant documentation has been moved and adapted to a new
6
format.
7
8
I've taken most of the original wording and tweaked it according to
9
some of the feedback from the original patch submission. I've also
10
adapted it to restructured text, which is the format the documentation
11
currently uses.
12
13
[1] https://lists.nongnu.org/archive/html/qemu-block/2019-10/msg01253.html
14
15
Fixes: https://bugzilla.redhat.com/1763105
16
Signed-off-by: Han Han <hhan@redhat.com>
17
Suggested-by: Max Reitz <mreitz@redhat.com>
18
[ Max: provided description of data_file_raw behavior ]
19
Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
20
Message-Id: <20210505195512.391128-1-ckuehl@redhat.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
---
23
docs/tools/qemu-img.rst | 31 +++++++++++++++++++++++++++++++
24
1 file changed, 31 insertions(+)
25
26
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
27
index XXXXXXX..XXXXXXX 100644
28
--- a/docs/tools/qemu-img.rst
29
+++ b/docs/tools/qemu-img.rst
30
@@ -XXX,XX +XXX,XX @@ Supported image file formats:
31
issue ``lsattr filename`` to check if the NOCOW flag is set or not
32
(Capital 'C' is NOCOW flag).
33
34
+ ``data_file``
35
+ Filename where all guest data will be stored. If this option is used,
36
+ the qcow2 file will only contain the image's metadata.
37
+
38
+ Note: Data loss will occur if the given filename already exists when
39
+ using this option with ``qemu-img create`` since ``qemu-img`` will create
40
+ the data file anew, overwriting the file's original contents. To simply
41
+ update the reference to point to the given pre-existing file, use
42
+ ``qemu-img amend``.
43
+
44
+ ``data_file_raw``
45
+ If this option is set to ``on``, QEMU will always keep the external data
46
+ file consistent as a standalone read-only raw image.
47
+
48
+ It does this by forwarding all write accesses to the qcow2 file through to
49
+ the raw data file, including their offsets. Therefore, data that is visible
50
+ on the qcow2 node (i.e., to the guest) at some offset is visible at the same
51
+ offset in the raw data file. This results in a read-only raw image. Writes
52
+ that bypass the qcow2 metadata may corrupt the qcow2 metadata because the
53
+ out-of-band writes may result in the metadata falling out of sync with the
54
+ raw image.
55
+
56
+ If this option is ``off``, QEMU will use the data file to store data in an
57
+ arbitrary manner. The file’s content will not make sense without the
58
+ accompanying qcow2 metadata. Where data is written will have no relation to
59
+ its offset as seen by the guest, and some writes (specifically zero writes)
60
+ may not be forwarded to the data file at all, but will only be handled by
61
+ modifying qcow2 metadata.
62
+
63
+ This option can only be enabled if ``data_file`` is set.
64
+
65
``Other``
66
67
QEMU also supports various other image file formats for
68
--
69
2.31.1
70
71
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Set fake progress for non-dirty clusters in copy_bitmap initialization,
3
Now, after huge update of block graph permission update algorithm, we
4
to. It simplifies code and allows further refactoring.
4
don't need this workaround with active state of the filter. Drop it and
5
5
use new smart bdrv_drop_filter() function.
6
This patch changes user's view of backup progress, but formally it
7
doesn't changed: progress hops are just moved to the beginning.
8
9
Actually it's just a point of view: when do we actually skip clusters?
10
We can say in the very beginning, that we skip these clusters and do
11
not think about them later.
12
13
Of course, if go through disk sequentially, it's logical to say, that
14
we skip clusters between copied portions to the left and to the right
15
of them. But even now copying progress is not sequential because of
16
write notifiers. Future patches will introduce new backup architecture
17
which will do copying in several coroutines in parallel, so it will
18
make no sense to publish fake progress by parts in parallel with
19
other copying requests.
20
6
21
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
22
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-Id: <20210506194143.394141-1-vsementsov@virtuozzo.com>
23
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
Reviewed-by: Jeff Cody <jcody@redhat.com>
25
Message-id: 20171012135313.227864-5-vsementsov@virtuozzo.com
26
Signed-off-by: Jeff Cody <jcody@redhat.com>
27
---
10
---
28
block/backup.c | 18 +++---------------
11
block/copy-on-read.c | 33 +--------------------------------
29
1 file changed, 3 insertions(+), 15 deletions(-)
12
1 file changed, 1 insertion(+), 32 deletions(-)
30
13
31
diff --git a/block/backup.c b/block/backup.c
14
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
32
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
33
--- a/block/backup.c
16
--- a/block/copy-on-read.c
34
+++ b/block/backup.c
17
+++ b/block/copy-on-read.c
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
18
@@ -XXX,XX +XXX,XX @@
36
int64_t offset;
19
37
int64_t cluster;
20
38
int64_t end;
21
typedef struct BDRVStateCOR {
39
- int64_t last_cluster = -1;
22
- bool active;
40
BdrvDirtyBitmapIter *dbi;
23
BlockDriverState *bottom_bs;
41
24
bool chain_frozen;
42
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
25
} BDRVStateCOR;
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
26
@@ -XXX,XX +XXX,XX @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
44
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
27
*/
45
cluster = offset / job->cluster_size;
28
bdrv_ref(bottom_bs);
46
29
}
47
- /* Fake progress updates for any clusters we skipped */
30
- state->active = true;
48
- if (cluster != last_cluster + 1) {
31
state->bottom_bs = bottom_bs;
49
- job->common.offset += ((cluster - last_cluster - 1) *
32
50
- job->cluster_size);
33
/*
51
- }
34
@@ -XXX,XX +XXX,XX @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
35
uint64_t perm, uint64_t shared,
36
uint64_t *nperm, uint64_t *nshared)
37
{
38
- BDRVStateCOR *s = bs->opaque;
52
-
39
-
53
for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
40
- if (!s->active) {
54
do {
41
- /*
55
if (yield_and_check(job)) {
42
- * While the filter is being removed
56
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
43
- */
57
if (granularity < job->cluster_size) {
44
- *nperm = 0;
58
bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
45
- *nshared = BLK_PERM_ALL;
59
}
46
- return;
60
-
61
- last_cluster = cluster - 1;
62
- }
47
- }
63
-
48
-
64
- /* Play some final catchup with the progress meter */
49
*nperm = perm & PERM_PASSTHROUGH;
65
- end = DIV_ROUND_UP(job->common.len, job->cluster_size);
50
*nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
66
- if (last_cluster + 1 < end) {
51
67
- job->common.offset += ((end - last_cluster - 1) * job->cluster_size);
52
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_copy_on_read = {
53
54
void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
55
{
56
- BdrvChild *child;
57
- BlockDriverState *bs;
58
BDRVStateCOR *s = cor_filter_bs->opaque;
59
60
- child = bdrv_filter_child(cor_filter_bs);
61
- if (!child) {
62
- return;
63
- }
64
- bs = child->bs;
65
-
66
- /* Retain the BDS until we complete the graph change. */
67
- bdrv_ref(bs);
68
- /* Hold a guest back from writing while permissions are being reset. */
69
- bdrv_drained_begin(bs);
70
- /* Drop permissions before the graph change. */
71
- s->active = false;
72
/* unfreeze, as otherwise bdrv_replace_node() will fail */
73
if (s->chain_frozen) {
74
s->chain_frozen = false;
75
bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
68
}
76
}
69
77
- bdrv_child_refresh_perms(cor_filter_bs, child, &error_abort);
70
out:
78
- bdrv_replace_node(cor_filter_bs, bs, &error_abort);
71
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
79
-
72
bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
80
- bdrv_drained_end(bs);
73
}
81
- bdrv_unref(bs);
74
82
+ bdrv_drop_filter(cor_filter_bs, &error_abort);
75
+ job->common.offset = job->common.len -
83
bdrv_unref(cor_filter_bs);
76
+ hbitmap_count(job->copy_bitmap) * job->cluster_size;
77
+
78
bdrv_dirty_iter_free(dbi);
79
}
84
}
80
85
81
--
86
--
82
2.9.5
87
2.31.1
83
88
84
89
diff view generated by jsdifflib
New patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
2
3
pylint 2.8 introduces consider-using-with error, suggesting
4
to use the 'with' block statement when possible.
5
6
Modify all subprocess.Popen call to use the 'with' statement,
7
except the one in __init__ of QemuIoInteractive class, since
8
it is assigned to a class field and used in other methods.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20210510190449.65948-1-eesposit@redhat.com>
12
[mreitz: Disable bad-option-value warning in the iotests' pylintrc, so
13
that disabling consider-using-with in QemuIoInteractive will
14
not produce a warning in pre-2.8 pylint versions]
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
tests/qemu-iotests/iotests.py | 65 ++++++++++++++++----------------
18
tests/qemu-iotests/pylintrc | 3 ++
19
tests/qemu-iotests/testrunner.py | 22 +++++------
20
3 files changed, 47 insertions(+), 43 deletions(-)
21
22
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
23
index XXXXXXX..XXXXXXX 100644
24
--- a/tests/qemu-iotests/iotests.py
25
+++ b/tests/qemu-iotests/iotests.py
26
@@ -XXX,XX +XXX,XX @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
27
Run a tool and return both its output and its exit code
28
"""
29
stderr = subprocess.STDOUT if connect_stderr else None
30
- subp = subprocess.Popen(args,
31
- stdout=subprocess.PIPE,
32
- stderr=stderr,
33
- universal_newlines=True)
34
- output = subp.communicate()[0]
35
- if subp.returncode < 0:
36
- cmd = ' '.join(args)
37
- sys.stderr.write(f'{tool} received signal {-subp.returncode}: {cmd}\n')
38
- return (output, subp.returncode)
39
+ with subprocess.Popen(args, stdout=subprocess.PIPE,
40
+ stderr=stderr, universal_newlines=True) as subp:
41
+ output = subp.communicate()[0]
42
+ if subp.returncode < 0:
43
+ cmd = ' '.join(args)
44
+ sys.stderr.write(f'{tool} received signal \
45
+ {-subp.returncode}: {cmd}\n')
46
+ return (output, subp.returncode)
47
48
def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
49
"""
50
@@ -XXX,XX +XXX,XX @@ def qemu_io_silent_check(*args):
51
class QemuIoInteractive:
52
def __init__(self, *args):
53
self.args = qemu_io_args_no_fmt + list(args)
54
+ # We need to keep the Popen objext around, and not
55
+ # close it immediately. Therefore, disable the pylint check:
56
+ # pylint: disable=consider-using-with
57
self._p = subprocess.Popen(self.args, stdin=subprocess.PIPE,
58
stdout=subprocess.PIPE,
59
stderr=subprocess.STDOUT,
60
@@ -XXX,XX +XXX,XX @@ def qemu_nbd_popen(*args):
61
cmd.extend(args)
62
63
log('Start NBD server')
64
- p = subprocess.Popen(cmd)
65
- try:
66
- while not os.path.exists(pid_file):
67
- if p.poll() is not None:
68
- raise RuntimeError(
69
- "qemu-nbd terminated with exit code {}: {}"
70
- .format(p.returncode, ' '.join(cmd)))
71
-
72
- time.sleep(0.01)
73
- yield
74
- finally:
75
- if os.path.exists(pid_file):
76
- os.remove(pid_file)
77
- log('Kill NBD server')
78
- p.kill()
79
- p.wait()
80
+ with subprocess.Popen(cmd) as p:
81
+ try:
82
+ while not os.path.exists(pid_file):
83
+ if p.poll() is not None:
84
+ raise RuntimeError(
85
+ "qemu-nbd terminated with exit code {}: {}"
86
+ .format(p.returncode, ' '.join(cmd)))
87
+
88
+ time.sleep(0.01)
89
+ yield
90
+ finally:
91
+ if os.path.exists(pid_file):
92
+ os.remove(pid_file)
93
+ log('Kill NBD server')
94
+ p.kill()
95
+ p.wait()
96
97
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
98
'''Return True if two image files are identical'''
99
@@ -XXX,XX +XXX,XX @@ def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
100
101
def create_image(name, size):
102
'''Create a fully-allocated raw image with sector markers'''
103
- file = open(name, 'wb')
104
- i = 0
105
- while i < size:
106
- sector = struct.pack('>l504xl', i // 512, i // 512)
107
- file.write(sector)
108
- i = i + 512
109
- file.close()
110
+ with open(name, 'wb') as file:
111
+ i = 0
112
+ while i < size:
113
+ sector = struct.pack('>l504xl', i // 512, i // 512)
114
+ file.write(sector)
115
+ i = i + 512
116
117
def image_size(img):
118
'''Return image's virtual size'''
119
diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc
120
index XXXXXXX..XXXXXXX 100644
121
--- a/tests/qemu-iotests/pylintrc
122
+++ b/tests/qemu-iotests/pylintrc
123
@@ -XXX,XX +XXX,XX @@ disable=invalid-name,
124
too-many-public-methods,
125
# pylint warns about Optional[] etc. as unsubscriptable in 3.9
126
unsubscriptable-object,
127
+ # Sometimes we need to disable a newly introduced pylint warning.
128
+ # Doing so should not produce a warning in older versions of pylint.
129
+ bad-option-value,
130
# These are temporary, and should be removed:
131
missing-docstring,
132
too-many-return-statements,
133
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
134
index XXXXXXX..XXXXXXX 100644
135
--- a/tests/qemu-iotests/testrunner.py
136
+++ b/tests/qemu-iotests/testrunner.py
137
@@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult:
138
139
t0 = time.time()
140
with f_bad.open('w', encoding="utf-8") as f:
141
- proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env,
142
- stdout=f, stderr=subprocess.STDOUT)
143
- try:
144
- proc.wait()
145
- except KeyboardInterrupt:
146
- proc.terminate()
147
- proc.wait()
148
- return TestResult(status='not run',
149
- description='Interrupted by user',
150
- interrupted=True)
151
- ret = proc.returncode
152
+ with subprocess.Popen(args, cwd=str(f_test.parent), env=env,
153
+ stdout=f, stderr=subprocess.STDOUT) as proc:
154
+ try:
155
+ proc.wait()
156
+ except KeyboardInterrupt:
157
+ proc.terminate()
158
+ proc.wait()
159
+ return TestResult(status='not run',
160
+ description='Interrupted by user',
161
+ interrupted=True)
162
+ ret = proc.returncode
163
164
elapsed = round(time.time() - t0, 1)
165
166
--
167
2.31.1
168
169
diff view generated by jsdifflib
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
2
3
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
write-notifiers are used only for write-threshold. New code for such
4
purpose should create filters.
5
6
Let's better special-case write-threshold and drop write notifiers at
7
all. (Actually, write-threshold is special-cased anyway, as the only
8
user of write-notifiers)
9
10
So, create a new direct interface for bdrv_co_write_req_prepare() and
11
drop all write-notifier related logic from write-threshold.c.
12
13
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-Id: <20210506090621.11848-2-vsementsov@virtuozzo.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
[mreitz: Adjusted comment as per Eric's suggestion]
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
---
20
---
5
block/curl.c | 6 ++++++
21
include/block/block_int.h | 1 -
6
1 file changed, 6 insertions(+)
22
include/block/write-threshold.h | 9 +++++
23
block/io.c | 5 ++-
24
block/write-threshold.c | 70 +++++++--------------------------
25
4 files changed, 27 insertions(+), 58 deletions(-)
7
26
8
diff --git a/block/curl.c b/block/curl.c
27
diff --git a/include/block/block_int.h b/include/block/block_int.h
9
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
10
--- a/block/curl.c
29
--- a/include/block/block_int.h
11
+++ b/block/curl.c
30
+++ b/include/block/block_int.h
12
@@ -XXX,XX +XXX,XX @@ out_noclean:
31
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
13
qemu_mutex_destroy(&s->mutex);
32
14
g_free(s->cookie);
33
/* threshold limit for writes, in bytes. "High water mark". */
15
g_free(s->url);
34
uint64_t write_threshold_offset;
16
+ g_free(s->username);
35
- NotifierWithReturn write_threshold_notifier;
17
+ g_free(s->proxyusername);
36
18
+ g_free(s->proxypassword);
37
/* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex.
19
qemu_opts_del(opts);
38
* Reading from the list can be done with either the BQL or the
20
return -EINVAL;
39
diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/include/block/write-threshold.h
42
+++ b/include/block/write-threshold.h
43
@@ -XXX,XX +XXX,XX @@ bool bdrv_write_threshold_is_set(const BlockDriverState *bs);
44
uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
45
const BdrvTrackedRequest *req);
46
47
+/*
48
+ * bdrv_write_threshold_check_write
49
+ *
50
+ * Check whether the specified request exceeds the write threshold.
51
+ * If so, send a corresponding event and disable write threshold checking.
52
+ */
53
+void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset,
54
+ int64_t bytes);
55
+
56
#endif
57
diff --git a/block/io.c b/block/io.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/io.c
60
+++ b/block/io.c
61
@@ -XXX,XX +XXX,XX @@
62
#include "block/blockjob_int.h"
63
#include "block/block_int.h"
64
#include "block/coroutines.h"
65
+#include "block/write-threshold.h"
66
#include "qemu/cutils.h"
67
#include "qapi/error.h"
68
#include "qemu/error-report.h"
69
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes,
70
} else {
71
assert(child->perm & BLK_PERM_WRITE);
72
}
73
- return notifier_with_return_list_notify(&bs->before_write_notifiers,
74
- req);
75
+ bdrv_write_threshold_check_write(bs, offset, bytes);
76
+ return 0;
77
case BDRV_TRACKED_TRUNCATE:
78
assert(child->perm & BLK_PERM_RESIZE);
79
return 0;
80
diff --git a/block/write-threshold.c b/block/write-threshold.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/write-threshold.c
83
+++ b/block/write-threshold.c
84
@@ -XXX,XX +XXX,XX @@ bool bdrv_write_threshold_is_set(const BlockDriverState *bs)
85
return bs->write_threshold_offset > 0;
21
}
86
}
22
@@ -XXX,XX +XXX,XX @@ static void curl_close(BlockDriverState *bs)
87
23
88
-static void write_threshold_disable(BlockDriverState *bs)
24
g_free(s->cookie);
89
-{
25
g_free(s->url);
90
- if (bdrv_write_threshold_is_set(bs)) {
26
+ g_free(s->username);
91
- notifier_with_return_remove(&bs->write_threshold_notifier);
27
+ g_free(s->proxyusername);
92
- bs->write_threshold_offset = 0;
28
+ g_free(s->proxypassword);
93
- }
94
-}
95
-
96
uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
97
const BdrvTrackedRequest *req)
98
{
99
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
100
return 0;
29
}
101
}
30
102
31
static int64_t curl_getlength(BlockDriverState *bs)
103
-static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
104
- void *opaque)
105
-{
106
- BdrvTrackedRequest *req = opaque;
107
- BlockDriverState *bs = req->bs;
108
- uint64_t amount = 0;
109
-
110
- amount = bdrv_write_threshold_exceeded(bs, req);
111
- if (amount > 0) {
112
- qapi_event_send_block_write_threshold(
113
- bs->node_name,
114
- amount,
115
- bs->write_threshold_offset);
116
-
117
- /* autodisable to avoid flooding the monitor */
118
- write_threshold_disable(bs);
119
- }
120
-
121
- return 0; /* should always let other notifiers run */
122
-}
123
-
124
-static void write_threshold_register_notifier(BlockDriverState *bs)
125
-{
126
- bs->write_threshold_notifier.notify = before_write_notify;
127
- bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier);
128
-}
129
-
130
-static void write_threshold_update(BlockDriverState *bs,
131
- int64_t threshold_bytes)
132
-{
133
- bs->write_threshold_offset = threshold_bytes;
134
-}
135
-
136
void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes)
137
{
138
- if (bdrv_write_threshold_is_set(bs)) {
139
- if (threshold_bytes > 0) {
140
- write_threshold_update(bs, threshold_bytes);
141
- } else {
142
- write_threshold_disable(bs);
143
- }
144
- } else {
145
- if (threshold_bytes > 0) {
146
- /* avoid multiple registration */
147
- write_threshold_register_notifier(bs);
148
- write_threshold_update(bs, threshold_bytes);
149
- }
150
- /* discard bogus disable request */
151
- }
152
+ bs->write_threshold_offset = threshold_bytes;
153
}
154
155
void qmp_block_set_write_threshold(const char *node_name,
156
@@ -XXX,XX +XXX,XX @@ void qmp_block_set_write_threshold(const char *node_name,
157
158
aio_context_release(aio_context);
159
}
160
+
161
+void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset,
162
+ int64_t bytes)
163
+{
164
+ int64_t end = offset + bytes;
165
+ uint64_t wtr = bs->write_threshold_offset;
166
+
167
+ if (wtr > 0 && end > wtr) {
168
+ qapi_event_send_block_write_threshold(bs->node_name, end - wtr, wtr);
169
+
170
+ /* autodisable to avoid flooding the monitor */
171
+ bdrv_write_threshold_set(bs, 0);
172
+ }
173
+}
32
--
174
--
33
2.9.5
175
2.31.1
34
176
35
177
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
They are unused now.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20210506090621.11848-3-vsementsov@virtuozzo.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
include/block/block_int.h | 12 ------------
12
block.c | 1 -
13
block/io.c | 6 ------
14
3 files changed, 19 deletions(-)
15
16
diff --git a/include/block/block_int.h b/include/block/block_int.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block_int.h
19
+++ b/include/block/block_int.h
20
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
21
*/
22
int64_t total_sectors;
23
24
- /* Callback before write request is processed */
25
- NotifierWithReturnList before_write_notifiers;
26
-
27
/* threshold limit for writes, in bytes. "High water mark". */
28
uint64_t write_threshold_offset;
29
30
@@ -XXX,XX +XXX,XX @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
31
bool bdrv_backing_overridden(BlockDriverState *bs);
32
33
34
-/**
35
- * bdrv_add_before_write_notifier:
36
- *
37
- * Register a callback that is invoked before write requests are processed but
38
- * after any throttling or waiting for overlapping requests.
39
- */
40
-void bdrv_add_before_write_notifier(BlockDriverState *bs,
41
- NotifierWithReturn *notifier);
42
-
43
/**
44
* bdrv_add_aio_context_notifier:
45
*
46
diff --git a/block.c b/block.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block.c
49
+++ b/block.c
50
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new(void)
51
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
52
QLIST_INIT(&bs->op_blockers[i]);
53
}
54
- notifier_with_return_list_init(&bs->before_write_notifiers);
55
qemu_co_mutex_init(&bs->reqs_lock);
56
qemu_mutex_init(&bs->dirty_bitmap_mutex);
57
bs->refcnt = 1;
58
diff --git a/block/io.c b/block/io.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/io.c
61
+++ b/block/io.c
62
@@ -XXX,XX +XXX,XX @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
63
return true;
64
}
65
66
-void bdrv_add_before_write_notifier(BlockDriverState *bs,
67
- NotifierWithReturn *notifier)
68
-{
69
- notifier_with_return_list_add(&bs->before_write_notifiers, notifier);
70
-}
71
-
72
void bdrv_io_plug(BlockDriverState *bs)
73
{
74
BdrvChild *child;
75
--
76
2.31.1
77
78
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
If users set an unreasonably low speed (like one byte per second), the
3
These tests use bdrv_write_threshold_exceeded() API, which is used only
4
calculated delay may exceed many hours. While we like to punish users
4
for test (since pre-previous commit). Better is testing real API, which
5
for asking for stupid things, we do also like to allow users to correct
5
is used in block.c as well.
6
their wicked ways.
7
6
8
When a user provides a new speed, kick the job to allow it to recalculate
7
So, let's call bdrv_write_threshold_check_write(), and check is
9
its delay.
8
bs->write_threshold_offset cleared or not (it's cleared iff threshold
9
triggered).
10
10
11
Signed-off-by: John Snow <jsnow@redhat.com>
11
Also we get rid of BdrvTrackedRequest use here. Note, that paranoiac
12
bdrv_check_request() calls were added in 8b1170012b1 to protect
13
BdrvTrackedRequest. Drop them now.
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Message-Id: <20210506090621.11848-4-vsementsov@virtuozzo.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: 20171213204611.26276-1-jsnow@redhat.com
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Jeff Cody <jcody@redhat.com>
15
---
20
---
16
blockjob.c | 30 +++++++++++++++++++++++++++++-
21
tests/unit/test-write-threshold.c | 22 ++++------------------
17
1 file changed, 29 insertions(+), 1 deletion(-)
22
1 file changed, 4 insertions(+), 18 deletions(-)
18
23
19
diff --git a/blockjob.c b/blockjob.c
24
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
20
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
21
--- a/blockjob.c
26
--- a/tests/unit/test-write-threshold.c
22
+++ b/blockjob.c
27
+++ b/tests/unit/test-write-threshold.c
23
@@ -XXX,XX +XXX,XX @@ static void __attribute__((__constructor__)) block_job_init(void)
28
@@ -XXX,XX +XXX,XX @@ static void test_threshold_multi_set_get(void)
24
29
25
static void block_job_event_cancelled(BlockJob *job);
30
static void test_threshold_not_trigger(void)
26
static void block_job_event_completed(BlockJob *job, const char *msg);
31
{
27
+static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job));
32
- uint64_t amount = 0;
28
33
uint64_t threshold = 4 * 1024 * 1024;
29
/* Transactional group of block jobs */
34
BlockDriverState bs;
30
struct BlockJobTxn {
35
- BdrvTrackedRequest req;
31
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
36
32
}
37
memset(&bs, 0, sizeof(bs));
38
- memset(&req, 0, sizeof(req));
39
- req.offset = 1024;
40
- req.bytes = 1024;
41
-
42
- bdrv_check_request(req.offset, req.bytes, &error_abort);
43
44
bdrv_write_threshold_set(&bs, threshold);
45
- amount = bdrv_write_threshold_exceeded(&bs, &req);
46
- g_assert_cmpuint(amount, ==, 0);
47
+ bdrv_write_threshold_check_write(&bs, 1024, 1024);
48
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, threshold);
33
}
49
}
34
50
35
+/* Assumes the block_job_mutex is held */
51
36
+static bool block_job_timer_pending(BlockJob *job)
52
static void test_threshold_trigger(void)
37
+{
38
+ return timer_pending(&job->sleep_timer);
39
+}
40
+
41
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
42
{
53
{
43
Error *local_err = NULL;
54
- uint64_t amount = 0;
44
+ int64_t old_speed = job->speed;
55
uint64_t threshold = 4 * 1024 * 1024;
45
56
BlockDriverState bs;
46
if (!job->driver->set_speed) {
57
- BdrvTrackedRequest req;
47
error_setg(errp, QERR_UNSUPPORTED);
58
48
@@ -XXX,XX +XXX,XX @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
59
memset(&bs, 0, sizeof(bs));
49
}
60
- memset(&req, 0, sizeof(req));
50
61
- req.offset = (4 * 1024 * 1024) - 1024;
51
job->speed = speed;
62
- req.bytes = 2 * 1024;
52
+ if (speed <= old_speed) {
63
-
53
+ return;
64
- bdrv_check_request(req.offset, req.bytes, &error_abort);
54
+ }
65
55
+
66
bdrv_write_threshold_set(&bs, threshold);
56
+ /* kick only if a timer is pending */
67
- amount = bdrv_write_threshold_exceeded(&bs, &req);
57
+ block_job_enter_cond(job, block_job_timer_pending);
68
- g_assert_cmpuint(amount, >=, 1024);
69
+ bdrv_write_threshold_check_write(&bs, threshold - 1024, 2 * 1024);
70
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0);
58
}
71
}
59
72
60
void block_job_complete(BlockJob *job, Error **errp)
73
typedef struct TestStruct {
61
@@ -XXX,XX +XXX,XX @@ void block_job_resume_all(void)
62
}
63
}
64
65
-void block_job_enter(BlockJob *job)
66
+/*
67
+ * Conditionally enter a block_job pending a call to fn() while
68
+ * under the block_job_lock critical section.
69
+ */
70
+static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job))
71
{
72
if (!block_job_started(job)) {
73
return;
74
@@ -XXX,XX +XXX,XX @@ void block_job_enter(BlockJob *job)
75
return;
76
}
77
78
+ if (fn && !fn(job)) {
79
+ block_job_unlock();
80
+ return;
81
+ }
82
+
83
assert(!job->deferred_to_main_loop);
84
timer_del(&job->sleep_timer);
85
job->busy = true;
86
@@ -XXX,XX +XXX,XX @@ void block_job_enter(BlockJob *job)
87
aio_co_wake(job->co);
88
}
89
90
+void block_job_enter(BlockJob *job)
91
+{
92
+ block_job_enter_cond(job, NULL);
93
+}
94
+
95
bool block_job_is_cancelled(BlockJob *job)
96
{
97
return job->cancelled;
98
--
74
--
99
2.9.5
75
2.31.1
100
76
101
77
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Use HBitmap copy_bitmap instead of done_bitmap. This is needed to
3
bdrv_write_threshold_exceeded() is unused.
4
improve incremental backup in following patches and to unify backup
4
5
loop for full/incremental modes in future patches.
5
bdrv_write_threshold_is_set() is used only to double check the value of
6
bs->write_threshold_offset in tests. No real sense in it (both tests do
7
check real value with help of bdrv_write_threshold_get())
6
8
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-Id: <20210506090621.11848-5-vsementsov@virtuozzo.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
14
[mreitz: Adjusted commit message as per Eric's suggestion]
11
Message-id: 20171012135313.227864-3-vsementsov@virtuozzo.com
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Jeff Cody <jcody@redhat.com>
13
---
16
---
14
block/backup.c | 23 ++++++++++++++---------
17
include/block/write-threshold.h | 24 ------------------------
15
1 file changed, 14 insertions(+), 9 deletions(-)
18
block/write-threshold.c | 19 -------------------
19
tests/unit/test-write-threshold.c | 4 ----
20
3 files changed, 47 deletions(-)
16
21
17
diff --git a/block/backup.c b/block/backup.c
22
diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h
18
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
19
--- a/block/backup.c
24
--- a/include/block/write-threshold.h
20
+++ b/block/backup.c
25
+++ b/include/block/write-threshold.h
21
@@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob {
26
@@ -XXX,XX +XXX,XX @@ void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes);
22
BlockdevOnError on_target_error;
27
*/
23
CoRwlock flush_rwlock;
28
uint64_t bdrv_write_threshold_get(const BlockDriverState *bs);
24
uint64_t bytes_read;
29
25
- unsigned long *done_bitmap;
30
-/*
26
int64_t cluster_size;
31
- * bdrv_write_threshold_is_set
27
bool compress;
32
- *
28
NotifierWithReturn before_write;
33
- * Tell if a write threshold is set for a given BDS.
29
QLIST_HEAD(, CowRequest) inflight_reqs;
34
- */
30
+
35
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs);
31
+ HBitmap *copy_bitmap;
32
} BackupBlockJob;
33
34
/* See if in-flight requests overlap and wait for them to complete */
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
36
cow_request_begin(&cow_request, job, start, end);
37
38
for (; start < end; start += job->cluster_size) {
39
- if (test_bit(start / job->cluster_size, job->done_bitmap)) {
40
+ if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
41
trace_backup_do_cow_skip(job, start);
42
continue; /* already copied */
43
}
44
+ hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
45
46
trace_backup_do_cow_process(job, start);
47
48
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
49
if (error_is_read) {
50
*error_is_read = true;
51
}
52
+ hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
53
goto out;
54
}
55
56
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
57
if (error_is_read) {
58
*error_is_read = false;
59
}
60
+ hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
61
goto out;
62
}
63
64
- set_bit(start / job->cluster_size, job->done_bitmap);
65
-
36
-
66
/* Publish progress, guest I/O counts as progress too. Note that the
37
-/*
67
* offset field is an opaque progress value, it is not a disk offset.
38
- * bdrv_write_threshold_exceeded
68
*/
39
- *
69
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
40
- * Return the extent of a write request that exceeded the threshold,
70
}
41
- * or zero if the request is below the threshold.
71
42
- * Return zero also if the threshold was not set.
72
len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size);
43
- *
73
- bitmap_zero(backup_job->done_bitmap, len);
44
- * NOTE: here we assume the following holds for each request this code
74
+ hbitmap_set(backup_job->copy_bitmap, 0, len);
45
- * deals with:
46
- *
47
- * assert((req->offset + req->bytes) <= UINT64_MAX)
48
- *
49
- * Please not there is *not* an actual C assert().
50
- */
51
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
52
- const BdrvTrackedRequest *req);
53
-
54
/*
55
* bdrv_write_threshold_check_write
56
*
57
diff --git a/block/write-threshold.c b/block/write-threshold.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/write-threshold.c
60
+++ b/block/write-threshold.c
61
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_write_threshold_get(const BlockDriverState *bs)
62
return bs->write_threshold_offset;
75
}
63
}
76
64
77
void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
65
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs)
78
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
66
-{
79
BackupBlockJob *job = opaque;
67
- return bs->write_threshold_offset > 0;
80
BackupCompleteData *data;
68
-}
81
BlockDriverState *bs = blk_bs(job->common.blk);
69
-
82
- int64_t offset;
70
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
83
+ int64_t offset, nb_clusters;
71
- const BdrvTrackedRequest *req)
84
int ret = 0;
72
-{
85
73
- if (bdrv_write_threshold_is_set(bs)) {
86
QLIST_INIT(&job->inflight_reqs);
74
- if (req->offset > bs->write_threshold_offset) {
87
qemu_co_rwlock_init(&job->flush_rwlock);
75
- return (req->offset - bs->write_threshold_offset) + req->bytes;
88
76
- }
89
- job->done_bitmap = bitmap_new(DIV_ROUND_UP(job->common.len,
77
- if ((req->offset + req->bytes) > bs->write_threshold_offset) {
90
- job->cluster_size));
78
- return (req->offset + req->bytes) - bs->write_threshold_offset;
91
+ nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size);
79
- }
92
+ job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
80
- }
93
+ hbitmap_set(job->copy_bitmap, 0, nb_clusters);
81
- return 0;
94
82
-}
95
job->before_write.notify = backup_before_write_notify;
83
-
96
bdrv_add_before_write_notifier(bs, &job->before_write);
84
void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes)
97
85
{
98
if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
86
bs->write_threshold_offset = threshold_bytes;
99
+ /* All bits are set in copy_bitmap to allow any cluster to be copied.
87
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
100
+ * This does not actually require them to be copied. */
88
index XXXXXXX..XXXXXXX 100644
101
while (!block_job_is_cancelled(&job->common)) {
89
--- a/tests/unit/test-write-threshold.c
102
/* Yield until the job is cancelled. We just let our before_write
90
+++ b/tests/unit/test-write-threshold.c
103
* notify callback service CoW requests. */
91
@@ -XXX,XX +XXX,XX @@ static void test_threshold_not_set_on_init(void)
104
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
92
BlockDriverState bs;
105
/* wait until pending backup_do_cow() calls have completed */
93
memset(&bs, 0, sizeof(bs));
106
qemu_co_rwlock_wrlock(&job->flush_rwlock);
94
107
qemu_co_rwlock_unlock(&job->flush_rwlock);
95
- g_assert(!bdrv_write_threshold_is_set(&bs));
108
- g_free(job->done_bitmap);
96
-
109
+ hbitmap_free(job->copy_bitmap);
97
res = bdrv_write_threshold_get(&bs);
110
98
g_assert_cmpint(res, ==, 0);
111
data = g_malloc(sizeof(*data));
99
}
112
data->ret = ret;
100
@@ -XXX,XX +XXX,XX @@ static void test_threshold_set_get(void)
101
102
bdrv_write_threshold_set(&bs, threshold);
103
104
- g_assert(bdrv_write_threshold_is_set(&bs));
105
-
106
res = bdrv_write_threshold_get(&bs);
107
g_assert_cmpint(res, ==, threshold);
108
}
113
--
109
--
114
2.9.5
110
2.31.1
115
111
116
112
diff view generated by jsdifflib
1
No functional changes, just whitespace manipulation.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
Testing set/get of one 64bit variable doesn't seem necessary. We have a
4
Reviewed-by: Eric Blake <eblake@redhat.com>
4
lot of such variables. Also remaining tests do test set/get anyway.
5
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
5
6
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20210506090621.11848-7-vsementsov@virtuozzo.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
11
---
8
block/sheepdog.c | 164 +++++++++++++++++++++++++++----------------------------
12
tests/unit/test-write-threshold.c | 43 -------------------------------
9
1 file changed, 82 insertions(+), 82 deletions(-)
13
1 file changed, 43 deletions(-)
10
14
11
diff --git a/block/sheepdog.c b/block/sheepdog.c
15
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/block/sheepdog.c
17
--- a/tests/unit/test-write-threshold.c
14
+++ b/block/sheepdog.c
18
+++ b/tests/unit/test-write-threshold.c
15
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVSheepdogReopenState {
19
@@ -XXX,XX +XXX,XX @@
16
int cache_flags;
20
#include "block/write-threshold.h"
17
} BDRVSheepdogReopenState;
21
18
22
19
-static const char * sd_strerror(int err)
23
-static void test_threshold_not_set_on_init(void)
20
+static const char *sd_strerror(int err)
24
-{
25
- uint64_t res;
26
- BlockDriverState bs;
27
- memset(&bs, 0, sizeof(bs));
28
-
29
- res = bdrv_write_threshold_get(&bs);
30
- g_assert_cmpint(res, ==, 0);
31
-}
32
-
33
-static void test_threshold_set_get(void)
34
-{
35
- uint64_t threshold = 4 * 1024 * 1024;
36
- uint64_t res;
37
- BlockDriverState bs;
38
- memset(&bs, 0, sizeof(bs));
39
-
40
- bdrv_write_threshold_set(&bs, threshold);
41
-
42
- res = bdrv_write_threshold_get(&bs);
43
- g_assert_cmpint(res, ==, threshold);
44
-}
45
-
46
-static void test_threshold_multi_set_get(void)
47
-{
48
- uint64_t threshold1 = 4 * 1024 * 1024;
49
- uint64_t threshold2 = 15 * 1024 * 1024;
50
- uint64_t res;
51
- BlockDriverState bs;
52
- memset(&bs, 0, sizeof(bs));
53
-
54
- bdrv_write_threshold_set(&bs, threshold1);
55
- bdrv_write_threshold_set(&bs, threshold2);
56
- res = bdrv_write_threshold_get(&bs);
57
- g_assert_cmpint(res, ==, threshold2);
58
-}
59
-
60
static void test_threshold_not_trigger(void)
21
{
61
{
22
int i;
62
uint64_t threshold = 4 * 1024 * 1024;
23
63
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
24
@@ -XXX,XX +XXX,XX @@ static QemuOptsList sd_create_opts = {
64
{
25
};
65
size_t i;
26
66
TestStruct tests[] = {
27
static BlockDriver bdrv_sheepdog = {
67
- { "/write-threshold/not-set-on-init",
28
- .format_name = "sheepdog",
68
- test_threshold_not_set_on_init },
29
- .protocol_name = "sheepdog",
69
- { "/write-threshold/set-get",
30
- .instance_size = sizeof(BDRVSheepdogState),
70
- test_threshold_set_get },
31
- .bdrv_parse_filename = sd_parse_filename,
71
- { "/write-threshold/multi-set-get",
32
- .bdrv_file_open = sd_open,
72
- test_threshold_multi_set_get },
33
- .bdrv_reopen_prepare = sd_reopen_prepare,
73
{ "/write-threshold/not-trigger",
34
- .bdrv_reopen_commit = sd_reopen_commit,
74
test_threshold_not_trigger },
35
- .bdrv_reopen_abort = sd_reopen_abort,
75
{ "/write-threshold/trigger",
36
- .bdrv_close = sd_close,
37
- .bdrv_create = sd_create,
38
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
39
- .bdrv_getlength = sd_getlength,
40
+ .format_name = "sheepdog",
41
+ .protocol_name = "sheepdog",
42
+ .instance_size = sizeof(BDRVSheepdogState),
43
+ .bdrv_parse_filename = sd_parse_filename,
44
+ .bdrv_file_open = sd_open,
45
+ .bdrv_reopen_prepare = sd_reopen_prepare,
46
+ .bdrv_reopen_commit = sd_reopen_commit,
47
+ .bdrv_reopen_abort = sd_reopen_abort,
48
+ .bdrv_close = sd_close,
49
+ .bdrv_create = sd_create,
50
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
51
+ .bdrv_getlength = sd_getlength,
52
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
53
- .bdrv_truncate = sd_truncate,
54
+ .bdrv_truncate = sd_truncate,
55
56
- .bdrv_co_readv = sd_co_readv,
57
- .bdrv_co_writev = sd_co_writev,
58
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
59
- .bdrv_co_pdiscard = sd_co_pdiscard,
60
- .bdrv_co_get_block_status = sd_co_get_block_status,
61
+ .bdrv_co_readv = sd_co_readv,
62
+ .bdrv_co_writev = sd_co_writev,
63
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
64
+ .bdrv_co_pdiscard = sd_co_pdiscard,
65
+ .bdrv_co_get_block_status = sd_co_get_block_status,
66
67
- .bdrv_snapshot_create = sd_snapshot_create,
68
- .bdrv_snapshot_goto = sd_snapshot_goto,
69
- .bdrv_snapshot_delete = sd_snapshot_delete,
70
- .bdrv_snapshot_list = sd_snapshot_list,
71
+ .bdrv_snapshot_create = sd_snapshot_create,
72
+ .bdrv_snapshot_goto = sd_snapshot_goto,
73
+ .bdrv_snapshot_delete = sd_snapshot_delete,
74
+ .bdrv_snapshot_list = sd_snapshot_list,
75
76
- .bdrv_save_vmstate = sd_save_vmstate,
77
- .bdrv_load_vmstate = sd_load_vmstate,
78
+ .bdrv_save_vmstate = sd_save_vmstate,
79
+ .bdrv_load_vmstate = sd_load_vmstate,
80
81
- .bdrv_detach_aio_context = sd_detach_aio_context,
82
- .bdrv_attach_aio_context = sd_attach_aio_context,
83
+ .bdrv_detach_aio_context = sd_detach_aio_context,
84
+ .bdrv_attach_aio_context = sd_attach_aio_context,
85
86
- .create_opts = &sd_create_opts,
87
+ .create_opts = &sd_create_opts,
88
};
89
90
static BlockDriver bdrv_sheepdog_tcp = {
91
- .format_name = "sheepdog",
92
- .protocol_name = "sheepdog+tcp",
93
- .instance_size = sizeof(BDRVSheepdogState),
94
- .bdrv_parse_filename = sd_parse_filename,
95
- .bdrv_file_open = sd_open,
96
- .bdrv_reopen_prepare = sd_reopen_prepare,
97
- .bdrv_reopen_commit = sd_reopen_commit,
98
- .bdrv_reopen_abort = sd_reopen_abort,
99
- .bdrv_close = sd_close,
100
- .bdrv_create = sd_create,
101
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
102
- .bdrv_getlength = sd_getlength,
103
+ .format_name = "sheepdog",
104
+ .protocol_name = "sheepdog+tcp",
105
+ .instance_size = sizeof(BDRVSheepdogState),
106
+ .bdrv_parse_filename = sd_parse_filename,
107
+ .bdrv_file_open = sd_open,
108
+ .bdrv_reopen_prepare = sd_reopen_prepare,
109
+ .bdrv_reopen_commit = sd_reopen_commit,
110
+ .bdrv_reopen_abort = sd_reopen_abort,
111
+ .bdrv_close = sd_close,
112
+ .bdrv_create = sd_create,
113
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
114
+ .bdrv_getlength = sd_getlength,
115
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
116
- .bdrv_truncate = sd_truncate,
117
+ .bdrv_truncate = sd_truncate,
118
119
- .bdrv_co_readv = sd_co_readv,
120
- .bdrv_co_writev = sd_co_writev,
121
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
122
- .bdrv_co_pdiscard = sd_co_pdiscard,
123
- .bdrv_co_get_block_status = sd_co_get_block_status,
124
+ .bdrv_co_readv = sd_co_readv,
125
+ .bdrv_co_writev = sd_co_writev,
126
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
127
+ .bdrv_co_pdiscard = sd_co_pdiscard,
128
+ .bdrv_co_get_block_status = sd_co_get_block_status,
129
130
- .bdrv_snapshot_create = sd_snapshot_create,
131
- .bdrv_snapshot_goto = sd_snapshot_goto,
132
- .bdrv_snapshot_delete = sd_snapshot_delete,
133
- .bdrv_snapshot_list = sd_snapshot_list,
134
+ .bdrv_snapshot_create = sd_snapshot_create,
135
+ .bdrv_snapshot_goto = sd_snapshot_goto,
136
+ .bdrv_snapshot_delete = sd_snapshot_delete,
137
+ .bdrv_snapshot_list = sd_snapshot_list,
138
139
- .bdrv_save_vmstate = sd_save_vmstate,
140
- .bdrv_load_vmstate = sd_load_vmstate,
141
+ .bdrv_save_vmstate = sd_save_vmstate,
142
+ .bdrv_load_vmstate = sd_load_vmstate,
143
144
- .bdrv_detach_aio_context = sd_detach_aio_context,
145
- .bdrv_attach_aio_context = sd_attach_aio_context,
146
+ .bdrv_detach_aio_context = sd_detach_aio_context,
147
+ .bdrv_attach_aio_context = sd_attach_aio_context,
148
149
- .create_opts = &sd_create_opts,
150
+ .create_opts = &sd_create_opts,
151
};
152
153
static BlockDriver bdrv_sheepdog_unix = {
154
- .format_name = "sheepdog",
155
- .protocol_name = "sheepdog+unix",
156
- .instance_size = sizeof(BDRVSheepdogState),
157
- .bdrv_parse_filename = sd_parse_filename,
158
- .bdrv_file_open = sd_open,
159
- .bdrv_reopen_prepare = sd_reopen_prepare,
160
- .bdrv_reopen_commit = sd_reopen_commit,
161
- .bdrv_reopen_abort = sd_reopen_abort,
162
- .bdrv_close = sd_close,
163
- .bdrv_create = sd_create,
164
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
165
- .bdrv_getlength = sd_getlength,
166
+ .format_name = "sheepdog",
167
+ .protocol_name = "sheepdog+unix",
168
+ .instance_size = sizeof(BDRVSheepdogState),
169
+ .bdrv_parse_filename = sd_parse_filename,
170
+ .bdrv_file_open = sd_open,
171
+ .bdrv_reopen_prepare = sd_reopen_prepare,
172
+ .bdrv_reopen_commit = sd_reopen_commit,
173
+ .bdrv_reopen_abort = sd_reopen_abort,
174
+ .bdrv_close = sd_close,
175
+ .bdrv_create = sd_create,
176
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
177
+ .bdrv_getlength = sd_getlength,
178
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
179
- .bdrv_truncate = sd_truncate,
180
+ .bdrv_truncate = sd_truncate,
181
182
- .bdrv_co_readv = sd_co_readv,
183
- .bdrv_co_writev = sd_co_writev,
184
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
185
- .bdrv_co_pdiscard = sd_co_pdiscard,
186
- .bdrv_co_get_block_status = sd_co_get_block_status,
187
+ .bdrv_co_readv = sd_co_readv,
188
+ .bdrv_co_writev = sd_co_writev,
189
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
190
+ .bdrv_co_pdiscard = sd_co_pdiscard,
191
+ .bdrv_co_get_block_status = sd_co_get_block_status,
192
193
- .bdrv_snapshot_create = sd_snapshot_create,
194
- .bdrv_snapshot_goto = sd_snapshot_goto,
195
- .bdrv_snapshot_delete = sd_snapshot_delete,
196
- .bdrv_snapshot_list = sd_snapshot_list,
197
+ .bdrv_snapshot_create = sd_snapshot_create,
198
+ .bdrv_snapshot_goto = sd_snapshot_goto,
199
+ .bdrv_snapshot_delete = sd_snapshot_delete,
200
+ .bdrv_snapshot_list = sd_snapshot_list,
201
202
- .bdrv_save_vmstate = sd_save_vmstate,
203
- .bdrv_load_vmstate = sd_load_vmstate,
204
+ .bdrv_save_vmstate = sd_save_vmstate,
205
+ .bdrv_load_vmstate = sd_load_vmstate,
206
207
- .bdrv_detach_aio_context = sd_detach_aio_context,
208
- .bdrv_attach_aio_context = sd_attach_aio_context,
209
+ .bdrv_detach_aio_context = sd_detach_aio_context,
210
+ .bdrv_attach_aio_context = sd_attach_aio_context,
211
212
- .create_opts = &sd_create_opts,
213
+ .create_opts = &sd_create_opts,
214
};
215
216
static void bdrv_sheepdog_init(void)
217
--
76
--
218
2.9.5
77
2.31.1
219
78
220
79
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The function searches for next zero bit.
3
We don't need this extra logic: it doesn't make code simpler.
4
Also add interface for BdrvDirtyBitmap and unit test.
5
4
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20171012135313.227864-2-vsementsov@virtuozzo.com
7
Message-Id: <20210506090621.11848-8-vsementsov@virtuozzo.com>
9
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
10
---
11
block/dirty-bitmap.c | 5 ++++
11
tests/unit/test-write-threshold.c | 20 +++-----------------
12
include/block/dirty-bitmap.h | 1 +
12
1 file changed, 3 insertions(+), 17 deletions(-)
13
include/qemu/hbitmap.h | 8 ++++++
14
tests/test-hbitmap.c | 61 ++++++++++++++++++++++++++++++++++++++++++++
15
util/hbitmap.c | 39 ++++++++++++++++++++++++++++
16
5 files changed, 114 insertions(+)
17
13
18
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
14
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/block/dirty-bitmap.c
16
--- a/tests/unit/test-write-threshold.c
21
+++ b/block/dirty-bitmap.c
17
+++ b/tests/unit/test-write-threshold.c
22
@@ -XXX,XX +XXX,XX @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ static void test_threshold_trigger(void)
23
{
19
g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0);
24
return hbitmap_sha256(bitmap->bitmap, errp);
25
}
20
}
26
+
21
27
+int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
22
-typedef struct TestStruct {
28
+{
23
- const char *name;
29
+ return hbitmap_next_zero(bitmap->bitmap, offset);
24
- void (*func)(void);
30
+}
25
-} TestStruct;
31
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
26
-
32
index XXXXXXX..XXXXXXX 100644
27
33
--- a/include/block/dirty-bitmap.h
34
+++ b/include/block/dirty-bitmap.h
35
@@ -XXX,XX +XXX,XX @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
36
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
37
BdrvDirtyBitmap *bitmap);
38
char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
39
+int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t start);
40
41
#endif
42
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
43
index XXXXXXX..XXXXXXX 100644
44
--- a/include/qemu/hbitmap.h
45
+++ b/include/qemu/hbitmap.h
46
@@ -XXX,XX +XXX,XX @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
47
*/
48
unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);
49
50
+/* hbitmap_next_zero:
51
+ * @hb: The HBitmap to operate on
52
+ * @start: The bit to start from.
53
+ *
54
+ * Find next not dirty bit.
55
+ */
56
+int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start);
57
+
58
/* hbitmap_create_meta:
59
* Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap.
60
* The caller owns the created bitmap and must call hbitmap_free_meta(hb) to
61
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/tests/test-hbitmap.c
64
+++ b/tests/test-hbitmap.c
65
@@ -XXX,XX +XXX,XX @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data,
66
hbitmap_iter_next(&hbi);
67
}
68
69
+static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start)
70
+{
71
+ int64_t ret1 = hbitmap_next_zero(data->hb, start);
72
+ int64_t ret2 = start;
73
+ for ( ; ret2 < data->size && hbitmap_get(data->hb, ret2); ret2++) {
74
+ ;
75
+ }
76
+ if (ret2 == data->size) {
77
+ ret2 = -1;
78
+ }
79
+
80
+ g_assert_cmpint(ret1, ==, ret2);
81
+}
82
+
83
+static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity)
84
+{
85
+ hbitmap_test_init(data, L3, granularity);
86
+ test_hbitmap_next_zero_check(data, 0);
87
+ test_hbitmap_next_zero_check(data, L3 - 1);
88
+
89
+ hbitmap_set(data->hb, L2, 1);
90
+ test_hbitmap_next_zero_check(data, 0);
91
+ test_hbitmap_next_zero_check(data, L2 - 1);
92
+ test_hbitmap_next_zero_check(data, L2);
93
+ test_hbitmap_next_zero_check(data, L2 + 1);
94
+
95
+ hbitmap_set(data->hb, L2 + 5, L1);
96
+ test_hbitmap_next_zero_check(data, 0);
97
+ test_hbitmap_next_zero_check(data, L2 + 1);
98
+ test_hbitmap_next_zero_check(data, L2 + 2);
99
+ test_hbitmap_next_zero_check(data, L2 + 5);
100
+ test_hbitmap_next_zero_check(data, L2 + L1 - 1);
101
+ test_hbitmap_next_zero_check(data, L2 + L1);
102
+
103
+ hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2);
104
+ test_hbitmap_next_zero_check(data, L2 * 2 - L1);
105
+ test_hbitmap_next_zero_check(data, L2 * 2 - 2);
106
+ test_hbitmap_next_zero_check(data, L2 * 2 - 1);
107
+ test_hbitmap_next_zero_check(data, L2 * 2);
108
+ test_hbitmap_next_zero_check(data, L3 - 1);
109
+
110
+ hbitmap_set(data->hb, 0, L3);
111
+ test_hbitmap_next_zero_check(data, 0);
112
+}
113
+
114
+static void test_hbitmap_next_zero_0(TestHBitmapData *data, const void *unused)
115
+{
116
+ test_hbitmap_next_zero_do(data, 0);
117
+}
118
+
119
+static void test_hbitmap_next_zero_4(TestHBitmapData *data, const void *unused)
120
+{
121
+ test_hbitmap_next_zero_do(data, 4);
122
+}
123
+
124
int main(int argc, char **argv)
28
int main(int argc, char **argv)
125
{
29
{
30
- size_t i;
31
- TestStruct tests[] = {
32
- { "/write-threshold/not-trigger",
33
- test_threshold_not_trigger },
34
- { "/write-threshold/trigger",
35
- test_threshold_trigger },
36
- { NULL, NULL }
37
- };
38
-
126
g_test_init(&argc, &argv, NULL);
39
g_test_init(&argc, &argv, NULL);
127
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
40
- for (i = 0; tests[i].name != NULL; i++) {
128
41
- g_test_add_func(tests[i].name, tests[i].func);
129
hbitmap_test_add("/hbitmap/iter/iter_and_reset",
42
- }
130
test_hbitmap_iter_and_reset);
43
+ g_test_add_func("/write-threshold/not-trigger", test_threshold_not_trigger);
44
+ g_test_add_func("/write-threshold/trigger", test_threshold_trigger);
131
+
45
+
132
+ hbitmap_test_add("/hbitmap/next_zero/next_zero_0",
46
return g_test_run();
133
+ test_hbitmap_next_zero_0);
134
+ hbitmap_test_add("/hbitmap/next_zero/next_zero_4",
135
+ test_hbitmap_next_zero_4);
136
+
137
g_test_run();
138
139
return 0;
140
diff --git a/util/hbitmap.c b/util/hbitmap.c
141
index XXXXXXX..XXXXXXX 100644
142
--- a/util/hbitmap.c
143
+++ b/util/hbitmap.c
144
@@ -XXX,XX +XXX,XX @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first)
145
}
146
}
47
}
147
148
+int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start)
149
+{
150
+ size_t pos = (start >> hb->granularity) >> BITS_PER_LEVEL;
151
+ unsigned long *last_lev = hb->levels[HBITMAP_LEVELS - 1];
152
+ uint64_t sz = hb->sizes[HBITMAP_LEVELS - 1];
153
+ unsigned long cur = last_lev[pos];
154
+ unsigned start_bit_offset =
155
+ (start >> hb->granularity) & (BITS_PER_LONG - 1);
156
+ int64_t res;
157
+
158
+ cur |= (1UL << start_bit_offset) - 1;
159
+ assert((start >> hb->granularity) < hb->size);
160
+
161
+ if (cur == (unsigned long)-1) {
162
+ do {
163
+ pos++;
164
+ } while (pos < sz && last_lev[pos] == (unsigned long)-1);
165
+
166
+ if (pos >= sz) {
167
+ return -1;
168
+ }
169
+
170
+ cur = last_lev[pos];
171
+ }
172
+
173
+ res = (pos << BITS_PER_LEVEL) + ctol(cur);
174
+ if (res >= hb->size) {
175
+ return -1;
176
+ }
177
+
178
+ res = res << hb->granularity;
179
+ if (res < start) {
180
+ assert(((start - res) >> hb->granularity) == 0);
181
+ return start;
182
+ }
183
+
184
+ return res;
185
+}
186
+
187
bool hbitmap_empty(const HBitmap *hb)
188
{
189
return hb->count == 0;
190
--
48
--
191
2.9.5
49
2.31.1
192
50
193
51
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
We can use copy_bitmap instead of sync_bitmap. copy_bitmap is
3
"qemu/typedefs.h" is enough for include/block/write-threshold.h header
4
initialized from sync_bitmap and it is more informative: we will not try
4
with forward declaration of BlockDriverState. Also drop extra includes
5
to process data, that is already in progress (by write notifier).
5
from block/write-threshold.c and tests/unit/test-write-threshold.c
6
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20210506090621.11848-9-vsementsov@virtuozzo.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
11
Message-id: 20171012135313.227864-6-vsementsov@virtuozzo.com
12
Signed-off-by: Jeff Cody <jcody@redhat.com>
13
---
11
---
14
block/backup.c | 55 +++++++++++++++++--------------------------------------
12
include/block/write-threshold.h | 2 +-
15
1 file changed, 17 insertions(+), 38 deletions(-)
13
block/write-threshold.c | 2 --
14
tests/unit/test-write-threshold.c | 1 -
15
3 files changed, 1 insertion(+), 4 deletions(-)
16
16
17
diff --git a/block/backup.c b/block/backup.c
17
diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/backup.c
19
--- a/include/block/write-threshold.h
20
+++ b/block/backup.c
20
+++ b/include/block/write-threshold.h
21
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
21
@@ -XXX,XX +XXX,XX @@
22
22
#ifndef BLOCK_WRITE_THRESHOLD_H
23
static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
23
#define BLOCK_WRITE_THRESHOLD_H
24
{
24
25
+ int ret;
25
-#include "block/block_int.h"
26
bool error_is_read;
26
+#include "qemu/typedefs.h"
27
- int ret = 0;
27
28
- int clusters_per_iter;
28
/*
29
- uint32_t granularity;
29
* bdrv_write_threshold_set:
30
- int64_t offset;
30
diff --git a/block/write-threshold.c b/block/write-threshold.c
31
int64_t cluster;
31
index XXXXXXX..XXXXXXX 100644
32
- int64_t end;
32
--- a/block/write-threshold.c
33
- BdrvDirtyBitmapIter *dbi;
33
+++ b/block/write-threshold.c
34
+ HBitmapIter hbi;
34
@@ -XXX,XX +XXX,XX @@
35
35
36
- granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
36
#include "qemu/osdep.h"
37
- clusters_per_iter = MAX((granularity / job->cluster_size), 1);
37
#include "block/block_int.h"
38
- dbi = bdrv_dirty_iter_new(job->sync_bitmap);
38
-#include "qemu/coroutine.h"
39
-
39
#include "block/write-threshold.h"
40
- /* Find the next dirty sector(s) */
40
-#include "qemu/notify.h"
41
- while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
41
#include "qapi/error.h"
42
- cluster = offset / job->cluster_size;
42
#include "qapi/qapi-commands-block-core.h"
43
-
43
#include "qapi/qapi-events-block-core.h"
44
- for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
44
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
45
- do {
45
index XXXXXXX..XXXXXXX 100644
46
- if (yield_and_check(job)) {
46
--- a/tests/unit/test-write-threshold.c
47
- goto out;
47
+++ b/tests/unit/test-write-threshold.c
48
- }
48
@@ -XXX,XX +XXX,XX @@
49
- ret = backup_do_cow(job, cluster * job->cluster_size,
49
*/
50
- job->cluster_size, &error_is_read,
50
51
- false);
51
#include "qemu/osdep.h"
52
- if ((ret < 0) &&
52
-#include "qapi/error.h"
53
- backup_error_action(job, error_is_read, -ret) ==
53
#include "block/block_int.h"
54
- BLOCK_ERROR_ACTION_REPORT) {
54
#include "block/write-threshold.h"
55
- goto out;
55
56
- }
57
- } while (ret < 0);
58
- }
59
-
60
- /* If the bitmap granularity is smaller than the backup granularity,
61
- * we need to advance the iterator pointer to the next cluster. */
62
- if (granularity < job->cluster_size) {
63
- bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
64
- }
65
+ hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
66
+ while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
67
+ do {
68
+ if (yield_and_check(job)) {
69
+ return 0;
70
+ }
71
+ ret = backup_do_cow(job, cluster * job->cluster_size,
72
+ job->cluster_size, &error_is_read, false);
73
+ if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
74
+ BLOCK_ERROR_ACTION_REPORT)
75
+ {
76
+ return ret;
77
+ }
78
+ } while (ret < 0);
79
}
80
81
-out:
82
- bdrv_dirty_iter_free(dbi);
83
- return ret;
84
+ return 0;
85
}
86
87
/* init copy_bitmap from sync_bitmap */
88
--
56
--
89
2.9.5
57
2.31.1
90
58
91
59
diff view generated by jsdifflib