qemu/blockjob.c
<<
>>
Prefs
   1/*
   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
  26#include "config-host.h"
  27#include "qemu-common.h"
  28#include "trace.h"
  29#include "monitor/monitor.h"
  30#include "block/block.h"
  31#include "block/blockjob.h"
  32#include "block/block_int.h"
  33#include "qapi/qmp/qjson.h"
  34#include "block/coroutine.h"
  35#include "qmp-commands.h"
  36#include "qemu/timer.h"
  37
  38void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
  39                       int64_t speed, BlockDriverCompletionFunc *cb,
  40                       void *opaque, Error **errp)
  41{
  42    BlockJob *job;
  43
  44    if (bs->job || bdrv_in_use(bs)) {
  45        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
  46        return NULL;
  47    }
  48    bdrv_ref(bs);
  49    bdrv_set_in_use(bs, 1);
  50
  51    job = g_malloc0(driver->instance_size);
  52    job->driver        = driver;
  53    job->bs            = bs;
  54    job->cb            = cb;
  55    job->opaque        = opaque;
  56    job->busy          = true;
  57    bs->job = job;
  58
  59    /* Only set speed when necessary to avoid NotSupported error */
  60    if (speed != 0) {
  61        Error *local_err = NULL;
  62
  63        block_job_set_speed(job, speed, &local_err);
  64        if (error_is_set(&local_err)) {
  65            bs->job = NULL;
  66            g_free(job);
  67            bdrv_set_in_use(bs, 0);
  68            error_propagate(errp, local_err);
  69            return NULL;
  70        }
  71    }
  72    return job;
  73}
  74
  75void block_job_completed(BlockJob *job, int ret)
  76{
  77    BlockDriverState *bs = job->bs;
  78
  79    assert(bs->job == job);
  80    job->cb(job->opaque, ret);
  81    bs->job = NULL;
  82    g_free(job);
  83    bdrv_set_in_use(bs, 0);
  84}
  85
  86void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
  87{
  88    Error *local_err = NULL;
  89
  90    if (!job->driver->set_speed) {
  91        error_set(errp, QERR_NOT_SUPPORTED);
  92        return;
  93    }
  94    job->driver->set_speed(job, speed, &local_err);
  95    if (error_is_set(&local_err)) {
  96        error_propagate(errp, local_err);
  97        return;
  98    }
  99
 100    job->speed = speed;
 101}
 102
 103void block_job_complete(BlockJob *job, Error **errp)
 104{
 105    if (job->paused || job->cancelled || !job->driver->complete) {
 106        error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
 107        return;
 108    }
 109
 110    job->driver->complete(job, errp);
 111}
 112
 113void block_job_pause(BlockJob *job)
 114{
 115    job->paused = true;
 116}
 117
 118bool block_job_is_paused(BlockJob *job)
 119{
 120    return job->paused;
 121}
 122
 123void block_job_resume(BlockJob *job)
 124{
 125    job->paused = false;
 126    block_job_iostatus_reset(job);
 127    if (job->co && !job->busy) {
 128        qemu_coroutine_enter(job->co, NULL);
 129    }
 130}
 131
 132void block_job_cancel(BlockJob *job)
 133{
 134    job->cancelled = true;
 135    block_job_resume(job);
 136}
 137
 138bool block_job_is_cancelled(BlockJob *job)
 139{
 140    return job->cancelled;
 141}
 142
 143void block_job_iostatus_reset(BlockJob *job)
 144{
 145    job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
 146    if (job->driver->iostatus_reset) {
 147        job->driver->iostatus_reset(job);
 148    }
 149}
 150
 151struct BlockCancelData {
 152    BlockJob *job;
 153    BlockDriverCompletionFunc *cb;
 154    void *opaque;
 155    bool cancelled;
 156    int ret;
 157};
 158
 159static void block_job_cancel_cb(void *opaque, int ret)
 160{
 161    struct BlockCancelData *data = opaque;
 162
 163    data->cancelled = block_job_is_cancelled(data->job);
 164    data->ret = ret;
 165    data->cb(data->opaque, ret);
 166}
 167
 168int block_job_cancel_sync(BlockJob *job)
 169{
 170    struct BlockCancelData data;
 171    BlockDriverState *bs = job->bs;
 172
 173    assert(bs->job == job);
 174
 175    /* Set up our own callback to store the result and chain to
 176     * the original callback.
 177     */
 178    data.job = job;
 179    data.cb = job->cb;
 180    data.opaque = job->opaque;
 181    data.ret = -EINPROGRESS;
 182    job->cb = block_job_cancel_cb;
 183    job->opaque = &data;
 184    block_job_cancel(job);
 185    while (data.ret == -EINPROGRESS) {
 186        qemu_aio_wait();
 187    }
 188    return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
 189}
 190
 191void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
 192{
 193    assert(job->busy);
 194
 195    /* Check cancellation *before* setting busy = false, too!  */
 196    if (block_job_is_cancelled(job)) {
 197        return;
 198    }
 199
 200    job->busy = false;
 201    if (block_job_is_paused(job)) {
 202        qemu_coroutine_yield();
 203    } else {
 204        co_sleep_ns(type, ns);
 205    }
 206    job->busy = true;
 207}
 208
 209BlockJobInfo *block_job_query(BlockJob *job)
 210{
 211    BlockJobInfo *info = g_new0(BlockJobInfo, 1);
 212    info->type      = g_strdup(BlockJobType_lookup[job->driver->job_type]);
 213    info->device    = g_strdup(bdrv_get_device_name(job->bs));
 214    info->len       = job->len;
 215    info->busy      = job->busy;
 216    info->paused    = job->paused;
 217    info->offset    = job->offset;
 218    info->speed     = job->speed;
 219    info->io_status = job->iostatus;
 220    return info;
 221}
 222
 223static void block_job_iostatus_set_err(BlockJob *job, int error)
 224{
 225    if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
 226        job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
 227                                          BLOCK_DEVICE_IO_STATUS_FAILED;
 228    }
 229}
 230
 231
 232QObject *qobject_from_block_job(BlockJob *job)
 233{
 234    return qobject_from_jsonf("{ 'type': %s,"
 235                              "'device': %s,"
 236                              "'len': %" PRId64 ","
 237                              "'offset': %" PRId64 ","
 238                              "'speed': %" PRId64 " }",
 239                              BlockJobType_lookup[job->driver->job_type],
 240                              bdrv_get_device_name(job->bs),
 241                              job->len,
 242                              job->offset,
 243                              job->speed);
 244}
 245
 246void block_job_ready(BlockJob *job)
 247{
 248    QObject *data = qobject_from_block_job(job);
 249    monitor_protocol_event(QEVENT_BLOCK_JOB_READY, data);
 250    qobject_decref(data);
 251}
 252
 253BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
 254                                        BlockdevOnError on_err,
 255                                        int is_read, int error)
 256{
 257    BlockErrorAction action;
 258
 259    switch (on_err) {
 260    case BLOCKDEV_ON_ERROR_ENOSPC:
 261        action = (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
 262        break;
 263    case BLOCKDEV_ON_ERROR_STOP:
 264        action = BDRV_ACTION_STOP;
 265        break;
 266    case BLOCKDEV_ON_ERROR_REPORT:
 267        action = BDRV_ACTION_REPORT;
 268        break;
 269    case BLOCKDEV_ON_ERROR_IGNORE:
 270        action = BDRV_ACTION_IGNORE;
 271        break;
 272    default:
 273        abort();
 274    }
 275    bdrv_emit_qmp_error_event(job->bs, QEVENT_BLOCK_JOB_ERROR, action, is_read);
 276    if (action == BDRV_ACTION_STOP) {
 277        block_job_pause(job);
 278        block_job_iostatus_set_err(job, error);
 279        if (bs != job->bs) {
 280            bdrv_iostatus_set_err(bs, error);
 281        }
 282    }
 283    return action;
 284}
 285