blob: 0f1bc77b1ddf2100616a078165b742862bd4f601 [file] [log] [blame]
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +02001/*
2 * QEMU System Emulator block driver
3 *
4 * Copyright (c) 2011 IBM Corp.
5 * Copyright (c) 2012 Red Hat, Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
Peter Maydelld38ea872016-01-29 17:50:05 +000026#include "qemu/osdep.h"
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020027#include "qemu-common.h"
28#include "trace.h"
Paolo Bonzini737e1502012-12-17 18:19:44 +010029#include "block/block.h"
30#include "block/blockjob.h"
31#include "block/block_int.h"
Max Reitz373340b2015-10-19 17:53:22 +020032#include "sysemu/block-backend.h"
Markus Armbrustercc7a8ea2015-03-17 17:22:46 +010033#include "qapi/qmp/qerror.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010034#include "qapi/qmp/qjson.h"
Daniel P. Berrange10817bf2015-09-01 14:48:02 +010035#include "qemu/coroutine.h"
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020036#include "qmp-commands.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010037#include "qemu/timer.h"
Wenchao Xia5a2d2cb2014-06-18 08:43:45 +020038#include "qapi-event.h"
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020039
Fam Zhengc55a8322015-11-05 18:13:15 -050040/* Transactional group of block jobs */
41struct BlockJobTxn {
42
43 /* Is this txn being cancelled? */
44 bool aborting;
45
46 /* List of jobs */
47 QLIST_HEAD(, BlockJob) jobs;
48
49 /* Reference count */
50 int refcnt;
51};
52
Alberto Garciaa7112792016-04-04 16:43:51 +030053static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
54
55BlockJob *block_job_next(BlockJob *job)
56{
57 if (!job) {
58 return QLIST_FIRST(&block_jobs);
59 }
60 return QLIST_NEXT(job, job_list);
61}
62
Fam Zheng3fc4b102013-10-08 17:29:38 +080063void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
Markus Armbruster097310b2014-10-07 13:59:15 +020064 int64_t speed, BlockCompletionFunc *cb,
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020065 void *opaque, Error **errp)
66{
67 BlockJob *job;
68
Fam Zheng628ff682014-05-23 21:29:44 +080069 if (bs->job) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +010070 error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020071 return NULL;
72 }
Fam Zhengfa510eb2013-08-23 09:14:51 +080073 bdrv_ref(bs);
Fam Zheng3fc4b102013-10-08 17:29:38 +080074 job = g_malloc0(driver->instance_size);
Fam Zheng3718d8a2014-05-23 21:29:43 +080075 error_setg(&job->blocker, "block device is in use by block job: %s",
76 BlockJobType_lookup[driver->job_type]);
77 bdrv_op_block_all(bs, job->blocker);
Stefan Hajnoczib112a652014-10-21 12:04:00 +010078 bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
Fam Zheng3718d8a2014-05-23 21:29:43 +080079
Fam Zheng3fc4b102013-10-08 17:29:38 +080080 job->driver = driver;
Kevin Wolf8ccb9562015-09-16 13:34:54 +020081 job->id = g_strdup(bdrv_get_device_name(bs));
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020082 job->bs = bs;
83 job->cb = cb;
84 job->opaque = opaque;
85 job->busy = true;
Fam Zheng18930ba2015-11-05 18:13:11 -050086 job->refcnt = 1;
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020087 bs->job = job;
88
Alberto Garciaa7112792016-04-04 16:43:51 +030089 QLIST_INSERT_HEAD(&block_jobs, job, job_list);
90
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020091 /* Only set speed when necessary to avoid NotSupported error */
92 if (speed != 0) {
93 Error *local_err = NULL;
94
95 block_job_set_speed(job, speed, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +010096 if (local_err) {
Fam Zheng18930ba2015-11-05 18:13:11 -050097 block_job_unref(job);
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +020098 error_propagate(errp, local_err);
99 return NULL;
100 }
101 }
102 return job;
103}
104
Fam Zheng18930ba2015-11-05 18:13:11 -0500105void block_job_ref(BlockJob *job)
Ting Wang97031162015-06-26 17:37:35 +0800106{
Fam Zheng18930ba2015-11-05 18:13:11 -0500107 ++job->refcnt;
108}
Ting Wang97031162015-06-26 17:37:35 +0800109
Fam Zheng18930ba2015-11-05 18:13:11 -0500110void block_job_unref(BlockJob *job)
111{
112 if (--job->refcnt == 0) {
113 job->bs->job = NULL;
114 bdrv_op_unblock_all(job->bs, job->blocker);
115 bdrv_unref(job->bs);
116 error_free(job->blocker);
117 g_free(job->id);
Alberto Garciaa7112792016-04-04 16:43:51 +0300118 QLIST_REMOVE(job, job_list);
Fam Zheng18930ba2015-11-05 18:13:11 -0500119 g_free(job);
120 }
Ting Wang97031162015-06-26 17:37:35 +0800121}
122
Fam Zhengc55a8322015-11-05 18:13:15 -0500123static void block_job_completed_single(BlockJob *job)
124{
125 if (!job->ret) {
126 if (job->driver->commit) {
127 job->driver->commit(job);
128 }
129 } else {
130 if (job->driver->abort) {
131 job->driver->abort(job);
132 }
133 }
134 job->cb(job->opaque, job->ret);
135 if (job->txn) {
136 block_job_txn_unref(job->txn);
137 }
138 block_job_unref(job);
139}
140
141static void block_job_completed_txn_abort(BlockJob *job)
142{
143 AioContext *ctx;
144 BlockJobTxn *txn = job->txn;
145 BlockJob *other_job, *next;
146
147 if (txn->aborting) {
148 /*
149 * We are cancelled by another job, which will handle everything.
150 */
151 return;
152 }
153 txn->aborting = true;
154 /* We are the first failed job. Cancel other jobs. */
155 QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
156 ctx = bdrv_get_aio_context(other_job->bs);
157 aio_context_acquire(ctx);
158 }
159 QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
160 if (other_job == job || other_job->completed) {
161 /* Other jobs are "effectively" cancelled by us, set the status for
162 * them; this job, however, may or may not be cancelled, depending
163 * on the caller, so leave it. */
164 if (other_job != job) {
165 other_job->cancelled = true;
166 }
167 continue;
168 }
169 block_job_cancel_sync(other_job);
170 assert(other_job->completed);
171 }
172 QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
173 ctx = bdrv_get_aio_context(other_job->bs);
174 block_job_completed_single(other_job);
175 aio_context_release(ctx);
176 }
177}
178
179static void block_job_completed_txn_success(BlockJob *job)
180{
181 AioContext *ctx;
182 BlockJobTxn *txn = job->txn;
183 BlockJob *other_job, *next;
184 /*
185 * Successful completion, see if there are other running jobs in this
186 * txn.
187 */
188 QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
189 if (!other_job->completed) {
190 return;
191 }
192 }
193 /* We are the last completed job, commit the transaction. */
194 QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
195 ctx = bdrv_get_aio_context(other_job->bs);
196 aio_context_acquire(ctx);
197 assert(other_job->ret == 0);
198 block_job_completed_single(other_job);
199 aio_context_release(ctx);
200 }
201}
202
Paolo Bonzini65f46322012-10-18 16:49:20 +0200203void block_job_completed(BlockJob *job, int ret)
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200204{
205 BlockDriverState *bs = job->bs;
206
207 assert(bs->job == job);
Fam Zhenga689dbf2015-11-05 18:13:13 -0500208 assert(!job->completed);
209 job->completed = true;
210 job->ret = ret;
Fam Zhengc55a8322015-11-05 18:13:15 -0500211 if (!job->txn) {
212 block_job_completed_single(job);
213 } else if (ret < 0 || block_job_is_cancelled(job)) {
214 block_job_completed_txn_abort(job);
215 } else {
216 block_job_completed_txn_success(job);
217 }
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200218}
219
220void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
221{
222 Error *local_err = NULL;
223
Fam Zheng3fc4b102013-10-08 17:29:38 +0800224 if (!job->driver->set_speed) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100225 error_setg(errp, QERR_UNSUPPORTED);
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200226 return;
227 }
Fam Zheng3fc4b102013-10-08 17:29:38 +0800228 job->driver->set_speed(job, speed, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +0100229 if (local_err) {
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200230 error_propagate(errp, local_err);
231 return;
232 }
233
234 job->speed = speed;
235}
236
Paolo Bonziniaeae8832012-10-18 16:49:21 +0200237void block_job_complete(BlockJob *job, Error **errp)
238{
Fam Zheng751ebd72015-04-03 22:05:18 +0800239 if (job->pause_count || job->cancelled || !job->driver->complete) {
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200240 error_setg(errp, QERR_BLOCK_JOB_NOT_READY, job->id);
Paolo Bonziniaeae8832012-10-18 16:49:21 +0200241 return;
242 }
243
Fam Zheng3fc4b102013-10-08 17:29:38 +0800244 job->driver->complete(job, errp);
Paolo Bonziniaeae8832012-10-18 16:49:21 +0200245}
246
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200247void block_job_pause(BlockJob *job)
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200248{
Fam Zheng751ebd72015-04-03 22:05:18 +0800249 job->pause_count++;
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200250}
251
252bool block_job_is_paused(BlockJob *job)
253{
Fam Zheng751ebd72015-04-03 22:05:18 +0800254 return job->pause_count > 0;
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200255}
256
257void block_job_resume(BlockJob *job)
258{
Fam Zheng751ebd72015-04-03 22:05:18 +0800259 assert(job->pause_count > 0);
260 job->pause_count--;
261 if (job->pause_count) {
262 return;
263 }
264 block_job_enter(job);
265}
266
267void block_job_enter(BlockJob *job)
268{
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200269 block_job_iostatus_reset(job);
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200270 if (job->co && !job->busy) {
271 qemu_coroutine_enter(job->co, NULL);
272 }
273}
274
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200275void block_job_cancel(BlockJob *job)
276{
277 job->cancelled = true;
Fam Zheng751ebd72015-04-03 22:05:18 +0800278 block_job_enter(job);
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200279}
280
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200281bool block_job_is_cancelled(BlockJob *job)
282{
283 return job->cancelled;
284}
285
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200286void block_job_iostatus_reset(BlockJob *job)
287{
288 job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
Fam Zheng3fc4b102013-10-08 17:29:38 +0800289 if (job->driver->iostatus_reset) {
290 job->driver->iostatus_reset(job);
Paolo Bonzini3bd293c2012-10-18 16:49:27 +0200291 }
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200292}
293
Max Reitz345f9e12014-10-24 15:57:33 +0200294static int block_job_finish_sync(BlockJob *job,
295 void (*finish)(BlockJob *, Error **errp),
296 Error **errp)
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200297{
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200298 BlockDriverState *bs = job->bs;
Max Reitz345f9e12014-10-24 15:57:33 +0200299 Error *local_err = NULL;
Fam Zheng94db6d22015-11-05 18:13:14 -0500300 int ret;
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200301
302 assert(bs->job == job);
303
Fam Zheng94db6d22015-11-05 18:13:14 -0500304 block_job_ref(job);
Max Reitz345f9e12014-10-24 15:57:33 +0200305 finish(job, &local_err);
306 if (local_err) {
307 error_propagate(errp, local_err);
Fam Zheng94db6d22015-11-05 18:13:14 -0500308 block_job_unref(job);
Max Reitz345f9e12014-10-24 15:57:33 +0200309 return -EBUSY;
310 }
Fam Zheng94db6d22015-11-05 18:13:14 -0500311 while (!job->completed) {
Fam Zheng794f0142016-02-02 10:12:24 +0800312 aio_poll(job->deferred_to_main_loop ? qemu_get_aio_context() :
313 bdrv_get_aio_context(bs),
314 true);
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200315 }
Fam Zheng94db6d22015-11-05 18:13:14 -0500316 ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
317 block_job_unref(job);
318 return ret;
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200319}
320
Max Reitz345f9e12014-10-24 15:57:33 +0200321/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
322 * used with block_job_finish_sync() without the need for (rather nasty)
323 * function pointer casts there. */
324static void block_job_cancel_err(BlockJob *job, Error **errp)
325{
326 block_job_cancel(job);
327}
328
329int block_job_cancel_sync(BlockJob *job)
330{
331 return block_job_finish_sync(job, &block_job_cancel_err, NULL);
332}
333
334int block_job_complete_sync(BlockJob *job, Error **errp)
335{
336 return block_job_finish_sync(job, &block_job_complete, errp);
337}
338
Alex Bligh7483d1e2013-08-21 16:03:05 +0100339void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200340{
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200341 assert(job->busy);
342
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200343 /* Check cancellation *before* setting busy = false, too! */
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200344 if (block_job_is_cancelled(job)) {
345 return;
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200346 }
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200347
348 job->busy = false;
349 if (block_job_is_paused(job)) {
350 qemu_coroutine_yield();
351 } else {
Fam Zheng0b9caf92014-08-26 15:15:43 +0800352 co_aio_sleep_ns(bdrv_get_aio_context(job->bs), type, ns);
Paolo Bonzini8acc72a2012-09-28 17:22:50 +0200353 }
354 job->busy = true;
Paolo Bonzini2f0c9fe2012-09-28 17:22:47 +0200355}
Paolo Bonzini30e628b2012-09-28 17:22:48 +0200356
Fam Zhengdc71ce42014-06-24 20:26:35 +0800357void block_job_yield(BlockJob *job)
358{
359 assert(job->busy);
360
361 /* Check cancellation *before* setting busy = false, too! */
362 if (block_job_is_cancelled(job)) {
363 return;
364 }
365
366 job->busy = false;
367 qemu_coroutine_yield();
368 job->busy = true;
369}
370
Paolo Bonzini30e628b2012-09-28 17:22:48 +0200371BlockJobInfo *block_job_query(BlockJob *job)
372{
373 BlockJobInfo *info = g_new0(BlockJobInfo, 1);
Fam Zheng79e14bf2013-10-08 17:29:40 +0800374 info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]);
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200375 info->device = g_strdup(job->id);
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200376 info->len = job->len;
377 info->busy = job->busy;
Fam Zheng751ebd72015-04-03 22:05:18 +0800378 info->paused = job->pause_count > 0;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200379 info->offset = job->offset;
380 info->speed = job->speed;
381 info->io_status = job->iostatus;
Max Reitzef6dbf12014-10-24 15:57:34 +0200382 info->ready = job->ready;
Paolo Bonzini30e628b2012-09-28 17:22:48 +0200383 return info;
384}
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200385
386static void block_job_iostatus_set_err(BlockJob *job, int error)
387{
388 if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
389 job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
390 BLOCK_DEVICE_IO_STATUS_FAILED;
391 }
392}
393
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200394void block_job_event_cancelled(BlockJob *job)
Paolo Bonzinia66a2a32012-07-23 15:15:47 +0200395{
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200396 qapi_event_send_block_job_cancelled(job->driver->job_type,
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200397 job->id,
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200398 job->len,
399 job->offset,
400 job->speed,
401 &error_abort);
Paolo Bonzinia66a2a32012-07-23 15:15:47 +0200402}
403
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200404void block_job_event_completed(BlockJob *job, const char *msg)
Paolo Bonzinia66a2a32012-07-23 15:15:47 +0200405{
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200406 qapi_event_send_block_job_completed(job->driver->job_type,
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200407 job->id,
Wenchao Xiabcada37b2014-06-18 08:43:47 +0200408 job->len,
409 job->offset,
410 job->speed,
411 !!msg,
412 msg,
413 &error_abort);
414}
415
416void block_job_event_ready(BlockJob *job)
417{
Max Reitzef6dbf12014-10-24 15:57:34 +0200418 job->ready = true;
419
Markus Armbruster518848a2014-06-27 19:24:13 +0200420 qapi_event_send_block_job_ready(job->driver->job_type,
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200421 job->id,
Markus Armbruster518848a2014-06-27 19:24:13 +0200422 job->len,
423 job->offset,
424 job->speed, &error_abort);
Paolo Bonzinia66a2a32012-07-23 15:15:47 +0200425}
426
Kevin Wolf81e254d2016-04-18 11:36:38 +0200427BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200428 int is_read, int error)
429{
430 BlockErrorAction action;
431
432 switch (on_err) {
433 case BLOCKDEV_ON_ERROR_ENOSPC:
Wenchao Xiaa5895692014-06-18 08:43:30 +0200434 action = (error == ENOSPC) ?
435 BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200436 break;
437 case BLOCKDEV_ON_ERROR_STOP:
Wenchao Xiaa5895692014-06-18 08:43:30 +0200438 action = BLOCK_ERROR_ACTION_STOP;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200439 break;
440 case BLOCKDEV_ON_ERROR_REPORT:
Wenchao Xiaa5895692014-06-18 08:43:30 +0200441 action = BLOCK_ERROR_ACTION_REPORT;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200442 break;
443 case BLOCKDEV_ON_ERROR_IGNORE:
Wenchao Xiaa5895692014-06-18 08:43:30 +0200444 action = BLOCK_ERROR_ACTION_IGNORE;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200445 break;
446 default:
447 abort();
448 }
Kevin Wolf8ccb9562015-09-16 13:34:54 +0200449 qapi_event_send_block_job_error(job->id,
Wenchao Xia5a2d2cb2014-06-18 08:43:45 +0200450 is_read ? IO_OPERATION_TYPE_READ :
451 IO_OPERATION_TYPE_WRITE,
452 action, &error_abort);
Wenchao Xiaa5895692014-06-18 08:43:30 +0200453 if (action == BLOCK_ERROR_ACTION_STOP) {
Fam Zheng751ebd72015-04-03 22:05:18 +0800454 /* make the pause user visible, which will be resumed from QMP. */
455 job->user_paused = true;
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200456 block_job_pause(job);
457 block_job_iostatus_set_err(job, error);
Paolo Bonzini32c81a42012-09-28 17:22:58 +0200458 }
459 return action;
460}
Stefan Hajnoczidec7d422014-10-21 12:03:54 +0100461
462typedef struct {
463 BlockJob *job;
464 QEMUBH *bh;
465 AioContext *aio_context;
466 BlockJobDeferToMainLoopFn *fn;
467 void *opaque;
468} BlockJobDeferToMainLoopData;
469
470static void block_job_defer_to_main_loop_bh(void *opaque)
471{
472 BlockJobDeferToMainLoopData *data = opaque;
473 AioContext *aio_context;
474
475 qemu_bh_delete(data->bh);
476
477 /* Prevent race with block_job_defer_to_main_loop() */
478 aio_context_acquire(data->aio_context);
479
480 /* Fetch BDS AioContext again, in case it has changed */
481 aio_context = bdrv_get_aio_context(data->job->bs);
482 aio_context_acquire(aio_context);
483
Fam Zheng794f0142016-02-02 10:12:24 +0800484 data->job->deferred_to_main_loop = false;
Stefan Hajnoczidec7d422014-10-21 12:03:54 +0100485 data->fn(data->job, data->opaque);
486
487 aio_context_release(aio_context);
488
489 aio_context_release(data->aio_context);
490
491 g_free(data);
492}
493
494void block_job_defer_to_main_loop(BlockJob *job,
495 BlockJobDeferToMainLoopFn *fn,
496 void *opaque)
497{
498 BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
499 data->job = job;
500 data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
501 data->aio_context = bdrv_get_aio_context(job->bs);
502 data->fn = fn;
503 data->opaque = opaque;
Fam Zheng794f0142016-02-02 10:12:24 +0800504 job->deferred_to_main_loop = true;
Stefan Hajnoczidec7d422014-10-21 12:03:54 +0100505
506 qemu_bh_schedule(data->bh);
507}
Fam Zhengc55a8322015-11-05 18:13:15 -0500508
509BlockJobTxn *block_job_txn_new(void)
510{
511 BlockJobTxn *txn = g_new0(BlockJobTxn, 1);
512 QLIST_INIT(&txn->jobs);
513 txn->refcnt = 1;
514 return txn;
515}
516
517static void block_job_txn_ref(BlockJobTxn *txn)
518{
519 txn->refcnt++;
520}
521
522void block_job_txn_unref(BlockJobTxn *txn)
523{
524 if (txn && --txn->refcnt == 0) {
525 g_free(txn);
526 }
527}
528
529void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job)
530{
531 if (!txn) {
532 return;
533 }
534
535 assert(!job->txn);
536 job->txn = txn;
537
538 QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
539 block_job_txn_ref(txn);
540}