xref: /qemu/blockjob.c (revision 30e628b7)
12f0c9fe6SPaolo Bonzini /*
22f0c9fe6SPaolo Bonzini  * QEMU System Emulator block driver
32f0c9fe6SPaolo Bonzini  *
42f0c9fe6SPaolo Bonzini  * Copyright (c) 2011 IBM Corp.
52f0c9fe6SPaolo Bonzini  * Copyright (c) 2012 Red Hat, Inc.
62f0c9fe6SPaolo Bonzini  *
72f0c9fe6SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
82f0c9fe6SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
92f0c9fe6SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
102f0c9fe6SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
112f0c9fe6SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
122f0c9fe6SPaolo Bonzini  * furnished to do so, subject to the following conditions:
132f0c9fe6SPaolo Bonzini  *
142f0c9fe6SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
152f0c9fe6SPaolo Bonzini  * all copies or substantial portions of the Software.
162f0c9fe6SPaolo Bonzini  *
172f0c9fe6SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
182f0c9fe6SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
192f0c9fe6SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
202f0c9fe6SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
212f0c9fe6SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
222f0c9fe6SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
232f0c9fe6SPaolo Bonzini  * THE SOFTWARE.
242f0c9fe6SPaolo Bonzini  */
252f0c9fe6SPaolo Bonzini 
262f0c9fe6SPaolo Bonzini #include "config-host.h"
272f0c9fe6SPaolo Bonzini #include "qemu-common.h"
282f0c9fe6SPaolo Bonzini #include "trace.h"
292f0c9fe6SPaolo Bonzini #include "monitor.h"
302f0c9fe6SPaolo Bonzini #include "block.h"
312f0c9fe6SPaolo Bonzini #include "blockjob.h"
322f0c9fe6SPaolo Bonzini #include "block_int.h"
332f0c9fe6SPaolo Bonzini #include "qjson.h"
342f0c9fe6SPaolo Bonzini #include "qemu-coroutine.h"
352f0c9fe6SPaolo Bonzini #include "qmp-commands.h"
362f0c9fe6SPaolo Bonzini #include "qemu-timer.h"
372f0c9fe6SPaolo Bonzini 
382f0c9fe6SPaolo Bonzini void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
392f0c9fe6SPaolo Bonzini                        int64_t speed, BlockDriverCompletionFunc *cb,
402f0c9fe6SPaolo Bonzini                        void *opaque, Error **errp)
412f0c9fe6SPaolo Bonzini {
422f0c9fe6SPaolo Bonzini     BlockJob *job;
432f0c9fe6SPaolo Bonzini 
442f0c9fe6SPaolo Bonzini     if (bs->job || bdrv_in_use(bs)) {
452f0c9fe6SPaolo Bonzini         error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
462f0c9fe6SPaolo Bonzini         return NULL;
472f0c9fe6SPaolo Bonzini     }
482f0c9fe6SPaolo Bonzini     bdrv_set_in_use(bs, 1);
492f0c9fe6SPaolo Bonzini 
502f0c9fe6SPaolo Bonzini     job = g_malloc0(job_type->instance_size);
512f0c9fe6SPaolo Bonzini     job->job_type      = job_type;
522f0c9fe6SPaolo Bonzini     job->bs            = bs;
532f0c9fe6SPaolo Bonzini     job->cb            = cb;
542f0c9fe6SPaolo Bonzini     job->opaque        = opaque;
552f0c9fe6SPaolo Bonzini     job->busy          = true;
562f0c9fe6SPaolo Bonzini     bs->job = job;
572f0c9fe6SPaolo Bonzini 
582f0c9fe6SPaolo Bonzini     /* Only set speed when necessary to avoid NotSupported error */
592f0c9fe6SPaolo Bonzini     if (speed != 0) {
602f0c9fe6SPaolo Bonzini         Error *local_err = NULL;
612f0c9fe6SPaolo Bonzini 
622f0c9fe6SPaolo Bonzini         block_job_set_speed(job, speed, &local_err);
632f0c9fe6SPaolo Bonzini         if (error_is_set(&local_err)) {
642f0c9fe6SPaolo Bonzini             bs->job = NULL;
652f0c9fe6SPaolo Bonzini             g_free(job);
662f0c9fe6SPaolo Bonzini             bdrv_set_in_use(bs, 0);
672f0c9fe6SPaolo Bonzini             error_propagate(errp, local_err);
682f0c9fe6SPaolo Bonzini             return NULL;
692f0c9fe6SPaolo Bonzini         }
702f0c9fe6SPaolo Bonzini     }
712f0c9fe6SPaolo Bonzini     return job;
722f0c9fe6SPaolo Bonzini }
732f0c9fe6SPaolo Bonzini 
742f0c9fe6SPaolo Bonzini void block_job_complete(BlockJob *job, int ret)
752f0c9fe6SPaolo Bonzini {
762f0c9fe6SPaolo Bonzini     BlockDriverState *bs = job->bs;
772f0c9fe6SPaolo Bonzini 
782f0c9fe6SPaolo Bonzini     assert(bs->job == job);
792f0c9fe6SPaolo Bonzini     job->cb(job->opaque, ret);
802f0c9fe6SPaolo Bonzini     bs->job = NULL;
812f0c9fe6SPaolo Bonzini     g_free(job);
822f0c9fe6SPaolo Bonzini     bdrv_set_in_use(bs, 0);
832f0c9fe6SPaolo Bonzini }
842f0c9fe6SPaolo Bonzini 
852f0c9fe6SPaolo Bonzini void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
862f0c9fe6SPaolo Bonzini {
872f0c9fe6SPaolo Bonzini     Error *local_err = NULL;
882f0c9fe6SPaolo Bonzini 
892f0c9fe6SPaolo Bonzini     if (!job->job_type->set_speed) {
902f0c9fe6SPaolo Bonzini         error_set(errp, QERR_NOT_SUPPORTED);
912f0c9fe6SPaolo Bonzini         return;
922f0c9fe6SPaolo Bonzini     }
932f0c9fe6SPaolo Bonzini     job->job_type->set_speed(job, speed, &local_err);
942f0c9fe6SPaolo Bonzini     if (error_is_set(&local_err)) {
952f0c9fe6SPaolo Bonzini         error_propagate(errp, local_err);
962f0c9fe6SPaolo Bonzini         return;
972f0c9fe6SPaolo Bonzini     }
982f0c9fe6SPaolo Bonzini 
992f0c9fe6SPaolo Bonzini     job->speed = speed;
1002f0c9fe6SPaolo Bonzini }
1012f0c9fe6SPaolo Bonzini 
1022f0c9fe6SPaolo Bonzini void block_job_cancel(BlockJob *job)
1032f0c9fe6SPaolo Bonzini {
1042f0c9fe6SPaolo Bonzini     job->cancelled = true;
1052f0c9fe6SPaolo Bonzini     if (job->co && !job->busy) {
1062f0c9fe6SPaolo Bonzini         qemu_coroutine_enter(job->co, NULL);
1072f0c9fe6SPaolo Bonzini     }
1082f0c9fe6SPaolo Bonzini }
1092f0c9fe6SPaolo Bonzini 
1102f0c9fe6SPaolo Bonzini bool block_job_is_cancelled(BlockJob *job)
1112f0c9fe6SPaolo Bonzini {
1122f0c9fe6SPaolo Bonzini     return job->cancelled;
1132f0c9fe6SPaolo Bonzini }
1142f0c9fe6SPaolo Bonzini 
1152f0c9fe6SPaolo Bonzini struct BlockCancelData {
1162f0c9fe6SPaolo Bonzini     BlockJob *job;
1172f0c9fe6SPaolo Bonzini     BlockDriverCompletionFunc *cb;
1182f0c9fe6SPaolo Bonzini     void *opaque;
1192f0c9fe6SPaolo Bonzini     bool cancelled;
1202f0c9fe6SPaolo Bonzini     int ret;
1212f0c9fe6SPaolo Bonzini };
1222f0c9fe6SPaolo Bonzini 
1232f0c9fe6SPaolo Bonzini static void block_job_cancel_cb(void *opaque, int ret)
1242f0c9fe6SPaolo Bonzini {
1252f0c9fe6SPaolo Bonzini     struct BlockCancelData *data = opaque;
1262f0c9fe6SPaolo Bonzini 
1272f0c9fe6SPaolo Bonzini     data->cancelled = block_job_is_cancelled(data->job);
1282f0c9fe6SPaolo Bonzini     data->ret = ret;
1292f0c9fe6SPaolo Bonzini     data->cb(data->opaque, ret);
1302f0c9fe6SPaolo Bonzini }
1312f0c9fe6SPaolo Bonzini 
1322f0c9fe6SPaolo Bonzini int block_job_cancel_sync(BlockJob *job)
1332f0c9fe6SPaolo Bonzini {
1342f0c9fe6SPaolo Bonzini     struct BlockCancelData data;
1352f0c9fe6SPaolo Bonzini     BlockDriverState *bs = job->bs;
1362f0c9fe6SPaolo Bonzini 
1372f0c9fe6SPaolo Bonzini     assert(bs->job == job);
1382f0c9fe6SPaolo Bonzini 
1392f0c9fe6SPaolo Bonzini     /* Set up our own callback to store the result and chain to
1402f0c9fe6SPaolo Bonzini      * the original callback.
1412f0c9fe6SPaolo Bonzini      */
1422f0c9fe6SPaolo Bonzini     data.job = job;
1432f0c9fe6SPaolo Bonzini     data.cb = job->cb;
1442f0c9fe6SPaolo Bonzini     data.opaque = job->opaque;
1452f0c9fe6SPaolo Bonzini     data.ret = -EINPROGRESS;
1462f0c9fe6SPaolo Bonzini     job->cb = block_job_cancel_cb;
1472f0c9fe6SPaolo Bonzini     job->opaque = &data;
1482f0c9fe6SPaolo Bonzini     block_job_cancel(job);
1492f0c9fe6SPaolo Bonzini     while (data.ret == -EINPROGRESS) {
1502f0c9fe6SPaolo Bonzini         qemu_aio_wait();
1512f0c9fe6SPaolo Bonzini     }
1522f0c9fe6SPaolo Bonzini     return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
1532f0c9fe6SPaolo Bonzini }
1542f0c9fe6SPaolo Bonzini 
1552f0c9fe6SPaolo Bonzini void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
1562f0c9fe6SPaolo Bonzini {
1572f0c9fe6SPaolo Bonzini     /* Check cancellation *before* setting busy = false, too!  */
1582f0c9fe6SPaolo Bonzini     if (!block_job_is_cancelled(job)) {
1592f0c9fe6SPaolo Bonzini         job->busy = false;
1602f0c9fe6SPaolo Bonzini         co_sleep_ns(clock, ns);
1612f0c9fe6SPaolo Bonzini         job->busy = true;
1622f0c9fe6SPaolo Bonzini     }
1632f0c9fe6SPaolo Bonzini }
164*30e628b7SPaolo Bonzini 
165*30e628b7SPaolo Bonzini BlockJobInfo *block_job_query(BlockJob *job)
166*30e628b7SPaolo Bonzini {
167*30e628b7SPaolo Bonzini     BlockJobInfo *info = g_new0(BlockJobInfo, 1);
168*30e628b7SPaolo Bonzini     info->type   = g_strdup(job->job_type->job_type);
169*30e628b7SPaolo Bonzini     info->device = g_strdup(bdrv_get_device_name(job->bs));
170*30e628b7SPaolo Bonzini     info->len    = job->len;
171*30e628b7SPaolo Bonzini     info->offset = job->offset;
172*30e628b7SPaolo Bonzini     info->speed  = job->speed;
173*30e628b7SPaolo Bonzini     return info;
174*30e628b7SPaolo Bonzini }
175