1
The following changes since commit 19b599f7664b2ebfd0f405fb79c14dd241557452:
1
The following changes since commit 6cb4f6db4f4367faa33da85b15f75bbbd2bed2a6:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-error-2018-08-27-v2' into staging (2018-08-27 16:44:20 +0100)
3
Merge remote-tracking branch 'remotes/cleber/tags/python-next-pull-request' into staging (2019-03-07 16:16:02 +0000)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://git.xanclic.moe/XanClic/qemu.git tags/pull-block-2018-08-31
7
git://github.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 40954cc7831c4f95f9ce6402ae3d6761f44f31ff:
9
for you to fetch changes up to 6ca206204fa773c8626d59caf2a5676d6cc35f52:
10
10
11
jobs: remove job_defer_to_main_loop (2018-08-31 16:11:27 +0200)
11
iothread: document about why we need explicit aio_poll() (2019-03-08 10:20:57 +0000)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- (Block) job exit refactoring, part 1
16
(removing job_defer_to_main_loop())
17
- Locking fix for the file-posix block driver
18
- test-bdrv-drain leak fix
19
15
20
----------------------------------------------------------------
16
----------------------------------------------------------------
21
Fam Zheng (1):
22
file-posix: Skip effectiveless OFD lock operations
23
17
24
John Snow (9):
18
Anastasiia Rusakova (1):
25
jobs: change start callback to run callback
19
hw/block/virtio-blk: Clean req->dev repetitions
26
jobs: canonize Error object
27
jobs: add exit shim
28
block/commit: utilize job_exit shim
29
block/mirror: utilize job_exit shim
30
jobs: utilize job_exit shim
31
block/backup: make function variables consistently named
32
jobs: remove ret argument to job_completed; privatize it
33
jobs: remove job_defer_to_main_loop
34
20
35
Marc-André Lureau (1):
21
Peter Xu (5):
36
tests: fix bdrv-drain leak
22
iothread: replace init_done_cond with a semaphore
23
iothread: create the gcontext unconditionally
24
iothread: create main loop unconditionally
25
iothread: push gcontext earlier in the thread_fn
26
iothread: document about why we need explicit aio_poll()
37
27
38
include/qemu/job.h | 70 ++++++++++++++++-----------------
28
Stefan Hajnoczi (1):
39
block/backup.c | 81 ++++++++++++++++-----------------------
29
MAINTAINERS: add missing support status fields
40
block/commit.c | 29 +++++---------
30
41
block/create.c | 19 +++------
31
MAINTAINERS | 3 ++
42
block/file-posix.c | 41 +++++++++++++++-----
32
include/sysemu/iothread.h | 5 +--
43
block/mirror.c | 39 ++++++++-----------
33
hw/block/virtio-blk.c | 16 ++++---
44
block/stream.c | 29 ++++++--------
34
iothread.c | 90 +++++++++++++++++++--------------------
45
job-qmp.c | 5 ++-
35
4 files changed, 57 insertions(+), 57 deletions(-)
46
job.c | 73 ++++++++++++-----------------------
47
tests/test-bdrv-drain.c | 14 +++----
48
tests/test-blockjob-txn.c | 25 +++++-------
49
tests/test-blockjob.c | 17 ++++----
50
trace-events | 2 +-
51
13 files changed, 192 insertions(+), 252 deletions(-)
52
36
53
--
37
--
54
2.17.1
38
2.20.1
55
39
56
40
diff view generated by jsdifflib
Deleted patch
1
From: Fam Zheng <famz@redhat.com>
2
1
3
If we know we've already locked the bytes, don't do it again; similarly
4
don't unlock a byte if we haven't locked it. This doesn't change the
5
behavior, but fixes a corner case explained below.
6
7
Libvirt had an error handling bug that an image can get its (ownership,
8
file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind
9
QEMU. Specifically, an image in use by Libvirt VM has:
10
11
$ ls -lhZ b.img
12
-rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img
13
14
Trying to attach it a second time won't work because of image locking.
15
And after the error, it becomes:
16
17
$ ls -lhZ b.img
18
-rw-r--r--. root root system_u:object_r:virt_image_t:s0 b.img
19
20
Then, we won't be able to do OFD lock operations with the existing fd.
21
In other words, the code such as in blk_detach_dev:
22
23
blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
24
25
can abort() QEMU, out of environmental changes.
26
27
This patch is an easy fix to this and the change is regardlessly
28
reasonable, so do it.
29
30
Signed-off-by: Fam Zheng <famz@redhat.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
32
---
33
block/file-posix.c | 41 +++++++++++++++++++++++++++++++----------
34
1 file changed, 31 insertions(+), 10 deletions(-)
35
36
diff --git a/block/file-posix.c b/block/file-posix.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/file-posix.c
39
+++ b/block/file-posix.c
40
@@ -XXX,XX +XXX,XX @@ typedef enum {
41
* file; if @unlock == true, also unlock the unneeded bytes.
42
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
43
*/
44
-static int raw_apply_lock_bytes(int fd,
45
+static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
46
uint64_t perm_lock_bits,
47
uint64_t shared_perm_lock_bits,
48
bool unlock, Error **errp)
49
{
50
int ret;
51
int i;
52
+ uint64_t locked_perm, locked_shared_perm;
53
+
54
+ if (s) {
55
+ locked_perm = s->perm;
56
+ locked_shared_perm = ~s->shared_perm & BLK_PERM_ALL;
57
+ } else {
58
+ /*
59
+ * We don't have the previous bits, just lock/unlock for each of the
60
+ * requested bits.
61
+ */
62
+ if (unlock) {
63
+ locked_perm = BLK_PERM_ALL;
64
+ locked_shared_perm = BLK_PERM_ALL;
65
+ } else {
66
+ locked_perm = 0;
67
+ locked_shared_perm = 0;
68
+ }
69
+ }
70
71
PERM_FOREACH(i) {
72
int off = RAW_LOCK_PERM_BASE + i;
73
- if (perm_lock_bits & (1ULL << i)) {
74
+ uint64_t bit = (1ULL << i);
75
+ if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
76
ret = qemu_lock_fd(fd, off, 1, false);
77
if (ret) {
78
error_setg(errp, "Failed to lock byte %d", off);
79
return ret;
80
}
81
- } else if (unlock) {
82
+ } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
83
ret = qemu_unlock_fd(fd, off, 1);
84
if (ret) {
85
error_setg(errp, "Failed to unlock byte %d", off);
86
@@ -XXX,XX +XXX,XX @@ static int raw_apply_lock_bytes(int fd,
87
}
88
PERM_FOREACH(i) {
89
int off = RAW_LOCK_SHARED_BASE + i;
90
- if (shared_perm_lock_bits & (1ULL << i)) {
91
+ uint64_t bit = (1ULL << i);
92
+ if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
93
ret = qemu_lock_fd(fd, off, 1, false);
94
if (ret) {
95
error_setg(errp, "Failed to lock byte %d", off);
96
return ret;
97
}
98
- } else if (unlock) {
99
+ } else if (unlock && (locked_shared_perm & bit) &&
100
+ !(shared_perm_lock_bits & bit)) {
101
ret = qemu_unlock_fd(fd, off, 1);
102
if (ret) {
103
error_setg(errp, "Failed to unlock byte %d", off);
104
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
105
106
switch (op) {
107
case RAW_PL_PREPARE:
108
- ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
109
+ ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm,
110
~s->shared_perm | ~new_shared,
111
false, errp);
112
if (!ret) {
113
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
114
op = RAW_PL_ABORT;
115
/* fall through to unlock bytes. */
116
case RAW_PL_ABORT:
117
- raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
118
+ raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm,
119
true, &local_err);
120
if (local_err) {
121
/* Theoretically the above call only unlocks bytes and it cannot
122
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
123
}
124
break;
125
case RAW_PL_COMMIT:
126
- raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
127
+ raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared,
128
true, &local_err);
129
if (local_err) {
130
/* Theoretically the above call only unlocks bytes and it cannot
131
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
132
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
133
134
/* Step one: Take locks */
135
- result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
136
+ result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
137
if (result < 0) {
138
goto out_close;
139
}
140
@@ -XXX,XX +XXX,XX @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
141
}
142
143
out_unlock:
144
- raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
145
+ raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
146
if (local_err) {
147
/* The above call should not fail, and if it does, that does
148
* not mean the whole creation operation has failed. So
149
--
150
2.17.1
151
152
diff view generated by jsdifflib
Deleted patch
1
From: Marc-André Lureau <marcandre.lureau@redhat.com>
2
1
3
Spotted by ASAN:
4
5
=================================================================
6
==5378==ERROR: LeakSanitizer: detected memory leaks
7
8
Direct leak of 65536 byte(s) in 1 object(s) allocated from:
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)
13
14
(Broken in commit 4c8158e359d.)
15
16
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
17
Message-id: 20180809114417.28718-3-marcandre.lureau@redhat.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
tests/test-bdrv-drain.c | 1 +
21
1 file changed, 1 insertion(+)
22
23
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/tests/test-bdrv-drain.c
26
+++ b/tests/test-bdrv-drain.c
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
28
}
29
30
dbdd->done = true;
31
+ g_free(buffer);
32
}
33
34
/**
35
--
36
2.17.1
37
38
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
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
1
From: John Snow <jsnow@redhat.com>
1
This patch adds the "S:" line for areas of the codebase that currently
2
lack a support status field.
2
3
3
Now that the job infrastructure is handling the job_completed call for
4
Note that there are a few more areas that are more abstract and do not
4
all implemented jobs, we can remove the interface that allowed jobs to
5
correspond to a specific set of files. They have not been modified.
5
schedule their own completion.
6
6
7
Signed-off-by: John Snow <jsnow@redhat.com>
7
Cc: Alex Bennée <alex.bennee@linaro.org>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-id: 20180830015734.19765-10-jsnow@redhat.com
9
Reviewed-by: Thomas Huth <thuth@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20190301163518.20702-1-stefanha@redhat.com
13
Message-Id: <20190301163518.20702-1-stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
15
---
12
include/qemu/job.h | 17 -----------------
16
MAINTAINERS | 3 +++
13
job.c | 40 ++--------------------------------------
17
1 file changed, 3 insertions(+)
14
2 files changed, 2 insertions(+), 55 deletions(-)
15
18
16
diff --git a/include/qemu/job.h b/include/qemu/job.h
19
diff --git a/MAINTAINERS b/MAINTAINERS
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/include/qemu/job.h
21
--- a/MAINTAINERS
19
+++ b/include/qemu/job.h
22
+++ b/MAINTAINERS
20
@@ -XXX,XX +XXX,XX @@ void job_finalize(Job *job, Error **errp);
23
@@ -XXX,XX +XXX,XX @@ F: include/hw/tricore/
21
*/
24
22
void job_dismiss(Job **job, Error **errp);
25
Multiarch Linux User Tests
23
26
M: Alex Bennée <alex.bennee@linaro.org>
24
-typedef void JobDeferToMainLoopFn(Job *job, void *opaque);
27
+S: Maintained
25
-
28
F: tests/tcg/multiarch/
26
-/**
29
27
- * @job: The job
30
Guest CPU Cores (KVM):
28
- * @fn: The function to run in the main loop
31
@@ -XXX,XX +XXX,XX @@ F: qemu.sasl
29
- * @opaque: The opaque value that is passed to @fn
32
Coroutines
30
- *
33
M: Stefan Hajnoczi <stefanha@redhat.com>
31
- * This function must be called by the main job coroutine just before it
34
M: Kevin Wolf <kwolf@redhat.com>
32
- * returns. @fn is executed in the main loop with the job AioContext acquired.
35
+S: Maintained
33
- *
36
F: util/*coroutine*
34
- * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses
37
F: include/qemu/coroutine*
35
- * bdrv_drain_all() in the main loop.
38
F: tests/test-coroutine.c
36
- *
39
@@ -XXX,XX +XXX,XX @@ F: .gitlab-ci.yml
37
- * The @job AioContext is held while @fn executes.
40
Guest Test Compilation Support
38
- */
41
M: Alex Bennée <alex.bennee@linaro.org>
39
-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque);
42
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
40
-
43
+S: Maintained
41
/**
44
F: tests/tcg/Makefile
42
* Synchronously finishes the given @job. If @finish is given, it is called to
45
F: tests/tcg/Makefile.include
43
* trigger completion or cancellation of the job.
46
L: qemu-devel@nongnu.org
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)
100
{
101
Error *local_err = NULL;
102
--
47
--
103
2.17.1
48
2.20.1
104
49
105
50
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Anastasiia Rusakova <arusakova917@gmail.com>
2
2
3
Jobs are now expected to return their retcode on the stack, from the
3
Some functions sometimes uses req->dev even though a local variable
4
.run callback, so we can remove that argument.
4
VirtIOBlock* s = req->dev has already been defined.
5
Updated places to use s everywhere in the file.
5
6
6
job_cancel does not need to set -ECANCELED because job_completed will
7
Signed-off-by: Anastasiia Rusakova <arusakova917@gmail.com>
7
update the return code itself if the job was canceled.
8
Message-id: 20190307161925.4158-1-rusakova.nastasia@icloud.com
9
Message-Id: <20190307161925.4158-1-rusakova.nastasia@icloud.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
hw/block/virtio-blk.c | 16 +++++++++-------
13
1 file changed, 9 insertions(+), 7 deletions(-)
8
14
9
While we're here, make job_completed static to job.c and remove it from
15
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
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>
17
---
18
include/qemu/job.h | 28 +++++++++++++++-------------
19
job.c | 11 ++++++-----
20
trace-events | 2 +-
21
3 files changed, 22 insertions(+), 19 deletions(-)
22
23
diff --git a/include/qemu/job.h b/include/qemu/job.h
24
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qemu/job.h
17
--- a/hw/block/virtio-blk.c
26
+++ b/include/qemu/job.h
18
+++ b/hw/block/virtio-blk.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
19
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
28
/** Estimated progress_current value at the completion of the job */
20
}
29
int64_t progress_total;
21
30
22
if (ret) {
31
- /** ret code passed to job_completed. */
23
- int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
32
+ /**
24
+ int p = virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type);
33
+ * Return code from @run and/or @prepare callback(s).
25
bool is_read = !(p & VIRTIO_BLK_T_OUT);
34
+ * Not final until the job has reached the CONCLUDED status.
26
/* Note that memory may be dirtied on read failure. If the
35
+ * 0 on success, -errno on failure.
27
* virtio request is not completed here, as is the case for
36
+ */
28
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
37
int ret;
29
}
38
30
39
/**
31
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
40
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
32
- block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
41
/** Enum describing the operation */
33
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
42
JobType job_type;
34
virtio_blk_free_request(req);
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
}
35
}
36
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
37
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
38
{
39
int status = VIRTIO_BLK_S_OK;
40
struct virtio_scsi_inhdr *scsi = NULL;
41
- VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
42
- VirtQueueElement *elem = &req->elem;
43
VirtIOBlock *blk = req->dev;
44
+ VirtIODevice *vdev = VIRTIO_DEVICE(blk);
45
+ VirtQueueElement *elem = &req->elem;
46
47
#ifdef __linux__
48
int i;
49
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
50
51
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
52
{
53
- block_acct_start(blk_get_stats(req->dev->blk), &req->acct, 0,
54
+ VirtIOBlock *s = req->dev;
55
+
56
+ block_acct_start(blk_get_stats(s->blk), &req->acct, 0,
57
BLOCK_ACCT_FLUSH);
58
59
/*
60
* Make sure all outstanding writes are posted to the backing device.
61
*/
62
if (mrb->is_write && mrb->num_reqs > 0) {
63
- virtio_blk_submit_multireq(req->dev->blk, mrb);
64
+ virtio_blk_submit_multireq(s->blk, mrb);
65
}
66
- blk_aio_flush(req->dev->blk, virtio_blk_flush_complete, req);
67
+ blk_aio_flush(s->blk, virtio_blk_flush_complete, req);
82
}
68
}
83
69
84
+static void job_completed(Job *job);
70
static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
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"
136
--
71
--
137
2.17.1
72
2.20.1
138
73
139
74
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Jobs presently use both an Error object in the case of the create job,
3
Only sending an init-done message using lock+cond seems an overkill to
4
and char strings in the case of generic errors elsewhere.
4
me. Replacing it with a simpler semaphore.
5
5
6
Unify the two paths as just j->err, and remove the extra argument from
6
Meanwhile, init the semaphore unconditionally, then we can destroy it
7
job_completed. The integer error code for job_completed is kept for now,
7
unconditionally too in finalize which seems cleaner.
8
to be removed shortly in a separate patch.
9
8
10
Signed-off-by: John Snow <jsnow@redhat.com>
9
Signed-off-by: Peter Xu <peterx@redhat.com>
11
Message-id: 20180830015734.19765-3-jsnow@redhat.com
10
Message-id: 20190306115532.23025-2-peterx@redhat.com
12
[mreitz: Dropped a superfluous g_strdup()]
11
Message-Id: <20190306115532.23025-2-peterx@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
13
---
16
include/qemu/job.h | 14 ++++++++------
14
include/sysemu/iothread.h | 3 +--
17
block/backup.c | 2 +-
15
iothread.c | 17 ++++-------------
18
block/commit.c | 2 +-
16
2 files changed, 5 insertions(+), 15 deletions(-)
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
17
29
diff --git a/include/qemu/job.h b/include/qemu/job.h
18
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
30
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
31
--- a/include/qemu/job.h
20
--- a/include/sysemu/iothread.h
32
+++ b/include/qemu/job.h
21
+++ b/include/sysemu/iothread.h
33
@@ -XXX,XX +XXX,XX @@ typedef struct Job {
22
@@ -XXX,XX +XXX,XX @@ typedef struct {
34
/** Estimated progress_current value at the completion of the job */
23
GMainContext *worker_context;
35
int64_t progress_total;
24
GMainLoop *main_loop;
36
25
GOnce once;
37
- /** Error string for a failed job (NULL if, and only if, job->ret == 0) */
26
- QemuMutex init_done_lock;
38
- char *error;
27
- QemuCond init_done_cond; /* is thread initialization done? */
39
-
28
+ QemuSemaphore init_done_sem; /* is thread init done? */
40
/** ret code passed to job_completed. */
29
bool stopping; /* has iothread_stop() been called? */
41
int ret;
30
bool running; /* should iothread_run() continue? */
42
31
int thread_id;
43
+ /**
32
diff --git a/iothread.c b/iothread.c
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
33
index XXXXXXX..XXXXXXX 100644
72
--- a/block/backup.c
34
--- a/iothread.c
73
+++ b/block/backup.c
35
+++ b/iothread.c
74
@@ -XXX,XX +XXX,XX @@ static void backup_complete(Job *job, void *opaque)
36
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
75
{
37
rcu_register_thread();
76
BackupCompleteData *data = opaque;
38
77
39
my_iothread = iothread;
78
- job_completed(job, data->ret, NULL);
40
- qemu_mutex_lock(&iothread->init_done_lock);
79
+ job_completed(job, data->ret);
41
iothread->thread_id = qemu_get_thread_id();
80
g_free(data);
42
- qemu_cond_signal(&iothread->init_done_cond);
43
- qemu_mutex_unlock(&iothread->init_done_lock);
44
+ qemu_sem_post(&iothread->init_done_sem);
45
46
while (iothread->running) {
47
aio_poll(iothread->ctx, true);
48
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_init(Object *obj)
49
50
iothread->poll_max_ns = IOTHREAD_POLL_MAX_NS_DEFAULT;
51
iothread->thread_id = -1;
52
+ qemu_sem_init(&iothread->init_done_sem, 0);
81
}
53
}
82
54
83
diff --git a/block/commit.c b/block/commit.c
55
static void iothread_instance_finalize(Object *obj)
84
index XXXXXXX..XXXXXXX 100644
56
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_finalize(Object *obj)
85
--- a/block/commit.c
57
86
+++ b/block/commit.c
58
iothread_stop(iothread);
87
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
59
88
* bdrv_set_backing_hd() to fail. */
60
- if (iothread->thread_id != -1) {
89
block_job_remove_all_bdrv(bjob);
61
- qemu_cond_destroy(&iothread->init_done_cond);
90
62
- qemu_mutex_destroy(&iothread->init_done_lock);
91
- job_completed(job, ret, NULL);
63
- }
92
+ job_completed(job, ret);
64
/*
93
g_free(data);
65
* Before glib2 2.33.10, there is a glib2 bug that GSource context
94
66
* pointer may not be cleared even if the context has already been
95
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
67
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_finalize(Object *obj)
96
diff --git a/block/create.c b/block/create.c
68
g_main_context_unref(iothread->worker_context);
97
index XXXXXXX..XXXXXXX 100644
69
iothread->worker_context = NULL;
98
--- a/block/create.c
70
}
99
+++ b/block/create.c
71
+ qemu_sem_destroy(&iothread->init_done_sem);
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
}
72
}
114
73
115
static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
74
static void iothread_complete(UserCreatable *obj, Error **errp)
116
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
75
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
117
BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
76
return;
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
}
77
}
144
78
145
g_free(s->backing_file_str);
79
- qemu_mutex_init(&iothread->init_done_lock);
146
- job_completed(job, data->ret, NULL);
80
- qemu_cond_init(&iothread->init_done_cond);
147
+ job_completed(job, data->ret);
81
iothread->once = (GOnce) G_ONCE_INIT;
148
g_free(data);
82
83
/* This assumes we are called from a thread with useful CPU affinity for us
84
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
85
g_free(name);
86
87
/* Wait for initialization to complete */
88
- qemu_mutex_lock(&iothread->init_done_lock);
89
while (iothread->thread_id == -1) {
90
- qemu_cond_wait(&iothread->init_done_cond,
91
- &iothread->init_done_lock);
92
+ qemu_sem_wait(&iothread->init_done_sem);
93
}
94
- qemu_mutex_unlock(&iothread->init_done_lock);
149
}
95
}
150
96
151
diff --git a/job-qmp.c b/job-qmp.c
97
typedef struct {
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
--
98
--
268
2.17.1
99
2.20.1
269
100
270
101
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
All jobs do the same thing when they leave their running loop:
4
- Store the return code in a structure
5
- wait to receive this structure in the main thread
6
- signal job completion via job_completed
7
8
Few jobs do anything beyond exactly this. Consolidate this exit
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>
28
---
29
include/qemu/job.h | 11 +++++++++++
30
job.c | 18 ++++++++++++++++++
31
2 files changed, 29 insertions(+)
32
33
diff --git a/include/qemu/job.h b/include/qemu/job.h
34
index XXXXXXX..XXXXXXX 100644
35
--- a/include/qemu/job.h
36
+++ b/include/qemu/job.h
37
@@ -XXX,XX +XXX,XX @@ struct JobDriver {
38
*/
39
void (*drain)(Job *job);
40
41
+ /**
42
+ * If the callback is not NULL, exit will be invoked from the main thread
43
+ * when the job's coroutine has finished, but before transactional
44
+ * convergence; before @prepare or @abort.
45
+ *
46
+ * FIXME TODO: This callback is only temporary to transition remaining jobs
47
+ * to prepare/commit/abort/clean callbacks and will be removed before 3.1.
48
+ * is released.
49
+ */
50
+ void (*exit)(Job *job);
51
+
52
/**
53
* If the callback is not NULL, prepare will be invoked when all the jobs
54
* belonging to the same transaction complete; or upon this job's completion
55
diff --git a/job.c b/job.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/job.c
58
+++ b/job.c
59
@@ -XXX,XX +XXX,XX @@ void job_drain(Job *job)
60
}
61
}
62
63
+static void job_exit(void *opaque)
64
+{
65
+ Job *job = (Job *)opaque;
66
+ AioContext *aio_context = job->aio_context;
67
+
68
+ if (job->driver->exit) {
69
+ aio_context_acquire(aio_context);
70
+ job->driver->exit(job);
71
+ aio_context_release(aio_context);
72
+ }
73
+ job_completed(job, job->ret);
74
+}
75
76
/**
77
* All jobs must allow a pause point before entering their job proper. This
78
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn job_co_entry(void *opaque)
79
assert(job && job->driver && job->driver->run);
80
job_pause_point(job);
81
job->ret = job->driver->run(job, &job->err);
82
+ if (!job->deferred_to_main_loop) {
83
+ job->deferred_to_main_loop = true;
84
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
85
+ job_exit,
86
+ job);
87
+ }
88
}
89
90
91
--
92
2.17.1
93
94
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Utilize the job_exit shim by not calling job_defer_to_main_loop, and
3
In existing code we create the gcontext dynamically at the first
4
where applicable, converting the deferred callback into the job_exit
4
access of the gcontext from caller. That can bring some complexity
5
callback.
5
and potential races during using iothread. Since the context itself
6
is not that big a resource, and we won't have millions of iothread,
7
let's simply create the gcontext unconditionally.
6
8
7
This converts backup, stream, create, and the unit tests all at once.
9
This will also be a preparation work further to move the thread
8
Most of these jobs do not see any changes to the order in which they
10
context push operation earlier than before (now it's only pushed right
9
clean up their resources, except the test-blockjob-txn test, which
11
before we want to start running the gmainloop).
10
now puts down its bs before job_completed is called.
11
12
12
This is safe for the same reason the reordering in the mirror job is
13
Removing the g_once since it's not necessary, while introducing a new
13
safe, because job_completed no longer runs under two locks, making
14
run_gcontext boolean to show whether we want to run the gcontext.
14
the unref safe even if it causes a flush.
15
15
16
Signed-off-by: John Snow <jsnow@redhat.com>
16
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Peter Xu <peterx@redhat.com>
18
Message-id: 20180830015734.19765-7-jsnow@redhat.com
18
Message-id: 20190306115532.23025-3-peterx@redhat.com
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
Message-Id: <20190306115532.23025-3-peterx@redhat.com>
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
---
21
---
21
block/backup.c | 16 ----------------
22
include/sysemu/iothread.h | 2 +-
22
block/create.c | 14 +++-----------
23
iothread.c | 43 +++++++++++++++++++--------------------
23
block/stream.c | 22 +++++++---------------
24
2 files changed, 22 insertions(+), 23 deletions(-)
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
25
29
diff --git a/block/backup.c b/block/backup.c
26
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
30
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
31
--- a/block/backup.c
28
--- a/include/sysemu/iothread.h
32
+++ b/block/backup.c
29
+++ b/include/sysemu/iothread.h
33
@@ -XXX,XX +XXX,XX @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
31
32
QemuThread thread;
33
AioContext *ctx;
34
+ bool run_gcontext; /* whether we should run gcontext */
35
GMainContext *worker_context;
36
GMainLoop *main_loop;
37
- GOnce once;
38
QemuSemaphore init_done_sem; /* is thread init done? */
39
bool stopping; /* has iothread_stop() been called? */
40
bool running; /* should iothread_run() continue? */
41
diff --git a/iothread.c b/iothread.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/iothread.c
44
+++ b/iothread.c
45
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
46
* We must check the running state again in case it was
47
* changed in previous aio_poll()
48
*/
49
- if (iothread->running && atomic_read(&iothread->worker_context)) {
50
+ if (iothread->running && atomic_read(&iothread->run_gcontext)) {
51
GMainLoop *loop;
52
53
g_main_context_push_thread_default(iothread->worker_context);
54
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_init(Object *obj)
55
iothread->poll_max_ns = IOTHREAD_POLL_MAX_NS_DEFAULT;
56
iothread->thread_id = -1;
57
qemu_sem_init(&iothread->init_done_sem, 0);
58
+ /* By default, we don't run gcontext */
59
+ atomic_set(&iothread->run_gcontext, 0);
60
}
61
62
static void iothread_instance_finalize(Object *obj)
63
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_finalize(Object *obj)
64
qemu_sem_destroy(&iothread->init_done_sem);
65
}
66
67
+static void iothread_init_gcontext(IOThread *iothread)
68
+{
69
+ GSource *source;
70
+
71
+ iothread->worker_context = g_main_context_new();
72
+ source = aio_get_g_source(iothread_get_aio_context(iothread));
73
+ g_source_attach(source, iothread->worker_context);
74
+ g_source_unref(source);
75
+}
76
+
77
static void iothread_complete(UserCreatable *obj, Error **errp)
78
{
79
Error *local_error = NULL;
80
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
81
return;
34
}
82
}
83
84
+ /*
85
+ * Init one GMainContext for the iothread unconditionally, even if
86
+ * it's not used
87
+ */
88
+ iothread_init_gcontext(iothread);
89
+
90
aio_context_set_poll_params(iothread->ctx,
91
iothread->poll_max_ns,
92
iothread->poll_grow,
93
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
94
return;
95
}
96
97
- iothread->once = (GOnce) G_ONCE_INIT;
98
-
99
/* This assumes we are called from a thread with useful CPU affinity for us
100
* to inherit.
101
*/
102
@@ -XXX,XX +XXX,XX @@ IOThreadInfoList *qmp_query_iothreads(Error **errp)
103
return head;
35
}
104
}
36
105
37
-typedef struct {
106
-static gpointer iothread_g_main_context_init(gpointer opaque)
38
- int ret;
107
-{
39
-} BackupCompleteData;
108
- AioContext *ctx;
109
- IOThread *iothread = opaque;
110
- GSource *source;
40
-
111
-
41
-static void backup_complete(Job *job, void *opaque)
112
- iothread->worker_context = g_main_context_new();
42
-{
43
- BackupCompleteData *data = opaque;
44
-
113
-
45
- job_completed(job, data->ret);
114
- ctx = iothread_get_aio_context(iothread);
46
- g_free(data);
115
- source = aio_get_g_source(ctx);
116
- g_source_attach(source, iothread->worker_context);
117
- g_source_unref(source);
118
-
119
- aio_notify(iothread->ctx);
120
- return NULL;
47
-}
121
-}
48
-
122
-
49
static bool coroutine_fn yield_and_check(BackupBlockJob *job)
123
GMainContext *iothread_get_g_main_context(IOThread *iothread)
50
{
124
{
51
uint64_t delay_ns;
125
- g_once(&iothread->once, iothread_g_main_context_init, iothread);
52
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
126
-
53
static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
127
+ atomic_set(&iothread->run_gcontext, 1);
54
{
128
+ aio_notify(iothread->ctx);
55
BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
129
return iothread->worker_context;
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
}
130
}
69
131
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
--
132
--
291
2.17.1
133
2.20.1
292
134
293
135
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Change the manual deferment to mirror_exit into the implicit
3
Since we've have the gcontext always there, create the main loop
4
callback to job_exit and the mirror_exit callback.
4
altogether. The iothread_run() is even cleaner.
5
5
6
This does change the order of some bdrv_unref calls and job_completed,
6
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
but thanks to the new context in which we call .exit, this is safe to
7
Signed-off-by: Peter Xu <peterx@redhat.com>
8
defer the possible flushing of any nodes to the job_finalize_single
8
Message-id: 20190306115532.23025-4-peterx@redhat.com
9
cleanup stage.
9
Message-Id: <20190306115532.23025-4-peterx@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
iothread.c | 12 +++---------
13
1 file changed, 3 insertions(+), 9 deletions(-)
10
14
11
Signed-off-by: John Snow <jsnow@redhat.com>
15
diff --git a/iothread.c b/iothread.c
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(-)
19
20
diff --git a/block/mirror.c b/block/mirror.c
21
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
22
--- a/block/mirror.c
17
--- a/iothread.c
23
+++ b/block/mirror.c
18
+++ b/iothread.c
24
@@ -XXX,XX +XXX,XX @@ static void mirror_wait_for_all_io(MirrorBlockJob *s)
19
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
25
}
20
* changed in previous aio_poll()
26
}
21
*/
27
22
if (iothread->running && atomic_read(&iothread->run_gcontext)) {
28
-typedef struct {
23
- GMainLoop *loop;
29
- int ret;
30
-} MirrorExitData;
31
-
24
-
32
-static void mirror_exit(Job *job, void *opaque)
25
g_main_context_push_thread_default(iothread->worker_context);
33
+static void mirror_exit(Job *job)
26
- iothread->main_loop =
34
{
27
- g_main_loop_new(iothread->worker_context, TRUE);
35
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
28
- loop = iothread->main_loop;
36
BlockJob *bjob = &s->common;
29
-
37
- MirrorExitData *data = opaque;
30
g_main_loop_run(iothread->main_loop);
38
MirrorBDSOpaque *bs_opaque = s->mirror_top_bs->opaque;
31
- iothread->main_loop = NULL;
39
AioContext *replace_aio_context = NULL;
32
- g_main_loop_unref(loop);
40
BlockDriverState *src = s->mirror_top_bs->backing->bs;
33
-
41
BlockDriverState *target_bs = blk_bs(s->target);
34
g_main_context_pop_thread_default(iothread->worker_context);
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
}
35
}
63
}
36
}
64
@@ -XXX,XX +XXX,XX @@ static void mirror_exit(Job *job, void *opaque)
37
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_finalize(Object *obj)
65
aio_context_acquire(replace_aio_context);
38
if (iothread->worker_context) {
39
g_main_context_unref(iothread->worker_context);
40
iothread->worker_context = NULL;
41
+ g_main_loop_unref(iothread->main_loop);
42
+ iothread->main_loop = NULL;
66
}
43
}
67
44
qemu_sem_destroy(&iothread->init_done_sem);
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);
92
+
93
+ job->ret = ret;
94
}
45
}
95
46
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
96
static void mirror_throttle(MirrorBlockJob *s)
47
source = aio_get_g_source(iothread_get_aio_context(iothread));
97
@@ -XXX,XX +XXX,XX @@ static int mirror_flush(MirrorBlockJob *s)
48
g_source_attach(source, iothread->worker_context);
98
static int coroutine_fn mirror_run(Job *job, Error **errp)
49
g_source_unref(source);
99
{
50
+ iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
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
}
51
}
119
52
120
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver mirror_job_driver = {
53
static void iothread_complete(UserCreatable *obj, Error **errp)
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
},
136
--
54
--
137
2.17.1
55
2.20.1
138
56
139
57
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Rename opaque_job to job to be consistent with other job implementations.
3
We were pushing the context until right before running the gmainloop.
4
Rename 'job', the BackupBlockJob object, to 's' to also be consistent.
4
Now since we have everything unconditionally, we can move this
5
earlier.
5
6
6
Suggested-by: Eric Blake <eblake@redhat.com>
7
One benefit is that now it's done even before init_done_sem, so as
7
Signed-off-by: John Snow <jsnow@redhat.com>
8
long as the iothread user calls iothread_create() and completes, we
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
know that the thread stack is ready.
9
Message-id: 20180830015734.19765-8-jsnow@redhat.com
10
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Peter Xu <peterx@redhat.com>
12
Message-id: 20190306115532.23025-5-peterx@redhat.com
13
Message-Id: <20190306115532.23025-5-peterx@redhat.com>
14
15
[Tweaked comment wording as discussed with Peter Xu.
16
--Stefan]
17
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
19
---
12
block/backup.c | 62 +++++++++++++++++++++++++-------------------------
20
iothread.c | 9 ++++++---
13
1 file changed, 31 insertions(+), 31 deletions(-)
21
1 file changed, 6 insertions(+), 3 deletions(-)
14
22
15
diff --git a/block/backup.c b/block/backup.c
23
diff --git a/iothread.c b/iothread.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/block/backup.c
25
--- a/iothread.c
18
+++ b/block/backup.c
26
+++ b/iothread.c
19
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
27
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
20
bdrv_dirty_iter_free(dbi);
28
IOThread *iothread = opaque;
21
}
29
22
30
rcu_register_thread();
23
-static int coroutine_fn backup_run(Job *opaque_job, Error **errp)
31
-
24
+static int coroutine_fn backup_run(Job *job, Error **errp)
32
+ /*
25
{
33
+ * g_main_context_push_thread_default() must be called before anything
26
- BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job);
34
+ * in this new thread uses glib.
27
- BlockDriverState *bs = blk_bs(job->common.blk);
35
+ */
28
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
36
+ g_main_context_push_thread_default(iothread->worker_context);
29
+ BlockDriverState *bs = blk_bs(s->common.blk);
37
my_iothread = iothread;
30
int64_t offset, nb_clusters;
38
iothread->thread_id = qemu_get_thread_id();
31
int ret = 0;
39
qemu_sem_post(&iothread->init_done_sem);
32
40
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
33
- QLIST_INIT(&job->inflight_reqs);
41
* changed in previous aio_poll()
34
- qemu_co_rwlock_init(&job->flush_rwlock);
42
*/
35
+ QLIST_INIT(&s->inflight_reqs);
43
if (iothread->running && atomic_read(&iothread->run_gcontext)) {
36
+ qemu_co_rwlock_init(&s->flush_rwlock);
44
- g_main_context_push_thread_default(iothread->worker_context);
37
45
g_main_loop_run(iothread->main_loop);
38
- nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size);
46
- g_main_context_pop_thread_default(iothread->worker_context);
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);
52
}
53
54
55
- job->before_write.notify = backup_before_write_notify;
56
- bdrv_add_before_write_notifier(bs, &job->before_write);
57
+ s->before_write.notify = backup_before_write_notify;
58
+ bdrv_add_before_write_notifier(bs, &s->before_write);
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
}
47
}
133
}
48
}
134
49
135
- notifier_with_return_remove(&job->before_write);
50
+ g_main_context_pop_thread_default(iothread->worker_context);
136
+ notifier_with_return_remove(&s->before_write);
51
rcu_unregister_thread();
137
52
return NULL;
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
}
53
}
148
--
54
--
149
2.17.1
55
2.20.1
150
56
151
57
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Change the manual deferment to commit_complete into the implicit
3
After consulting Paolo I know why we'd better keep the explicit
4
callback to job_exit, renaming commit_complete to commit_exit.
4
aio_poll() in iothread_run(). Document it directly into the code so
5
that future readers will know the answer from day one.
5
6
6
This conversion does change the timing of when job_completed is
7
Signed-off-by: Peter Xu <peterx@redhat.com>
7
called to after the bdrv_replace_node and bdrv_unref calls, which
8
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
could have implications for bjob->blk which will now be put down
9
Message-id: 20190306115532.23025-6-peterx@redhat.com
9
after this cleanup.
10
Message-Id: <20190306115532.23025-6-peterx@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
iothread.c | 9 +++++++++
14
1 file changed, 9 insertions(+)
10
15
11
Kevin highlights that we did not take any permissions for that backend
16
diff --git a/iothread.c b/iothread.c
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>
19
---
20
block/commit.c | 22 +++++-----------------
21
1 file changed, 5 insertions(+), 17 deletions(-)
22
23
diff --git a/block/commit.c b/block/commit.c
24
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
25
--- a/block/commit.c
18
--- a/iothread.c
26
+++ b/block/commit.c
19
+++ b/iothread.c
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
20
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
28
return 0;
21
qemu_sem_post(&iothread->init_done_sem);
29
}
22
30
23
while (iothread->running) {
31
-typedef struct {
24
+ /*
32
- int ret;
25
+ * Note: from functional-wise the g_main_loop_run() below can
33
-} CommitCompleteData;
26
+ * already cover the aio_poll() events, but we can't run the
34
-
27
+ * main loop unconditionally because explicit aio_poll() here
35
-static void commit_complete(Job *job, void *opaque)
28
+ * is faster than g_main_loop_run() when we do not need the
36
+static void commit_exit(Job *job)
29
+ * gcontext at all (e.g., pure block layer iothreads). In
37
{
30
+ * other words, when we want to run the gcontext with the
38
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
31
+ * iothread we need to pay some performance for functionality.
39
BlockJob *bjob = &s->common;
32
+ */
40
- CommitCompleteData *data = opaque;
33
aio_poll(iothread->ctx, true);
41
BlockDriverState *top = blk_bs(s->top);
34
42
BlockDriverState *base = blk_bs(s->base);
35
/*
43
BlockDriverState *commit_top_bs = s->commit_top_bs;
44
- int ret = data->ret;
45
bool remove_commit_top_bs = false;
46
47
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
48
@@ -XXX,XX +XXX,XX @@ static void commit_complete(Job *job, void *opaque)
49
* the normal backing chain can be restored. */
50
blk_unref(s->base);
51
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
};
97
98
--
36
--
99
2.17.1
37
2.20.1
100
38
101
39
diff view generated by jsdifflib