1
The following changes since commit 464588675455afda2899e20a0b120e4075de50c7:
1
The following changes since commit 19b599f7664b2ebfd0f405fb79c14dd241557452:
2
2
3
Merge remote-tracking branch 'remotes/sstabellini/tags/xen-20170627-tag' into staging (2017-06-29 11:45:01 +0100)
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-error-2018-08-27-v2' into staging (2018-08-27 16:44:20 +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/stefanha/qemu.git tags/block-pull-request
7
https://git.xanclic.moe/XanClic/qemu.git tags/pull-block-2018-08-31-v2
8
8
9
for you to fetch changes up to c324fd0a39cee43c13f6d1fb34f74fc5e2fb007b:
9
for you to fetch changes up to e21a1c9831fc80ae3f3c1affdfa43350035d8588:
10
10
11
virtio-pci: use ioeventfd even when KVM is disabled (2017-06-30 11:03:45 +0100)
11
jobs: remove job_defer_to_main_loop (2018-08-31 16:28:33 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
15
- (Block) job exit refactoring, part 1
16
(removing job_defer_to_main_loop())
17
- test-bdrv-drain leak fix
14
18
15
----------------------------------------------------------------
19
----------------------------------------------------------------
20
John Snow (9):
21
jobs: change start callback to run callback
22
jobs: canonize Error object
23
jobs: add exit shim
24
block/commit: utilize job_exit shim
25
block/mirror: utilize job_exit shim
26
jobs: utilize job_exit shim
27
block/backup: make function variables consistently named
28
jobs: remove ret argument to job_completed; privatize it
29
jobs: remove job_defer_to_main_loop
16
30
17
Stefan Hajnoczi (7):
31
Marc-André Lureau (1):
18
virtio-blk: trace vdev so devices can be distinguished
32
tests: fix bdrv-drain leak
19
libqos: fix typo in virtio.h QVirtQueue->used comment
20
libqos: add virtio used ring support
21
tests: fix virtio-scsi-test ISR dependence
22
tests: fix virtio-blk-test ISR dependence
23
tests: fix virtio-net-test ISR dependence
24
virtio-pci: use ioeventfd even when KVM is disabled
25
33
26
tests/libqos/virtio.h | 8 ++++++-
34
include/qemu/job.h | 70 ++++++++++++++++-----------------
27
hw/block/virtio-blk.c | 12 ++++++----
35
block/backup.c | 81 ++++++++++++++++-----------------------
28
hw/virtio/virtio-pci.c | 2 +-
36
block/commit.c | 29 +++++---------
29
tests/libqos/virtio.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
37
block/create.c | 19 +++------
30
tests/virtio-blk-test.c | 27 ++++++++++++++--------
38
block/mirror.c | 39 ++++++++-----------
31
tests/virtio-net-test.c | 6 ++---
39
block/stream.c | 29 ++++++--------
32
tests/virtio-scsi-test.c | 2 +-
40
job-qmp.c | 5 ++-
33
hw/block/trace-events | 10 ++++----
41
job.c | 73 ++++++++++++-----------------------
34
8 files changed, 101 insertions(+), 26 deletions(-)
42
tests/test-bdrv-drain.c | 14 +++----
43
tests/test-blockjob-txn.c | 25 +++++-------
44
tests/test-blockjob.c | 17 ++++----
45
trace-events | 2 +-
46
12 files changed, 161 insertions(+), 242 deletions(-)
35
47
36
--
48
--
37
2.9.4
49
2.17.1
38
50
39
51
diff view generated by jsdifflib
1
Old kvm.ko versions only supported a tiny number of ioeventfds so
1
From: Marc-André Lureau <marcandre.lureau@redhat.com>
2
virtio-pci avoids ioeventfds when kvm_has_many_ioeventfds() returns 0.
3
2
4
Do not check kvm_has_many_ioeventfds() when KVM is disabled since it
3
Spotted by ASAN:
5
always returns 0. Since commit 8c56c1a592b5092d91da8d8943c17777d6462a6f
6
("memory: emulate ioeventfd") it has been possible to use ioeventfds in
7
qtest or TCG mode.
8
4
9
This patch makes -device virtio-blk-pci,iothread=iothread0 work even
5
=================================================================
10
when KVM is disabled.
6
==5378==ERROR: LeakSanitizer: detected memory leaks
11
7
12
I have tested that virtio-blk-pci works under TCG both with and without
8
Direct leak of 65536 byte(s) in 1 object(s) allocated from:
13
iothread.
9
#0 0x7f788f83bc48 in malloc (/lib64/libasan.so.5+0xeec48)
10
#1 0x7f788c9923c5 in g_malloc (/lib64/libglib-2.0.so.0+0x523c5)
11
#2 0x5622a1fe37bc in coroutine_trampoline /home/elmarco/src/qq/util/coroutine-ucontext.c:116
12
#3 0x7f788a15d75f in __correctly_grouped_prefixwc (/lib64/libc.so.6+0x4c75f)
14
13
15
This patch fixes qemu-iotests 068, which was accidentally merged early
14
(Broken in commit 4c8158e359d.)
16
despite the dependency on ioeventfd.
17
15
18
Cc: Michael S. Tsirkin <mst@redhat.com>
16
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-id: 20180809114417.28718-3-marcandre.lureau@redhat.com
20
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Fam Zheng <famz@redhat.com>
22
Tested-by: Eric Blake <eblake@redhat.com>
23
Tested-by: Kevin Wolf <kwolf@redhat.com>
24
Message-id: 20170628184724.21378-7-stefanha@redhat.com
25
Message-id: 20170615163813.7255-2-stefanha@redhat.com
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
---
19
---
28
hw/virtio/virtio-pci.c | 2 +-
20
tests/test-bdrv-drain.c | 1 +
29
1 file changed, 1 insertion(+), 1 deletion(-)
21
1 file changed, 1 insertion(+)
30
22
31
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
23
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
32
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/virtio/virtio-pci.c
25
--- a/tests/test-bdrv-drain.c
34
+++ b/hw/virtio/virtio-pci.c
26
+++ b/tests/test-bdrv-drain.c
35
@@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
36
bool pcie_port = pci_bus_is_express(pci_dev->bus) &&
37
!pci_bus_is_root(pci_dev->bus);
38
39
- if (!kvm_has_many_ioeventfds()) {
40
+ if (kvm_enabled() && !kvm_has_many_ioeventfds()) {
41
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
42
}
28
}
43
29
30
dbdd->done = true;
31
+ g_free(buffer);
32
}
33
34
/**
44
--
35
--
45
2.9.4
36
2.17.1
46
37
47
38
diff view generated by jsdifflib
New patch
1
1
From: John Snow <jsnow@redhat.com>
2
3
Presently we codify the entry point for a job as the "start" callback,
4
but a more apt name would be "run" to clarify the idea that when this
5
function returns we consider the job to have "finished," except for
6
any cleanup which occurs in separate callbacks later.
7
8
As part of this clarification, change the signature to include an error
9
object and a return code. The error ptr is not yet used, and the return
10
code while captured, will be overwritten by actions in the job_completed
11
function.
12
13
Signed-off-by: John Snow <jsnow@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-id: 20180830015734.19765-2-jsnow@redhat.com
16
Reviewed-by: Jeff Cody <jcody@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
include/qemu/job.h | 2 +-
20
block/backup.c | 7 ++++---
21
block/commit.c | 7 ++++---
22
block/create.c | 8 +++++---
23
block/mirror.c | 10 ++++++----
24
block/stream.c | 7 ++++---
25
job.c | 6 +++---
26
tests/test-bdrv-drain.c | 7 ++++---
27
tests/test-blockjob-txn.c | 16 ++++++++--------
28
tests/test-blockjob.c | 7 ++++---
29
10 files changed, 43 insertions(+), 34 deletions(-)
30
31
diff --git a/include/qemu/job.h b/include/qemu/job.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/qemu/job.h
34
+++ b/include/qemu/job.h
35
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
36
JobType job_type;
37
38
/** Mandatory: Entrypoint for the Coroutine. */
39
- CoroutineEntry *start;
40
+ int coroutine_fn (*run)(Job *job, Error **errp);
41
42
/**
43
* If the callback is not NULL, it will be invoked when the job transitions
44
diff --git a/block/backup.c b/block/backup.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/backup.c
47
+++ b/block/backup.c
48
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
49
bdrv_dirty_iter_free(dbi);
50
}
51
52
-static void coroutine_fn backup_run(void *opaque)
53
+static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
54
{
55
- BackupBlockJob *job = opaque;
56
+ BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
57
BackupCompleteData *data;
58
BlockDriverState *bs = blk_bs(job->common.blk);
59
int64_t offset, nb_clusters;
60
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn backup_run(void *opaque)
61
data = g_malloc(sizeof(*data));
62
data->ret = ret;
63
job_defer_to_main_loop(&job->common.job, backup_complete, data);
64
+ return ret;
65
}
66
67
static const BlockJobDriver backup_job_driver = {
68
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
69
.free = block_job_free,
70
.user_resume = block_job_user_resume,
71
.drain = block_job_drain,
72
- .start = backup_run,
73
+ .run = backup_run,
74
.commit = backup_commit,
75
.abort = backup_abort,
76
.clean = backup_clean,
77
diff --git a/block/commit.c b/block/commit.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/commit.c
80
+++ b/block/commit.c
81
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
82
bdrv_unref(top);
83
}
84
85
-static void coroutine_fn commit_run(void *opaque)
86
+static int coroutine_fn commit_run(Job *job, Error **errp)
87
{
88
- CommitBlockJob *s = opaque;
89
+ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
90
CommitCompleteData *data;
91
int64_t offset;
92
uint64_t delay_ns = 0;
93
@@ -XXX,XX +XXX,XX @@ out:
94
data = g_malloc(sizeof(*data));
95
data->ret = ret;
96
job_defer_to_main_loop(&s->common.job, commit_complete, data);
97
+ return ret;
98
}
99
100
static const BlockJobDriver commit_job_driver = {
101
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
102
.free = block_job_free,
103
.user_resume = block_job_user_resume,
104
.drain = block_job_drain,
105
- .start = commit_run,
106
+ .run = commit_run,
107
},
108
};
109
110
diff --git a/block/create.c b/block/create.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/create.c
113
+++ b/block/create.c
114
@@ -XXX,XX +XXX,XX @@ static void blockdev_create_complete(Job *job, void *opaque)
115
job_completed(job, s->ret, s->err);
116
}
117
118
-static void coroutine_fn blockdev_create_run(void *opaque)
119
+static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
120
{
121
- BlockdevCreateJob *s = opaque;
122
+ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
123
124
job_progress_set_remaining(&s->common, 1);
125
s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
126
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blockdev_create_run(void *opaque)
127
128
qapi_free_BlockdevCreateOptions(s->opts);
129
job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
130
+
131
+ return s->ret;
132
}
133
134
static const JobDriver blockdev_create_job_driver = {
135
.instance_size = sizeof(BlockdevCreateJob),
136
.job_type = JOB_TYPE_CREATE,
137
- .start = blockdev_create_run,
138
+ .run = blockdev_create_run,
139
};
140
141
void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
142
diff --git a/block/mirror.c b/block/mirror.c
143
index XXXXXXX..XXXXXXX 100644
144
--- a/block/mirror.c
145
+++ b/block/mirror.c
146
@@ -XXX,XX +XXX,XX @@ static int mirror_flush(MirrorBlockJob *s)
147
return ret;
148
}
149
150
-static void coroutine_fn mirror_run(void *opaque)
151
+static int coroutine_fn mirror_run(Job *job, Error **errp)
152
{
153
- MirrorBlockJob *s = opaque;
154
+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
155
MirrorExitData *data;
156
BlockDriverState *bs = s->mirror_top_bs->backing->bs;
157
BlockDriverState *target_bs = blk_bs(s->target);
158
@@ -XXX,XX +XXX,XX @@ immediate_exit:
159
if (need_drain) {
160
bdrv_drained_begin(bs);
161
}
162
+
163
job_defer_to_main_loop(&s->common.job, mirror_exit, data);
164
+ return ret;
165
}
166
167
static void mirror_complete(Job *job, Error **errp)
168
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
169
.free = block_job_free,
170
.user_resume = block_job_user_resume,
171
.drain = block_job_drain,
172
- .start = mirror_run,
173
+ .run = mirror_run,
174
.pause = mirror_pause,
175
.complete = mirror_complete,
176
},
177
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
178
.free = block_job_free,
179
.user_resume = block_job_user_resume,
180
.drain = block_job_drain,
181
- .start = mirror_run,
182
+ .run = mirror_run,
183
.pause = mirror_pause,
184
.complete = mirror_complete,
185
},
186
diff --git a/block/stream.c b/block/stream.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/block/stream.c
189
+++ b/block/stream.c
190
@@ -XXX,XX +XXX,XX @@ out:
191
g_free(data);
192
}
193
194
-static void coroutine_fn stream_run(void *opaque)
195
+static int coroutine_fn stream_run(Job *job, Error **errp)
196
{
197
- StreamBlockJob *s = opaque;
198
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
199
StreamCompleteData *data;
200
BlockBackend *blk = s->common.blk;
201
BlockDriverState *bs = blk_bs(blk);
202
@@ -XXX,XX +XXX,XX @@ out:
203
data = g_malloc(sizeof(*data));
204
data->ret = ret;
205
job_defer_to_main_loop(&s->common.job, stream_complete, data);
206
+ return ret;
207
}
208
209
static const BlockJobDriver stream_job_driver = {
210
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
211
.instance_size = sizeof(StreamBlockJob),
212
.job_type = JOB_TYPE_STREAM,
213
.free = block_job_free,
214
- .start = stream_run,
215
+ .run = stream_run,
216
.user_resume = block_job_user_resume,
217
.drain = block_job_drain,
218
},
219
diff --git a/job.c b/job.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/job.c
222
+++ b/job.c
223
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
224
{
225
Job *job = opaque;
226
227
- assert(job && job->driver && job->driver->start);
228
+ assert(job && job->driver && job->driver->run);
229
job_pause_point(job);
230
- job->driver->start(job);
231
+ job->ret = job->driver->run(job, NULL);
232
}
233
234
235
void job_start(Job *job)
236
{
237
assert(job && !job_started(job) && job->paused &&
238
- job->driver && job->driver->start);
239
+ job->driver && job->driver->run);
240
job->co = qemu_coroutine_create(job_co_entry, job);
241
job->pause_count--;
242
job->busy = true;
243
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
244
index XXXXXXX..XXXXXXX 100644
245
--- a/tests/test-bdrv-drain.c
246
+++ b/tests/test-bdrv-drain.c
247
@@ -XXX,XX +XXX,XX @@ static void test_job_completed(Job *job, void *opaque)
248
job_completed(job, 0, NULL);
249
}
250
251
-static void coroutine_fn test_job_start(void *opaque)
252
+static int coroutine_fn test_job_run(Job *job, Error **errp)
253
{
254
- TestBlockJob *s = opaque;
255
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
256
257
job_transition_to_ready(&s->common.job);
258
while (!s->should_complete) {
259
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_job_start(void *opaque)
260
}
261
262
job_defer_to_main_loop(&s->common.job, test_job_completed, NULL);
263
+ return 0;
264
}
265
266
static void test_job_complete(Job *job, Error **errp)
267
@@ -XXX,XX +XXX,XX @@ BlockJobDriver test_job_driver = {
268
.free = block_job_free,
269
.user_resume = block_job_user_resume,
270
.drain = block_job_drain,
271
- .start = test_job_start,
272
+ .run = test_job_run,
273
.complete = test_job_complete,
274
},
275
};
276
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
277
index XXXXXXX..XXXXXXX 100644
278
--- a/tests/test-blockjob-txn.c
279
+++ b/tests/test-blockjob-txn.c
280
@@ -XXX,XX +XXX,XX @@ static void test_block_job_complete(Job *job, void *opaque)
281
bdrv_unref(bs);
282
}
283
284
-static void coroutine_fn test_block_job_run(void *opaque)
285
+static int coroutine_fn test_block_job_run(Job *job, Error **errp)
286
{
287
- TestBlockJob *s = opaque;
288
- BlockJob *job = &s->common;
289
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
290
291
while (s->iterations--) {
292
if (s->use_timer) {
293
- job_sleep_ns(&job->job, 0);
294
+ job_sleep_ns(job, 0);
295
} else {
296
- job_yield(&job->job);
297
+ job_yield(job);
298
}
299
300
- if (job_is_cancelled(&job->job)) {
301
+ if (job_is_cancelled(job)) {
302
break;
303
}
304
}
305
306
- job_defer_to_main_loop(&job->job, test_block_job_complete,
307
+ job_defer_to_main_loop(job, test_block_job_complete,
308
(void *)(intptr_t)s->rc);
309
+ return s->rc;
310
}
311
312
typedef struct {
313
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
314
.free = block_job_free,
315
.user_resume = block_job_user_resume,
316
.drain = block_job_drain,
317
- .start = test_block_job_run,
318
+ .run = test_block_job_run,
319
},
320
};
321
322
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
323
index XXXXXXX..XXXXXXX 100644
324
--- a/tests/test-blockjob.c
325
+++ b/tests/test-blockjob.c
326
@@ -XXX,XX +XXX,XX @@ static void cancel_job_complete(Job *job, Error **errp)
327
s->should_complete = true;
328
}
329
330
-static void coroutine_fn cancel_job_start(void *opaque)
331
+static int coroutine_fn cancel_job_run(Job *job, Error **errp)
332
{
333
- CancelJob *s = opaque;
334
+ CancelJob *s = container_of(job, CancelJob, common.job);
335
336
while (!s->should_complete) {
337
if (job_is_cancelled(&s->common.job)) {
338
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn cancel_job_start(void *opaque)
339
340
defer:
341
job_defer_to_main_loop(&s->common.job, cancel_job_completed, s);
342
+ return 0;
343
}
344
345
static const BlockJobDriver test_cancel_driver = {
346
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_cancel_driver = {
347
.free = block_job_free,
348
.user_resume = block_job_user_resume,
349
.drain = block_job_drain,
350
- .start = cancel_job_start,
351
+ .run = cancel_job_run,
352
.complete = cancel_job_complete,
353
},
354
};
355
--
356
2.17.1
357
358
diff view generated by jsdifflib
New patch
1
1
From: John Snow <jsnow@redhat.com>
2
3
Jobs presently use both an Error object in the case of the create job,
4
and char strings in the case of generic errors elsewhere.
5
6
Unify the two paths as just j->err, and remove the extra argument from
7
job_completed. The integer error code for job_completed is kept for now,
8
to be removed shortly in a separate patch.
9
10
Signed-off-by: John Snow <jsnow@redhat.com>
11
Message-id: 20180830015734.19765-3-jsnow@redhat.com
12
[mreitz: Dropped a superfluous g_strdup()]
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
include/qemu/job.h | 14 ++++++++------
17
block/backup.c | 2 +-
18
block/commit.c | 2 +-
19
block/create.c | 5 ++---
20
block/mirror.c | 2 +-
21
block/stream.c | 2 +-
22
job-qmp.c | 5 +++--
23
job.c | 18 ++++++------------
24
tests/test-bdrv-drain.c | 2 +-
25
tests/test-blockjob-txn.c | 2 +-
26
tests/test-blockjob.c | 2 +-
27
11 files changed, 26 insertions(+), 30 deletions(-)
28
29
diff --git a/include/qemu/job.h b/include/qemu/job.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/qemu/job.h
32
+++ b/include/qemu/job.h
33
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
34
/** Estimated progress_current value at the completion of the job */
35
int64_t progress_total;
36
37
- /** Error string for a failed job (NULL if, and only if, job->ret == 0) */
38
- char *error;
39
-
40
/** ret code passed to job_completed. */
41
int ret;
42
43
+ /**
44
+ * Error object for a failed job.
45
+ * If job->ret is nonzero and an error object was not set, it will be set
46
+ * to strerror(-job->ret) during job_completed.
47
+ */
48
+ Error *err;
49
+
50
/** The completion function that will be called when the job completes. */
51
BlockCompletionFunc *cb;
52
53
@@ -XXX,XX +XXX,XX @@ void job_transition_to_ready(Job *job);
54
/**
55
* @job: The job being completed.
56
* @ret: The status code.
57
- * @error: The error message for a failing job (only with @ret < 0). If @ret is
58
- * negative, but NULL is given for @error, strerror() is used.
59
*
60
* Marks @job as completed. If @ret is non-zero, the job transaction it is part
61
* of is aborted. If @ret is zero, the job moves into the WAITING state. If it
62
* is the last job to complete in its transaction, all jobs in the transaction
63
* move from WAITING to PENDING.
64
*/
65
-void job_completed(Job *job, int ret, Error *error);
66
+void job_completed(Job *job, int ret);
67
68
/** Asynchronously complete the specified @job. */
69
void job_complete(Job *job, Error **errp);
70
diff --git a/block/backup.c b/block/backup.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/backup.c
73
+++ b/block/backup.c
74
@@ -XXX,XX +XXX,XX @@ static void backup_complete(Job *job, void *opaque)
75
{
76
BackupCompleteData *data = opaque;
77
78
- job_completed(job, data->ret, NULL);
79
+ job_completed(job, data->ret);
80
g_free(data);
81
}
82
83
diff --git a/block/commit.c b/block/commit.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/block/commit.c
86
+++ b/block/commit.c
87
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
88
* bdrv_set_backing_hd() to fail. */
89
block_job_remove_all_bdrv(bjob);
90
91
- job_completed(job, ret, NULL);
92
+ job_completed(job, ret);
93
g_free(data);
94
95
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
96
diff --git a/block/create.c b/block/create.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block/create.c
99
+++ b/block/create.c
100
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevCreateJob {
101
BlockDriver *drv;
102
BlockdevCreateOptions *opts;
103
int ret;
104
- Error *err;
105
} BlockdevCreateJob;
106
107
static void blockdev_create_complete(Job *job, void *opaque)
108
{
109
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
110
111
- job_completed(job, s->ret, s->err);
112
+ job_completed(job, s->ret);
113
}
114
115
static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
116
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
117
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
118
119
job_progress_set_remaining(&s->common, 1);
120
- s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
121
+ s->ret = s->drv->bdrv_co_create(s->opts, errp);
122
job_progress_update(&s->common, 1);
123
124
qapi_free_BlockdevCreateOptions(s->opts);
125
diff --git a/block/mirror.c b/block/mirror.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/block/mirror.c
128
+++ b/block/mirror.c
129
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
130
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
131
132
bs_opaque->job = NULL;
133
- job_completed(job, data->ret, NULL);
134
+ job_completed(job, data->ret);
135
136
g_free(data);
137
bdrv_drained_end(src);
138
diff --git a/block/stream.c b/block/stream.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/stream.c
141
+++ b/block/stream.c
142
@@ -XXX,XX +XXX,XX @@ out:
143
}
144
145
g_free(s->backing_file_str);
146
- job_completed(job, data->ret, NULL);
147
+ job_completed(job, data->ret);
148
g_free(data);
149
}
150
151
diff --git a/job-qmp.c b/job-qmp.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/job-qmp.c
154
+++ b/job-qmp.c
155
@@ -XXX,XX +XXX,XX @@ static JobInfo *job_query_single(Job *job, Error **errp)
156
.status = job->status,
157
.current_progress = job->progress_current,
158
.total_progress = job->progress_total,
159
- .has_error = !!job->error,
160
- .error = g_strdup(job->error),
161
+ .has_error = !!job->err,
162
+ .error = job->err ? \
163
+ g_strdup(error_get_pretty(job->err)) : NULL,
164
};
165
166
return info;
167
diff --git a/job.c b/job.c
168
index XXXXXXX..XXXXXXX 100644
169
--- a/job.c
170
+++ b/job.c
171
@@ -XXX,XX +XXX,XX @@ void job_unref(Job *job)
172
173
QLIST_REMOVE(job, job_list);
174
175
- g_free(job->error);
176
+ error_free(job->err);
177
g_free(job->id);
178
g_free(job);
179
}
180
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
181
182
assert(job && job->driver && job->driver->run);
183
job_pause_point(job);
184
- job->ret = job->driver->run(job, NULL);
185
+ job->ret = job->driver->run(job, &job->err);
186
}
187
188
189
@@ -XXX,XX +XXX,XX @@ static void job_update_rc(Job *job)
190
job->ret = -ECANCELED;
191
}
192
if (job->ret) {
193
- if (!job->error) {
194
- job->error = g_strdup(strerror(-job->ret));
195
+ if (!job->err) {
196
+ error_setg(&job->err, "%s", strerror(-job->ret));
197
}
198
job_state_transition(job, JOB_STATUS_ABORTING);
199
}
200
@@ -XXX,XX +XXX,XX @@ static void job_completed_txn_success(Job *job)
201
}
202
}
203
204
-void job_completed(Job *job, int ret, Error *error)
205
+void job_completed(Job *job, int ret)
206
{
207
assert(job && job->txn && !job_is_completed(job));
208
209
job->ret = ret;
210
- if (error) {
211
- assert(job->ret < 0);
212
- job->error = g_strdup(error_get_pretty(error));
213
- error_free(error);
214
- }
215
-
216
job_update_rc(job);
217
trace_job_completed(job, ret, job->ret);
218
if (job->ret) {
219
@@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force)
220
}
221
job_cancel_async(job, force);
222
if (!job_started(job)) {
223
- job_completed(job, -ECANCELED, NULL);
224
+ job_completed(job, -ECANCELED);
225
} else if (job->deferred_to_main_loop) {
226
job_completed_txn_abort(job);
227
} else {
228
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
229
index XXXXXXX..XXXXXXX 100644
230
--- a/tests/test-bdrv-drain.c
231
+++ b/tests/test-bdrv-drain.c
232
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
233
234
static void test_job_completed(Job *job, void *opaque)
235
{
236
- job_completed(job, 0, NULL);
237
+ job_completed(job, 0);
238
}
239
240
static int coroutine_fn test_job_run(Job *job, Error **errp)
241
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
242
index XXXXXXX..XXXXXXX 100644
243
--- a/tests/test-blockjob-txn.c
244
+++ b/tests/test-blockjob-txn.c
245
@@ -XXX,XX +XXX,XX @@ static void test_block_job_complete(Job *job, void *opaque)
246
rc = -ECANCELED;
247
}
248
249
- job_completed(job, rc, NULL);
250
+ job_completed(job, rc);
251
bdrv_unref(bs);
252
}
253
254
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
255
index XXXXXXX..XXXXXXX 100644
256
--- a/tests/test-blockjob.c
257
+++ b/tests/test-blockjob.c
258
@@ -XXX,XX +XXX,XX @@ static void cancel_job_completed(Job *job, void *opaque)
259
{
260
CancelJob *s = opaque;
261
s->completed = true;
262
- job_completed(job, 0, NULL);
263
+ job_completed(job, 0);
264
}
265
266
static void cancel_job_complete(Job *job, Error **errp)
267
--
268
2.17.1
269
270
diff view generated by jsdifflib
1
Use the new used ring APIs instead of assuming ISR being set means the
1
From: John Snow <jsnow@redhat.com>
2
request has completed.
3
2
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
3
All jobs do the same thing when they leave their running loop:
5
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
4
- Store the return code in a structure
6
Reviewed-by: Fam Zheng <famz@redhat.com>
5
- wait to receive this structure in the main thread
7
Tested-by: Eric Blake <eblake@redhat.com>
6
- signal job completion via job_completed
8
Tested-by: Kevin Wolf <kwolf@redhat.com>
7
9
Message-id: 20170628184724.21378-5-stefanha@redhat.com
8
Few jobs do anything beyond exactly this. Consolidate this exit
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
logic for a net reduction in SLOC.
10
11
More seriously, when we utilize job_defer_to_main_loop_bh to call
12
a function that calls job_completed, job_finalize_single will run
13
in a context where it has recursively taken the aio_context lock,
14
which can cause hangs if it puts down a reference that causes a flush.
15
16
You can observe this in practice by looking at mirror_exit's careful
17
placement of job_completed and bdrv_unref calls.
18
19
If we centralize job exiting, we can signal job completion from outside
20
of the aio_context, which should allow for job cleanup code to run with
21
only one lock, which makes cleanup callbacks less tricky to write.
22
23
Signed-off-by: John Snow <jsnow@redhat.com>
24
Reviewed-by: Max Reitz <mreitz@redhat.com>
25
Message-id: 20180830015734.19765-4-jsnow@redhat.com
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
28
---
12
tests/virtio-blk-test.c | 27 +++++++++++++++++----------
29
include/qemu/job.h | 11 +++++++++++
13
1 file changed, 17 insertions(+), 10 deletions(-)
30
job.c | 18 ++++++++++++++++++
31
2 files changed, 29 insertions(+)
14
32
15
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
33
diff --git a/include/qemu/job.h b/include/qemu/job.h
16
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/virtio-blk-test.c
35
--- a/include/qemu/job.h
18
+++ b/tests/virtio-blk-test.c
36
+++ b/include/qemu/job.h
19
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
37
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
20
38
*/
21
qvirtqueue_kick(dev, vq, free_head);
39
void (*drain)(Job *job);
22
40
23
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
41
+ /**
24
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
42
+ * If the callback is not NULL, exit will be invoked from the main thread
25
status = readb(req_addr + 528);
43
+ * when the job's coroutine has finished, but before transactional
26
g_assert_cmpint(status, ==, 0);
44
+ * convergence; before @prepare or @abort.
27
45
+ *
28
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
46
+ * FIXME TODO: This callback is only temporary to transition remaining jobs
29
47
+ * to prepare/commit/abort/clean callbacks and will be removed before 3.1.
30
qvirtqueue_kick(dev, vq, free_head);
48
+ * is released.
31
49
+ */
32
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
50
+ void (*exit)(Job *job);
33
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
51
+
34
status = readb(req_addr + 528);
52
/**
35
g_assert_cmpint(status, ==, 0);
53
* If the callback is not NULL, prepare will be invoked when all the jobs
36
54
* belonging to the same transaction complete; or upon this job's completion
37
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
55
diff --git a/job.c b/job.c
38
qvirtqueue_add(vq, req_addr + 528, 1, true, false);
56
index XXXXXXX..XXXXXXX 100644
39
qvirtqueue_kick(dev, vq, free_head);
57
--- a/job.c
40
58
+++ b/job.c
41
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
59
@@ -XXX,XX +XXX,XX @@ void job_drain(Job *job)
42
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
60
}
43
status = readb(req_addr + 528);
61
}
44
g_assert_cmpint(status, ==, 0);
62
45
63
+static void job_exit(void *opaque)
46
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
64
+{
47
65
+ Job *job = (Job *)opaque;
48
qvirtqueue_kick(dev, vq, free_head);
66
+ AioContext *aio_context = job->aio_context;
49
67
+
50
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
68
+ if (job->driver->exit) {
51
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
69
+ aio_context_acquire(aio_context);
52
status = readb(req_addr + 528);
70
+ job->driver->exit(job);
53
g_assert_cmpint(status, ==, 0);
71
+ aio_context_release(aio_context);
54
72
+ }
55
@@ -XXX,XX +XXX,XX @@ static void pci_indirect(void)
73
+ job_completed(job, job->ret);
56
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
74
+}
57
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
75
58
76
/**
59
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
77
* All jobs must allow a pause point before entering their job proper. This
60
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
78
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
61
QVIRTIO_BLK_TIMEOUT_US);
79
assert(job && job->driver && job->driver->run);
62
status = readb(req_addr + 528);
80
job_pause_point(job);
63
g_assert_cmpint(status, ==, 0);
81
job->ret = job->driver->run(job, &job->err);
64
@@ -XXX,XX +XXX,XX @@ static void pci_indirect(void)
82
+ if (!job->deferred_to_main_loop) {
65
free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
83
+ job->deferred_to_main_loop = true;
66
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
84
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
67
85
+ job_exit,
68
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
86
+ job);
69
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
87
+ }
70
QVIRTIO_BLK_TIMEOUT_US);
88
}
71
status = readb(req_addr + 528);
89
72
g_assert_cmpint(status, ==, 0);
90
73
@@ -XXX,XX +XXX,XX @@ static void pci_msix(void)
74
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
75
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
76
77
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
78
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
79
QVIRTIO_BLK_TIMEOUT_US);
80
81
status = readb(req_addr + 528);
82
@@ -XXX,XX +XXX,XX @@ static void pci_msix(void)
83
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
84
85
86
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
87
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
88
QVIRTIO_BLK_TIMEOUT_US);
89
90
status = readb(req_addr + 528);
91
@@ -XXX,XX +XXX,XX @@ static void pci_idx(void)
92
uint64_t capacity;
93
uint32_t features;
94
uint32_t free_head;
95
+ uint32_t write_head;
96
+ uint32_t desc_idx;
97
uint8_t status;
98
char *data;
99
100
@@ -XXX,XX +XXX,XX @@ static void pci_idx(void)
101
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
102
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
103
104
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq, QVIRTIO_BLK_TIMEOUT_US);
105
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
106
+ QVIRTIO_BLK_TIMEOUT_US);
107
108
/* Write request */
109
req.type = VIRTIO_BLK_T_OUT;
110
@@ -XXX,XX +XXX,XX @@ static void pci_idx(void)
111
qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
112
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
113
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
114
+ write_head = free_head;
115
116
/* No notification expected */
117
status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
118
@@ -XXX,XX +XXX,XX @@ static void pci_idx(void)
119
120
qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
121
122
- qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
123
+ /* We get just one notification for both requests */
124
+ qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head,
125
QVIRTIO_BLK_TIMEOUT_US);
126
+ g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx));
127
+ g_assert_cmpint(desc_idx, ==, free_head);
128
129
status = readb(req_addr + 528);
130
g_assert_cmpint(status, ==, 0);
131
--
91
--
132
2.9.4
92
2.17.1
133
93
134
94
diff view generated by jsdifflib
1
Use the new used ring APIs instead of assuming ISR being set means the
1
From: John Snow <jsnow@redhat.com>
2
request has completed.
3
2
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Change the manual deferment to commit_complete into the implicit
5
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
4
callback to job_exit, renaming commit_complete to commit_exit.
6
Reviewed-by: Fam Zheng <famz@redhat.com>
5
7
Tested-by: Eric Blake <eblake@redhat.com>
6
This conversion does change the timing of when job_completed is
8
Tested-by: Kevin Wolf <kwolf@redhat.com>
7
called to after the bdrv_replace_node and bdrv_unref calls, which
9
Message-id: 20170628184724.21378-6-stefanha@redhat.com
8
could have implications for bjob->blk which will now be put down
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
after this cleanup.
10
11
Kevin highlights that we did not take any permissions for that backend
12
at job creation time, so it is safe to reorder these operations.
13
14
Signed-off-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-id: 20180830015734.19765-5-jsnow@redhat.com
17
Reviewed-by: Jeff Cody <jcody@redhat.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
19
---
12
tests/virtio-net-test.c | 6 +++---
20
block/commit.c | 22 +++++-----------------
13
1 file changed, 3 insertions(+), 3 deletions(-)
21
1 file changed, 5 insertions(+), 17 deletions(-)
14
22
15
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
23
diff --git a/block/commit.c b/block/commit.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/virtio-net-test.c
25
--- a/block/commit.c
18
+++ b/tests/virtio-net-test.c
26
+++ b/block/commit.c
19
@@ -XXX,XX +XXX,XX @@ static void rx_test(QVirtioDevice *dev,
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
20
ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
28
return 0;
21
g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
29
}
22
30
23
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_NET_TIMEOUT_US);
31
-typedef struct {
24
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US);
32
- int ret;
25
memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
33
-} CommitCompleteData;
26
g_assert_cmpstr(buffer, ==, "TEST");
34
-
27
35
-static void commit_complete(Job *job, void *opaque)
28
@@ -XXX,XX +XXX,XX @@ static void tx_test(QVirtioDevice *dev,
36
+static void commit_exit(Job *job)
29
free_head = qvirtqueue_add(vq, req_addr, 64, false, false);
37
{
30
qvirtqueue_kick(dev, vq, free_head);
38
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
31
39
BlockJob *bjob = &s->common;
32
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_NET_TIMEOUT_US);
40
- CommitCompleteData *data = opaque;
33
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US);
41
BlockDriverState *top = blk_bs(s->top);
34
guest_free(alloc, req_addr);
42
BlockDriverState *base = blk_bs(s->base);
35
43
BlockDriverState *commit_top_bs = s->commit_top_bs;
36
ret = qemu_recv(socket, &len, sizeof(len), 0);
44
- int ret = data->ret;
37
@@ -XXX,XX +XXX,XX @@ static void rx_stop_cont_test(QVirtioDevice *dev,
45
bool remove_commit_top_bs = false;
38
rsp = qmp("{ 'execute' : 'cont'}");
46
39
QDECREF(rsp);
47
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
40
48
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
41
- qvirtio_wait_queue_isr(dev, vq, QVIRTIO_NET_TIMEOUT_US);
49
* the normal backing chain can be restored. */
42
+ qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US);
50
blk_unref(s->base);
43
memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
51
44
g_assert_cmpstr(buffer, ==, "TEST");
52
- if (!job_is_cancelled(job) && ret == 0) {
53
+ if (!job_is_cancelled(job) && job->ret == 0) {
54
/* success */
55
- ret = bdrv_drop_intermediate(s->commit_top_bs, base,
56
- s->backing_file_str);
57
+ job->ret = bdrv_drop_intermediate(s->commit_top_bs, base,
58
+ s->backing_file_str);
59
} else {
60
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
61
* after the failed/cancelled commit job is gone? If we already wrote
62
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
63
* bdrv_set_backing_hd() to fail. */
64
block_job_remove_all_bdrv(bjob);
65
66
- job_completed(job, ret);
67
- g_free(data);
68
-
69
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
70
* filter driver from the backing chain. Do this as the final step so that
71
* the 'consistent read' permission can be granted. */
72
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
73
static int coroutine_fn commit_run(Job *job, Error **errp)
74
{
75
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
76
- CommitCompleteData *data;
77
int64_t offset;
78
uint64_t delay_ns = 0;
79
int ret = 0;
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
out:
82
qemu_vfree(buf);
83
84
- data = g_malloc(sizeof(*data));
85
- data->ret = ret;
86
- job_defer_to_main_loop(&s->common.job, commit_complete, data);
87
return ret;
88
}
89
90
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
91
.user_resume = block_job_user_resume,
92
.drain = block_job_drain,
93
.run = commit_run,
94
+ .exit = commit_exit,
95
},
96
};
45
97
46
--
98
--
47
2.9.4
99
2.17.1
48
100
49
101
diff view generated by jsdifflib
1
Existing tests do not touch the virtqueue used ring. Instead they poll
1
From: John Snow <jsnow@redhat.com>
2
the virtqueue ISR register and peek into their request's device-specific
3
status field.
4
2
5
It turns out that the virtqueue ISR register can be set to 1 more than
3
Change the manual deferment to mirror_exit into the implicit
6
once for a single notification (see commit
4
callback to job_exit and the mirror_exit callback.
7
83d768b5640946b7da55ce8335509df297e2c7cd "virtio: set ISR on dataplane
8
notifications"). This causes problems for tests that assume a 1:1
9
correspondence between the ISR being 1 and request completion.
10
5
11
Peeking at device-specific status fields is also problematic if the
6
This does change the order of some bdrv_unref calls and job_completed,
12
device has no field that can be abused for EINPROGRESS polling
7
but thanks to the new context in which we call .exit, this is safe to
13
semantics. This is the case if all the field's values may be set by the
8
defer the possible flushing of any nodes to the job_finalize_single
14
device; there's no magic constant left for polling.
9
cleanup stage.
15
10
16
It's time to process the used ring for completed requests, just like a
11
Signed-off-by: John Snow <jsnow@redhat.com>
17
real virtio guest driver. This patch adds the necessary APIs.
12
Message-id: 20180830015734.19765-6-jsnow@redhat.com
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Jeff Cody <jcody@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/mirror.c | 29 +++++++++++------------------
18
1 file changed, 11 insertions(+), 18 deletions(-)
18
19
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
diff --git a/block/mirror.c b/block/mirror.c
20
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
21
Reviewed-by: Fam Zheng <famz@redhat.com>
22
Tested-by: Eric Blake <eblake@redhat.com>
23
Tested-by: Kevin Wolf <kwolf@redhat.com>
24
Message-id: 20170628184724.21378-3-stefanha@redhat.com
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
26
---
27
tests/libqos/virtio.h | 6 ++++++
28
tests/libqos/virtio.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
29
2 files changed, 66 insertions(+)
30
31
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
32
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
33
--- a/tests/libqos/virtio.h
22
--- a/block/mirror.c
34
+++ b/tests/libqos/virtio.h
23
+++ b/block/mirror.c
35
@@ -XXX,XX +XXX,XX @@ typedef struct QVirtQueue {
24
@@ -XXX,XX +XXX,XX @@ static void mirror_wait_for_all_io(MirrorBlockJob *s)
36
uint32_t free_head;
37
uint32_t num_free;
38
uint32_t align;
39
+ uint16_t last_used_idx;
40
bool indirect;
41
bool event;
42
} QVirtQueue;
43
@@ -XXX,XX +XXX,XX @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d,
44
QVirtQueue *vq,
45
uint64_t addr,
46
gint64 timeout_us);
47
+void qvirtio_wait_used_elem(QVirtioDevice *d,
48
+ QVirtQueue *vq,
49
+ uint32_t desc_idx,
50
+ gint64 timeout_us);
51
void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us);
52
QVirtQueue *qvirtqueue_setup(QVirtioDevice *d,
53
QGuestAllocator *alloc, uint16_t index);
54
@@ -XXX,XX +XXX,XX @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write,
55
bool next);
56
uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect);
57
void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head);
58
+bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx);
59
60
void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx);
61
#endif
62
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/libqos/virtio.c
65
+++ b/tests/libqos/virtio.c
66
@@ -XXX,XX +XXX,XX @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d,
67
return val;
68
}
69
70
+/*
71
+ * qvirtio_wait_used_elem:
72
+ * @desc_idx: The next expected vq->desc[] index in the used ring
73
+ * @timeout_us: How many microseconds to wait before failing
74
+ *
75
+ * This function waits for the next completed request on the used ring.
76
+ */
77
+void qvirtio_wait_used_elem(QVirtioDevice *d,
78
+ QVirtQueue *vq,
79
+ uint32_t desc_idx,
80
+ gint64 timeout_us)
81
+{
82
+ gint64 start_time = g_get_monotonic_time();
83
+
84
+ for (;;) {
85
+ uint32_t got_desc_idx;
86
+
87
+ clock_step(100);
88
+
89
+ if (d->bus->get_queue_isr_status(d, vq) &&
90
+ qvirtqueue_get_buf(vq, &got_desc_idx)) {
91
+ g_assert_cmpint(got_desc_idx, ==, desc_idx);
92
+ return;
93
+ }
94
+
95
+ g_assert(g_get_monotonic_time() - start_time <= timeout_us);
96
+ }
97
+}
98
+
99
void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us)
100
{
101
gint64 start_time = g_get_monotonic_time();
102
@@ -XXX,XX +XXX,XX @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head)
103
}
25
}
104
}
26
}
105
27
106
+/*
28
-typedef struct {
107
+ * qvirtqueue_get_buf:
29
- int ret;
108
+ * @desc_idx: A pointer that is filled with the vq->desc[] index, may be NULL
30
-} MirrorExitData;
109
+ *
31
-
110
+ * This function gets the next used element if there is one ready.
32
-static void mirror_exit(Job *job, void *opaque)
111
+ *
33
+static void mirror_exit(Job *job)
112
+ * Returns: true if an element was ready, false otherwise
34
{
113
+ */
35
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
114
+bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx)
36
BlockJob *bjob = &s->common;
115
+{
37
- MirrorExitData *data = opaque;
116
+ uint16_t idx;
38
MirrorBDSOpaque *bs_opaque = s->mirror_top_bs->opaque;
39
AioContext *replace_aio_context = NULL;
40
BlockDriverState *src = s->mirror_top_bs->backing->bs;
41
BlockDriverState *target_bs = blk_bs(s->target);
42
BlockDriverState *mirror_top_bs = s->mirror_top_bs;
43
Error *local_err = NULL;
44
+ int ret = job->ret;
45
46
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
47
48
- /* Make sure that the source BDS doesn't go away before we called
49
- * job_completed(). */
50
+ /* Make sure that the source BDS doesn't go away during bdrv_replace_node,
51
+ * before we can call bdrv_drained_end */
52
bdrv_ref(src);
53
bdrv_ref(mirror_top_bs);
54
bdrv_ref(target_bs);
55
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
56
bdrv_set_backing_hd(target_bs, backing, &local_err);
57
if (local_err) {
58
error_report_err(local_err);
59
- data->ret = -EPERM;
60
+ ret = -EPERM;
61
}
62
}
63
}
64
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
65
aio_context_acquire(replace_aio_context);
66
}
67
68
- if (s->should_complete && data->ret == 0) {
69
+ if (s->should_complete && ret == 0) {
70
BlockDriverState *to_replace = src;
71
if (s->to_replace) {
72
to_replace = s->to_replace;
73
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
74
bdrv_drained_end(target_bs);
75
if (local_err) {
76
error_report_err(local_err);
77
- data->ret = -EPERM;
78
+ ret = -EPERM;
79
}
80
}
81
if (s->to_replace) {
82
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
83
blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
84
85
bs_opaque->job = NULL;
86
- job_completed(job, data->ret);
87
88
- g_free(data);
89
bdrv_drained_end(src);
90
bdrv_unref(mirror_top_bs);
91
bdrv_unref(src);
117
+
92
+
118
+ idx = readw(vq->used + offsetof(struct vring_used, idx));
93
+ job->ret = ret;
119
+ if (idx == vq->last_used_idx) {
94
}
120
+ return false;
95
121
+ }
96
static void mirror_throttle(MirrorBlockJob *s)
122
+
97
@@ -XXX,XX +XXX,XX @@ static int mirror_flush(MirrorBlockJob *s)
123
+ if (desc_idx) {
98
static int coroutine_fn mirror_run(Job *job, Error **errp)
124
+ uint64_t elem_addr;
125
+
126
+ elem_addr = vq->used +
127
+ offsetof(struct vring_used, ring) +
128
+ (vq->last_used_idx % vq->size) *
129
+ sizeof(struct vring_used_elem);
130
+ *desc_idx = readl(elem_addr + offsetof(struct vring_used_elem, id));
131
+ }
132
+
133
+ vq->last_used_idx++;
134
+ return true;
135
+}
136
+
137
void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx)
138
{
99
{
139
g_assert(vq->event);
100
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
101
- MirrorExitData *data;
102
BlockDriverState *bs = s->mirror_top_bs->backing->bs;
103
BlockDriverState *target_bs = blk_bs(s->target);
104
bool need_drain = true;
105
@@ -XXX,XX +XXX,XX @@ immediate_exit:
106
g_free(s->in_flight_bitmap);
107
bdrv_dirty_iter_free(s->dbi);
108
109
- data = g_malloc(sizeof(*data));
110
- data->ret = ret;
111
-
112
if (need_drain) {
113
bdrv_drained_begin(bs);
114
}
115
116
- job_defer_to_main_loop(&s->common.job, mirror_exit, data);
117
return ret;
118
}
119
120
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
121
.user_resume = block_job_user_resume,
122
.drain = block_job_drain,
123
.run = mirror_run,
124
+ .exit = mirror_exit,
125
.pause = mirror_pause,
126
.complete = mirror_complete,
127
},
128
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_active_job_driver = {
129
.user_resume = block_job_user_resume,
130
.drain = block_job_drain,
131
.run = mirror_run,
132
+ .exit = mirror_exit,
133
.pause = mirror_pause,
134
.complete = mirror_complete,
135
},
140
--
136
--
141
2.9.4
137
2.17.1
142
138
143
139
diff view generated by jsdifflib
New patch
1
1
From: John Snow <jsnow@redhat.com>
2
3
Utilize the job_exit shim by not calling job_defer_to_main_loop, and
4
where applicable, converting the deferred callback into the job_exit
5
callback.
6
7
This converts backup, stream, create, and the unit tests all at once.
8
Most of these jobs do not see any changes to the order in which they
9
clean up their resources, except the test-blockjob-txn test, which
10
now puts down its bs before job_completed is called.
11
12
This is safe for the same reason the reordering in the mirror job is
13
safe, because job_completed no longer runs under two locks, making
14
the unref safe even if it causes a flush.
15
16
Signed-off-by: John Snow <jsnow@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Message-id: 20180830015734.19765-7-jsnow@redhat.com
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/backup.c | 16 ----------------
22
block/create.c | 14 +++-----------
23
block/stream.c | 22 +++++++---------------
24
tests/test-bdrv-drain.c | 6 ------
25
tests/test-blockjob-txn.c | 11 ++---------
26
tests/test-blockjob.c | 10 ++++------
27
6 files changed, 16 insertions(+), 63 deletions(-)
28
29
diff --git a/block/backup.c b/block/backup.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/backup.c
32
+++ b/block/backup.c
33
@@ -XXX,XX +XXX,XX @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
34
}
35
}
36
37
-typedef struct {
38
- int ret;
39
-} BackupCompleteData;
40
-
41
-static void backup_complete(Job *job, void *opaque)
42
-{
43
- BackupCompleteData *data = opaque;
44
-
45
- job_completed(job, data->ret);
46
- g_free(data);
47
-}
48
-
49
static bool coroutine_fn yield_and_check(BackupBlockJob *job)
50
{
51
uint64_t delay_ns;
52
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
53
static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
54
{
55
BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
56
- BackupCompleteData *data;
57
BlockDriverState *bs = blk_bs(job->common.blk);
58
int64_t offset, nb_clusters;
59
int ret = 0;
60
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
61
qemu_co_rwlock_unlock(&job->flush_rwlock);
62
hbitmap_free(job->copy_bitmap);
63
64
- data = g_malloc(sizeof(*data));
65
- data->ret = ret;
66
- job_defer_to_main_loop(&job->common.job, backup_complete, data);
67
return ret;
68
}
69
70
diff --git a/block/create.c b/block/create.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/create.c
73
+++ b/block/create.c
74
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevCreateJob {
75
Job common;
76
BlockDriver *drv;
77
BlockdevCreateOptions *opts;
78
- int ret;
79
} BlockdevCreateJob;
80
81
-static void blockdev_create_complete(Job *job, void *opaque)
82
-{
83
- BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
84
-
85
- job_completed(job, s->ret);
86
-}
87
-
88
static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
89
{
90
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
91
+ int ret;
92
93
job_progress_set_remaining(&s->common, 1);
94
- s->ret = s->drv->bdrv_co_create(s->opts, errp);
95
+ ret = s->drv->bdrv_co_create(s->opts, errp);
96
job_progress_update(&s->common, 1);
97
98
qapi_free_BlockdevCreateOptions(s->opts);
99
- job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
100
101
- return s->ret;
102
+ return ret;
103
}
104
105
static const JobDriver blockdev_create_job_driver = {
106
diff --git a/block/stream.c b/block/stream.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/stream.c
109
+++ b/block/stream.c
110
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_populate(BlockBackend *blk,
111
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
112
}
113
114
-typedef struct {
115
- int ret;
116
-} StreamCompleteData;
117
-
118
-static void stream_complete(Job *job, void *opaque)
119
+static void stream_exit(Job *job)
120
{
121
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
122
BlockJob *bjob = &s->common;
123
- StreamCompleteData *data = opaque;
124
BlockDriverState *bs = blk_bs(bjob->blk);
125
BlockDriverState *base = s->base;
126
Error *local_err = NULL;
127
+ int ret = job->ret;
128
129
- if (!job_is_cancelled(job) && bs->backing && data->ret == 0) {
130
+ if (!job_is_cancelled(job) && bs->backing && ret == 0) {
131
const char *base_id = NULL, *base_fmt = NULL;
132
if (base) {
133
base_id = s->backing_file_str;
134
@@ -XXX,XX +XXX,XX @@ static void stream_complete(Job *job, void *opaque)
135
base_fmt = base->drv->format_name;
136
}
137
}
138
- data->ret = bdrv_change_backing_file(bs, base_id, base_fmt);
139
+ ret = bdrv_change_backing_file(bs, base_id, base_fmt);
140
bdrv_set_backing_hd(bs, base, &local_err);
141
if (local_err) {
142
error_report_err(local_err);
143
- data->ret = -EPERM;
144
+ ret = -EPERM;
145
goto out;
146
}
147
}
148
@@ -XXX,XX +XXX,XX @@ out:
149
}
150
151
g_free(s->backing_file_str);
152
- job_completed(job, data->ret);
153
- g_free(data);
154
+ job->ret = ret;
155
}
156
157
static int coroutine_fn stream_run(Job *job, Error **errp)
158
{
159
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
160
- StreamCompleteData *data;
161
BlockBackend *blk = s->common.blk;
162
BlockDriverState *bs = blk_bs(blk);
163
BlockDriverState *base = s->base;
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
165
166
out:
167
/* Modify backing chain and close BDSes in main loop */
168
- data = g_malloc(sizeof(*data));
169
- data->ret = ret;
170
- job_defer_to_main_loop(&s->common.job, stream_complete, data);
171
return ret;
172
}
173
174
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
175
.job_type = JOB_TYPE_STREAM,
176
.free = block_job_free,
177
.run = stream_run,
178
+ .exit = stream_exit,
179
.user_resume = block_job_user_resume,
180
.drain = block_job_drain,
181
},
182
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/tests/test-bdrv-drain.c
185
+++ b/tests/test-bdrv-drain.c
186
@@ -XXX,XX +XXX,XX @@ typedef struct TestBlockJob {
187
bool should_complete;
188
} TestBlockJob;
189
190
-static void test_job_completed(Job *job, void *opaque)
191
-{
192
- job_completed(job, 0);
193
-}
194
-
195
static int coroutine_fn test_job_run(Job *job, Error **errp)
196
{
197
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
198
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
199
job_pause_point(&s->common.job);
200
}
201
202
- job_defer_to_main_loop(&s->common.job, test_job_completed, NULL);
203
return 0;
204
}
205
206
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
207
index XXXXXXX..XXXXXXX 100644
208
--- a/tests/test-blockjob-txn.c
209
+++ b/tests/test-blockjob-txn.c
210
@@ -XXX,XX +XXX,XX @@ typedef struct {
211
int *result;
212
} TestBlockJob;
213
214
-static void test_block_job_complete(Job *job, void *opaque)
215
+static void test_block_job_exit(Job *job)
216
{
217
BlockJob *bjob = container_of(job, BlockJob, job);
218
BlockDriverState *bs = blk_bs(bjob->blk);
219
- int rc = (intptr_t)opaque;
220
221
- if (job_is_cancelled(job)) {
222
- rc = -ECANCELED;
223
- }
224
-
225
- job_completed(job, rc);
226
bdrv_unref(bs);
227
}
228
229
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn test_block_job_run(Job *job, Error **errp)
230
}
231
}
232
233
- job_defer_to_main_loop(job, test_block_job_complete,
234
- (void *)(intptr_t)s->rc);
235
return s->rc;
236
}
237
238
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
239
.user_resume = block_job_user_resume,
240
.drain = block_job_drain,
241
.run = test_block_job_run,
242
+ .exit = test_block_job_exit,
243
},
244
};
245
246
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
247
index XXXXXXX..XXXXXXX 100644
248
--- a/tests/test-blockjob.c
249
+++ b/tests/test-blockjob.c
250
@@ -XXX,XX +XXX,XX @@ typedef struct CancelJob {
251
bool completed;
252
} CancelJob;
253
254
-static void cancel_job_completed(Job *job, void *opaque)
255
+static void cancel_job_exit(Job *job)
256
{
257
- CancelJob *s = opaque;
258
+ CancelJob *s = container_of(job, CancelJob, common.job);
259
s->completed = true;
260
- job_completed(job, 0);
261
}
262
263
static void cancel_job_complete(Job *job, Error **errp)
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp)
265
266
while (!s->should_complete) {
267
if (job_is_cancelled(&s->common.job)) {
268
- goto defer;
269
+ return 0;
270
}
271
272
if (!job_is_ready(&s->common.job) && s->should_converge) {
273
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp)
274
job_sleep_ns(&s->common.job, 100000);
275
}
276
277
- defer:
278
- job_defer_to_main_loop(&s->common.job, cancel_job_completed, s);
279
return 0;
280
}
281
282
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_cancel_driver = {
283
.user_resume = block_job_user_resume,
284
.drain = block_job_drain,
285
.run = cancel_job_run,
286
+ .exit = cancel_job_exit,
287
.complete = cancel_job_complete,
288
},
289
};
290
--
291
2.17.1
292
293
diff view generated by jsdifflib
1
Use the new used ring APIs instead of assuming ISR being set means the
1
From: John Snow <jsnow@redhat.com>
2
request has completed.
3
2
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Rename opaque_job to job to be consistent with other job implementations.
5
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
4
Rename 'job', the BackupBlockJob object, to 's' to also be consistent.
6
Reviewed-by: Fam Zheng <famz@redhat.com>
5
7
Tested-by: Eric Blake <eblake@redhat.com>
6
Suggested-by: Eric Blake <eblake@redhat.com>
8
Tested-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: John Snow <jsnow@redhat.com>
9
Message-id: 20170628184724.21378-4-stefanha@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 20180830015734.19765-8-jsnow@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
11
---
12
tests/virtio-scsi-test.c | 2 +-
12
block/backup.c | 62 +++++++++++++++++++++++++-------------------------
13
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 31 insertions(+), 31 deletions(-)
14
14
15
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
15
diff --git a/block/backup.c b/block/backup.c
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/virtio-scsi-test.c
17
--- a/block/backup.c
18
+++ b/tests/virtio-scsi-test.c
18
+++ b/block/backup.c
19
@@ -XXX,XX +XXX,XX @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb,
19
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
20
bdrv_dirty_iter_free(dbi);
21
}
22
23
-static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
24
+static int coroutine_fn backup_run(Job *job, Error **errp)
25
{
26
- BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
27
- BlockDriverState *bs = blk_bs(job->common.blk);
28
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
29
+ BlockDriverState *bs = blk_bs(s->common.blk);
30
int64_t offset, nb_clusters;
31
int ret = 0;
32
33
- QLIST_INIT(&job->inflight_reqs);
34
- qemu_co_rwlock_init(&job->flush_rwlock);
35
+ QLIST_INIT(&s->inflight_reqs);
36
+ qemu_co_rwlock_init(&s->flush_rwlock);
37
38
- nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size);
39
- job_progress_set_remaining(&job->common.job, job->len);
40
+ nb_clusters = DIV_ROUND_UP(s->len, s->cluster_size);
41
+ job_progress_set_remaining(job, s->len);
42
43
- job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
44
- if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
45
- backup_incremental_init_copy_bitmap(job);
46
+ s->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
47
+ if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
48
+ backup_incremental_init_copy_bitmap(s);
49
} else {
50
- hbitmap_set(job->copy_bitmap, 0, nb_clusters);
51
+ hbitmap_set(s->copy_bitmap, 0, nb_clusters);
20
}
52
}
21
53
22
qvirtqueue_kick(vs->dev, vq, free_head);
54
23
- qvirtio_wait_queue_isr(vs->dev, vq, QVIRTIO_SCSI_TIMEOUT_US);
55
- job->before_write.notify = backup_before_write_notify;
24
+ qvirtio_wait_used_elem(vs->dev, vq, free_head, QVIRTIO_SCSI_TIMEOUT_US);
56
- bdrv_add_before_write_notifier(bs, &job->before_write);
25
57
+ s->before_write.notify = backup_before_write_notify;
26
response = readb(resp_addr +
58
+ bdrv_add_before_write_notifier(bs, &s->before_write);
27
offsetof(struct virtio_scsi_cmd_resp, response));
59
60
- if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
61
+ if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
62
/* All bits are set in copy_bitmap to allow any cluster to be copied.
63
* This does not actually require them to be copied. */
64
- while (!job_is_cancelled(&job->common.job)) {
65
+ while (!job_is_cancelled(job)) {
66
/* Yield until the job is cancelled. We just let our before_write
67
* notify callback service CoW requests. */
68
- job_yield(&job->common.job);
69
+ job_yield(job);
70
}
71
- } else if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
72
- ret = backup_run_incremental(job);
73
+ } else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
74
+ ret = backup_run_incremental(s);
75
} else {
76
/* Both FULL and TOP SYNC_MODE's require copying.. */
77
- for (offset = 0; offset < job->len;
78
- offset += job->cluster_size) {
79
+ for (offset = 0; offset < s->len;
80
+ offset += s->cluster_size) {
81
bool error_is_read;
82
int alloced = 0;
83
84
- if (yield_and_check(job)) {
85
+ if (yield_and_check(s)) {
86
break;
87
}
88
89
- if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
90
+ if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
91
int i;
92
int64_t n;
93
94
/* Check to see if these blocks are already in the
95
* backing file. */
96
97
- for (i = 0; i < job->cluster_size;) {
98
+ for (i = 0; i < s->cluster_size;) {
99
/* bdrv_is_allocated() only returns true/false based
100
* on the first set of sectors it comes across that
101
* are are all in the same state.
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
103
* needed but at some point that is always the case. */
104
alloced =
105
bdrv_is_allocated(bs, offset + i,
106
- job->cluster_size - i, &n);
107
+ s->cluster_size - i, &n);
108
i += n;
109
110
if (alloced || n == 0) {
111
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
112
if (alloced < 0) {
113
ret = alloced;
114
} else {
115
- ret = backup_do_cow(job, offset, job->cluster_size,
116
+ ret = backup_do_cow(s, offset, s->cluster_size,
117
&error_is_read, false);
118
}
119
if (ret < 0) {
120
/* Depending on error action, fail now or retry cluster */
121
BlockErrorAction action =
122
- backup_error_action(job, error_is_read, -ret);
123
+ backup_error_action(s, error_is_read, -ret);
124
if (action == BLOCK_ERROR_ACTION_REPORT) {
125
break;
126
} else {
127
- offset -= job->cluster_size;
128
+ offset -= s->cluster_size;
129
continue;
130
}
131
}
132
}
133
}
134
135
- notifier_with_return_remove(&job->before_write);
136
+ notifier_with_return_remove(&s->before_write);
137
138
/* wait until pending backup_do_cow() calls have completed */
139
- qemu_co_rwlock_wrlock(&job->flush_rwlock);
140
- qemu_co_rwlock_unlock(&job->flush_rwlock);
141
- hbitmap_free(job->copy_bitmap);
142
+ qemu_co_rwlock_wrlock(&s->flush_rwlock);
143
+ qemu_co_rwlock_unlock(&s->flush_rwlock);
144
+ hbitmap_free(s->copy_bitmap);
145
146
return ret;
147
}
28
--
148
--
29
2.9.4
149
2.17.1
30
150
31
151
diff view generated by jsdifflib
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2
3
Reviewed-by: Fam Zheng <famz@redhat.com>
3
Jobs are now expected to return their retcode on the stack, from the
4
Tested-by: Eric Blake <eblake@redhat.com>
4
.run callback, so we can remove that argument.
5
Tested-by: Kevin Wolf <kwolf@redhat.com>
5
6
Message-id: 20170628184724.21378-2-stefanha@redhat.com
6
job_cancel does not need to set -ECANCELED because job_completed will
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
update the return code itself if the job was canceled.
8
9
While we're here, make job_completed static to job.c and remove it from
10
job.h; move the documentation of return code to the .run() callback and
11
to the job->ret property, accordingly.
12
13
Signed-off-by: John Snow <jsnow@redhat.com>
14
Message-id: 20180830015734.19765-9-jsnow@redhat.com
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
17
---
9
tests/libqos/virtio.h | 2 +-
18
include/qemu/job.h | 28 +++++++++++++++-------------
10
1 file changed, 1 insertion(+), 1 deletion(-)
19
job.c | 11 ++++++-----
20
trace-events | 2 +-
21
3 files changed, 22 insertions(+), 19 deletions(-)
11
22
12
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
23
diff --git a/include/qemu/job.h b/include/qemu/job.h
13
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/libqos/virtio.h
25
--- a/include/qemu/job.h
15
+++ b/tests/libqos/virtio.h
26
+++ b/include/qemu/job.h
16
@@ -XXX,XX +XXX,XX @@ typedef struct QVirtioDevice {
27
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
17
typedef struct QVirtQueue {
28
/** Estimated progress_current value at the completion of the job */
18
uint64_t desc; /* This points to an array of struct vring_desc */
29
int64_t progress_total;
19
uint64_t avail; /* This points to a struct vring_avail */
30
20
- uint64_t used; /* This points to a struct vring_desc */
31
- /** ret code passed to job_completed. */
21
+ uint64_t used; /* This points to a struct vring_used */
32
+ /**
22
uint16_t index;
33
+ * Return code from @run and/or @prepare callback(s).
23
uint32_t size;
34
+ * Not final until the job has reached the CONCLUDED status.
24
uint32_t free_head;
35
+ * 0 on success, -errno on failure.
36
+ */
37
int ret;
38
39
/**
40
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
41
/** Enum describing the operation */
42
JobType job_type;
43
44
- /** Mandatory: Entrypoint for the Coroutine. */
45
+ /**
46
+ * Mandatory: Entrypoint for the Coroutine.
47
+ *
48
+ * This callback will be invoked when moving from CREATED to RUNNING.
49
+ *
50
+ * If this callback returns nonzero, the job transaction it is part of is
51
+ * aborted. If it returns zero, the job moves into the WAITING state. If it
52
+ * is the last job to complete in its transaction, all jobs in the
53
+ * transaction move from WAITING to PENDING.
54
+ */
55
int coroutine_fn (*run)(Job *job, Error **errp);
56
57
/**
58
@@ -XXX,XX +XXX,XX @@ void job_early_fail(Job *job);
59
/** Moves the @job from RUNNING to READY */
60
void job_transition_to_ready(Job *job);
61
62
-/**
63
- * @job: The job being completed.
64
- * @ret: The status code.
65
- *
66
- * Marks @job as completed. If @ret is non-zero, the job transaction it is part
67
- * of is aborted. If @ret is zero, the job moves into the WAITING state. If it
68
- * is the last job to complete in its transaction, all jobs in the transaction
69
- * move from WAITING to PENDING.
70
- */
71
-void job_completed(Job *job, int ret);
72
-
73
/** Asynchronously complete the specified @job. */
74
void job_complete(Job *job, Error **errp);
75
76
diff --git a/job.c b/job.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/job.c
79
+++ b/job.c
80
@@ -XXX,XX +XXX,XX @@ void job_drain(Job *job)
81
}
82
}
83
84
+static void job_completed(Job *job);
85
+
86
static void job_exit(void *opaque)
87
{
88
Job *job = (Job *)opaque;
89
@@ -XXX,XX +XXX,XX @@ static void job_exit(void *opaque)
90
job->driver->exit(job);
91
aio_context_release(aio_context);
92
}
93
- job_completed(job, job->ret);
94
+ job_completed(job);
95
}
96
97
/**
98
@@ -XXX,XX +XXX,XX @@ static void job_completed_txn_success(Job *job)
99
}
100
}
101
102
-void job_completed(Job *job, int ret)
103
+static void job_completed(Job *job)
104
{
105
assert(job && job->txn && !job_is_completed(job));
106
107
- job->ret = ret;
108
job_update_rc(job);
109
- trace_job_completed(job, ret, job->ret);
110
+ trace_job_completed(job, job->ret);
111
if (job->ret) {
112
job_completed_txn_abort(job);
113
} else {
114
@@ -XXX,XX +XXX,XX @@ void job_cancel(Job *job, bool force)
115
}
116
job_cancel_async(job, force);
117
if (!job_started(job)) {
118
- job_completed(job, -ECANCELED);
119
+ job_completed(job);
120
} else if (job->deferred_to_main_loop) {
121
job_completed_txn_abort(job);
122
} else {
123
diff --git a/trace-events b/trace-events
124
index XXXXXXX..XXXXXXX 100644
125
--- a/trace-events
126
+++ b/trace-events
127
@@ -XXX,XX +XXX,XX @@ gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packe
128
# job.c
129
job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
130
job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
131
-job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
132
+job_completed(void *job, int ret) "job %p ret %d"
133
134
# job-qmp.c
135
qmp_job_cancel(void *job) "job %p"
25
--
136
--
26
2.9.4
137
2.17.1
27
138
28
139
diff view generated by jsdifflib
1
It is hard to analyze trace logs with multiple virtio-blk devices
1
From: John Snow <jsnow@redhat.com>
2
because none of the trace events include the VirtIODevice *vdev.
3
2
4
This patch adds vdev so it's clear which device a request is associated
3
Now that the job infrastructure is handling the job_completed call for
5
with.
4
all implemented jobs, we can remove the interface that allowed jobs to
5
schedule their own completion.
6
6
7
I considered using VirtIOBlock *s instead but VirtIODevice *vdev is more
7
Signed-off-by: John Snow <jsnow@redhat.com>
8
general and may be correlated with generic virtio trace events like
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
virtio_set_status.
9
Message-id: 20180830015734.19765-10-jsnow@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
include/qemu/job.h | 17 -----------------
13
job.c | 40 ++--------------------------------------
14
2 files changed, 2 insertions(+), 55 deletions(-)
10
15
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
diff --git a/include/qemu/job.h b/include/qemu/job.h
12
Reviewed-by: Fam Zheng <famz@redhat.com>
13
Message-id: 20170614092930.11234-1-stefanha@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
hw/block/virtio-blk.c | 12 +++++++-----
17
hw/block/trace-events | 10 +++++-----
18
2 files changed, 12 insertions(+), 10 deletions(-)
19
20
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
21
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/block/virtio-blk.c
18
--- a/include/qemu/job.h
23
+++ b/hw/block/virtio-blk.c
19
+++ b/include/qemu/job.h
24
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
20
@@ -XXX,XX +XXX,XX @@ void job_finalize(Job *job, Error **errp);
25
VirtIOBlock *s = req->dev;
21
*/
26
VirtIODevice *vdev = VIRTIO_DEVICE(s);
22
void job_dismiss(Job **job, Error **errp);
27
23
28
- trace_virtio_blk_req_complete(req, status);
24
-typedef void JobDeferToMainLoopFn(Job *job, void *opaque);
29
+ trace_virtio_blk_req_complete(vdev, req, status);
25
-
30
26
-/**
31
stb_p(&req->in->status, status);
27
- * @job: The job
32
virtqueue_push(req->vq, &req->elem, req->in_len);
28
- * @fn: The function to run in the main loop
33
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
29
- * @opaque: The opaque value that is passed to @fn
30
- *
31
- * This function must be called by the main job coroutine just before it
32
- * returns. @fn is executed in the main loop with the job AioContext acquired.
33
- *
34
- * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses
35
- * bdrv_drain_all() in the main loop.
36
- *
37
- * The @job AioContext is held while @fn executes.
38
- */
39
-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque);
40
-
41
/**
42
* Synchronously finishes the given @job. If @finish is given, it is called to
43
* trigger completion or cancellation of the job.
44
diff --git a/job.c b/job.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/job.c
47
+++ b/job.c
48
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
49
assert(job && job->driver && job->driver->run);
50
job_pause_point(job);
51
job->ret = job->driver->run(job, &job->err);
52
- if (!job->deferred_to_main_loop) {
53
- job->deferred_to_main_loop = true;
54
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
55
- job_exit,
56
- job);
57
- }
58
+ job->deferred_to_main_loop = true;
59
+ aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job);
60
}
61
62
63
@@ -XXX,XX +XXX,XX @@ void job_complete(Job *job, Error **errp)
64
job->driver->complete(job, errp);
65
}
66
67
-
68
-typedef struct {
69
- Job *job;
70
- JobDeferToMainLoopFn *fn;
71
- void *opaque;
72
-} JobDeferToMainLoopData;
73
-
74
-static void job_defer_to_main_loop_bh(void *opaque)
75
-{
76
- JobDeferToMainLoopData *data = opaque;
77
- Job *job = data->job;
78
- AioContext *aio_context = job->aio_context;
79
-
80
- aio_context_acquire(aio_context);
81
- data->fn(data->job, data->opaque);
82
- aio_context_release(aio_context);
83
-
84
- g_free(data);
85
-}
86
-
87
-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque)
88
-{
89
- JobDeferToMainLoopData *data = g_malloc(sizeof(*data));
90
- data->job = job;
91
- data->fn = fn;
92
- data->opaque = opaque;
93
- job->deferred_to_main_loop = true;
94
-
95
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
96
- job_defer_to_main_loop_bh, data);
97
-}
98
-
99
int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
34
{
100
{
35
VirtIOBlockReq *next = opaque;
101
Error *local_err = NULL;
36
VirtIOBlock *s = next->dev;
37
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
38
39
aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
40
while (next) {
41
VirtIOBlockReq *req = next;
42
next = req->mr_next;
43
- trace_virtio_blk_rw_complete(req, ret);
44
+ trace_virtio_blk_rw_complete(vdev, req, ret);
45
46
if (req->qiov.nalloc != -1) {
47
/* If nalloc is != 1 req->qiov is a local copy of the original
48
@@ -XXX,XX +XXX,XX @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
49
mrb->reqs[i - 1]->mr_next = mrb->reqs[i];
50
}
51
52
- trace_virtio_blk_submit_multireq(mrb, start, num_reqs,
53
+ trace_virtio_blk_submit_multireq(VIRTIO_DEVICE(mrb->reqs[start]->dev),
54
+ mrb, start, num_reqs,
55
sector_num << BDRV_SECTOR_BITS,
56
qiov->size, is_write);
57
block_acct_merge_done(blk_get_stats(blk),
58
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
59
60
if (is_write) {
61
qemu_iovec_init_external(&req->qiov, iov, out_num);
62
- trace_virtio_blk_handle_write(req, req->sector_num,
63
+ trace_virtio_blk_handle_write(vdev, req, req->sector_num,
64
req->qiov.size / BDRV_SECTOR_SIZE);
65
} else {
66
qemu_iovec_init_external(&req->qiov, in_iov, in_num);
67
- trace_virtio_blk_handle_read(req, req->sector_num,
68
+ trace_virtio_blk_handle_read(vdev, req, req->sector_num,
69
req->qiov.size / BDRV_SECTOR_SIZE);
70
}
71
72
diff --git a/hw/block/trace-events b/hw/block/trace-events
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/block/trace-events
75
+++ b/hw/block/trace-events
76
@@ -XXX,XX +XXX,XX @@
77
# See docs/tracing.txt for syntax documentation.
78
79
# hw/block/virtio-blk.c
80
-virtio_blk_req_complete(void *req, int status) "req %p status %d"
81
-virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
82
-virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
83
-virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
84
-virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
85
+virtio_blk_req_complete(void *vdev, void *req, int status) "vdev %p req %p status %d"
86
+virtio_blk_rw_complete(void *vdev, void *req, int ret) "vdev %p req %p ret %d"
87
+virtio_blk_handle_write(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu"
88
+virtio_blk_handle_read(void *vdev, void *req, uint64_t sector, size_t nsectors) "vdev %p req %p sector %"PRIu64" nsectors %zu"
89
+virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "vdev %p mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
90
91
# hw/block/hd-geometry.c
92
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
93
--
102
--
94
2.9.4
103
2.17.1
95
104
96
105
diff view generated by jsdifflib