blockjob.c 11.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * QEMU System Emulator block driver
 *
 * Copyright (c) 2011 IBM Corp.
 * Copyright (c) 2012 Red Hat, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "config-host.h"
#include "qemu-common.h"
#include "trace.h"
29 30 31
#include "block/block.h"
#include "block/blockjob.h"
#include "block/block_int.h"
32
#include "sysemu/block-backend.h"
33
#include "qapi/qmp/qerror.h"
34
#include "qapi/qmp/qjson.h"
35
#include "qemu/coroutine.h"
36
#include "qmp-commands.h"
37
#include "qemu/timer.h"
38
#include "qapi-event.h"
39

40
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
41
                       int64_t speed, BlockCompletionFunc *cb,
42 43 44 45
                       void *opaque, Error **errp)
{
    BlockJob *job;

46
    if (bs->job) {
47
        error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
48 49
        return NULL;
    }
F
Fam Zheng 已提交
50
    bdrv_ref(bs);
51
    job = g_malloc0(driver->instance_size);
52 53 54
    error_setg(&job->blocker, "block device is in use by block job: %s",
               BlockJobType_lookup[driver->job_type]);
    bdrv_op_block_all(bs, job->blocker);
55
    bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
56

57
    job->driver        = driver;
58
    job->id            = g_strdup(bdrv_get_device_name(bs));
59 60 61 62
    job->bs            = bs;
    job->cb            = cb;
    job->opaque        = opaque;
    job->busy          = true;
63
    job->refcnt        = 1;
64 65 66 67 68 69 70
    bs->job = job;

    /* Only set speed when necessary to avoid NotSupported error */
    if (speed != 0) {
        Error *local_err = NULL;

        block_job_set_speed(job, speed, &local_err);
71
        if (local_err) {
72
            block_job_unref(job);
73 74 75 76 77 78 79
            error_propagate(errp, local_err);
            return NULL;
        }
    }
    return job;
}

80
void block_job_ref(BlockJob *job)
81
{
82 83
    ++job->refcnt;
}
84

85 86 87 88 89 90 91 92 93 94
void block_job_unref(BlockJob *job)
{
    if (--job->refcnt == 0) {
        job->bs->job = NULL;
        bdrv_op_unblock_all(job->bs, job->blocker);
        bdrv_unref(job->bs);
        error_free(job->blocker);
        g_free(job->id);
        g_free(job);
    }
95 96
}

97 98 99 100 101
void block_job_completed(BlockJob *job, int ret)
{
    BlockDriverState *bs = job->bs;

    assert(bs->job == job);
102 103 104
    assert(!job->completed);
    job->completed = true;
    job->ret = ret;
105
    job->cb(job->opaque, ret);
106
    block_job_unref(job);
107 108
}

109 110 111 112
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
    Error *local_err = NULL;

113
    if (!job->driver->set_speed) {
114
        error_setg(errp, QERR_UNSUPPORTED);
115 116
        return;
    }
117
    job->driver->set_speed(job, speed, &local_err);
118
    if (local_err) {
119 120 121 122 123 124 125
        error_propagate(errp, local_err);
        return;
    }

    job->speed = speed;
}

P
Paolo Bonzini 已提交
126 127
void block_job_complete(BlockJob *job, Error **errp)
{
F
Fam Zheng 已提交
128
    if (job->pause_count || job->cancelled || !job->driver->complete) {
129
        error_setg(errp, QERR_BLOCK_JOB_NOT_READY, job->id);
P
Paolo Bonzini 已提交
130 131 132
        return;
    }

133
    job->driver->complete(job, errp);
P
Paolo Bonzini 已提交
134 135
}

136
void block_job_pause(BlockJob *job)
137
{
F
Fam Zheng 已提交
138
    job->pause_count++;
139 140 141 142
}

bool block_job_is_paused(BlockJob *job)
{
F
Fam Zheng 已提交
143
    return job->pause_count > 0;
144 145 146 147
}

void block_job_resume(BlockJob *job)
{
F
Fam Zheng 已提交
148 149 150 151 152 153 154 155 156 157
    assert(job->pause_count > 0);
    job->pause_count--;
    if (job->pause_count) {
        return;
    }
    block_job_enter(job);
}

void block_job_enter(BlockJob *job)
{
P
Paolo Bonzini 已提交
158
    block_job_iostatus_reset(job);
159 160 161 162 163
    if (job->co && !job->busy) {
        qemu_coroutine_enter(job->co, NULL);
    }
}

164 165 166
void block_job_cancel(BlockJob *job)
{
    job->cancelled = true;
F
Fam Zheng 已提交
167
    block_job_enter(job);
168 169
}

170 171 172 173 174
bool block_job_is_cancelled(BlockJob *job)
{
    return job->cancelled;
}

P
Paolo Bonzini 已提交
175 176 177
void block_job_iostatus_reset(BlockJob *job)
{
    job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
178 179
    if (job->driver->iostatus_reset) {
        job->driver->iostatus_reset(job);
180
    }
P
Paolo Bonzini 已提交
181 182
}

183
struct BlockFinishData {
184
    BlockJob *job;
185
    BlockCompletionFunc *cb;
186 187 188 189 190
    void *opaque;
    bool cancelled;
    int ret;
};

191 192 193
static int block_job_finish_sync(BlockJob *job,
                                 void (*finish)(BlockJob *, Error **errp),
                                 Error **errp)
194 195
{
    BlockDriverState *bs = job->bs;
196
    Error *local_err = NULL;
197
    int ret;
198 199 200

    assert(bs->job == job);

201
    block_job_ref(job);
202 203 204
    finish(job, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
205
        block_job_unref(job);
206 207
        return -EBUSY;
    }
208
    while (!job->completed) {
209
        aio_poll(bdrv_get_aio_context(bs), true);
210
    }
211 212 213
    ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
    block_job_unref(job);
    return ret;
214 215
}

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
 * used with block_job_finish_sync() without the need for (rather nasty)
 * function pointer casts there. */
static void block_job_cancel_err(BlockJob *job, Error **errp)
{
    block_job_cancel(job);
}

int block_job_cancel_sync(BlockJob *job)
{
    return block_job_finish_sync(job, &block_job_cancel_err, NULL);
}

int block_job_complete_sync(BlockJob *job, Error **errp)
{
    return block_job_finish_sync(job, &block_job_complete, errp);
}

234
void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
235
{
236 237
    assert(job->busy);

238
    /* Check cancellation *before* setting busy = false, too!  */
239 240 241 242 243 244 245 246
    if (block_job_is_cancelled(job)) {
        return;
    }

    job->busy = false;
    if (block_job_is_paused(job)) {
        qemu_coroutine_yield();
    } else {
F
Fam Zheng 已提交
247
        co_aio_sleep_ns(bdrv_get_aio_context(job->bs), type, ns);
248
    }
249
    job->busy = true;
250
}
P
Paolo Bonzini 已提交
251

F
Fam Zheng 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265
void block_job_yield(BlockJob *job)
{
    assert(job->busy);

    /* Check cancellation *before* setting busy = false, too!  */
    if (block_job_is_cancelled(job)) {
        return;
    }

    job->busy = false;
    qemu_coroutine_yield();
    job->busy = true;
}

P
Paolo Bonzini 已提交
266 267 268
BlockJobInfo *block_job_query(BlockJob *job)
{
    BlockJobInfo *info = g_new0(BlockJobInfo, 1);
F
Fam Zheng 已提交
269
    info->type      = g_strdup(BlockJobType_lookup[job->driver->job_type]);
270
    info->device    = g_strdup(job->id);
P
Paolo Bonzini 已提交
271 272
    info->len       = job->len;
    info->busy      = job->busy;
F
Fam Zheng 已提交
273
    info->paused    = job->pause_count > 0;
P
Paolo Bonzini 已提交
274 275 276
    info->offset    = job->offset;
    info->speed     = job->speed;
    info->io_status = job->iostatus;
M
Max Reitz 已提交
277
    info->ready     = job->ready;
P
Paolo Bonzini 已提交
278 279
    return info;
}
P
Paolo Bonzini 已提交
280 281 282 283 284 285 286 287 288

static void block_job_iostatus_set_err(BlockJob *job, int error)
{
    if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
        job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
                                          BLOCK_DEVICE_IO_STATUS_FAILED;
    }
}

289 290 291
void block_job_event_cancelled(BlockJob *job)
{
    qapi_event_send_block_job_cancelled(job->driver->job_type,
292
                                        job->id,
293 294 295 296 297
                                        job->len,
                                        job->offset,
                                        job->speed,
                                        &error_abort);
}
P
Paolo Bonzini 已提交
298

299
void block_job_event_completed(BlockJob *job, const char *msg)
300
{
301
    qapi_event_send_block_job_completed(job->driver->job_type,
302
                                        job->id,
303 304 305 306 307 308
                                        job->len,
                                        job->offset,
                                        job->speed,
                                        !!msg,
                                        msg,
                                        &error_abort);
309 310
}

311
void block_job_event_ready(BlockJob *job)
312
{
M
Max Reitz 已提交
313 314
    job->ready = true;

315
    qapi_event_send_block_job_ready(job->driver->job_type,
316
                                    job->id,
317 318 319
                                    job->len,
                                    job->offset,
                                    job->speed, &error_abort);
320 321
}

P
Paolo Bonzini 已提交
322 323 324 325 326 327 328 329
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
                                        BlockdevOnError on_err,
                                        int is_read, int error)
{
    BlockErrorAction action;

    switch (on_err) {
    case BLOCKDEV_ON_ERROR_ENOSPC:
W
Wenchao Xia 已提交
330 331
        action = (error == ENOSPC) ?
                 BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
P
Paolo Bonzini 已提交
332 333
        break;
    case BLOCKDEV_ON_ERROR_STOP:
W
Wenchao Xia 已提交
334
        action = BLOCK_ERROR_ACTION_STOP;
P
Paolo Bonzini 已提交
335 336
        break;
    case BLOCKDEV_ON_ERROR_REPORT:
W
Wenchao Xia 已提交
337
        action = BLOCK_ERROR_ACTION_REPORT;
P
Paolo Bonzini 已提交
338 339
        break;
    case BLOCKDEV_ON_ERROR_IGNORE:
W
Wenchao Xia 已提交
340
        action = BLOCK_ERROR_ACTION_IGNORE;
P
Paolo Bonzini 已提交
341 342 343 344
        break;
    default:
        abort();
    }
345
    qapi_event_send_block_job_error(job->id,
346 347 348
                                    is_read ? IO_OPERATION_TYPE_READ :
                                    IO_OPERATION_TYPE_WRITE,
                                    action, &error_abort);
W
Wenchao Xia 已提交
349
    if (action == BLOCK_ERROR_ACTION_STOP) {
F
Fam Zheng 已提交
350 351
        /* make the pause user visible, which will be resumed from QMP. */
        job->user_paused = true;
P
Paolo Bonzini 已提交
352 353
        block_job_pause(job);
        block_job_iostatus_set_err(job, error);
354 355
        if (bs->blk && bs != job->bs) {
            blk_iostatus_set_err(bs->blk, error);
P
Paolo Bonzini 已提交
356 357 358 359
        }
    }
    return action;
}
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

typedef struct {
    BlockJob *job;
    QEMUBH *bh;
    AioContext *aio_context;
    BlockJobDeferToMainLoopFn *fn;
    void *opaque;
} BlockJobDeferToMainLoopData;

static void block_job_defer_to_main_loop_bh(void *opaque)
{
    BlockJobDeferToMainLoopData *data = opaque;
    AioContext *aio_context;

    qemu_bh_delete(data->bh);

    /* Prevent race with block_job_defer_to_main_loop() */
    aio_context_acquire(data->aio_context);

    /* Fetch BDS AioContext again, in case it has changed */
    aio_context = bdrv_get_aio_context(data->job->bs);
    aio_context_acquire(aio_context);

    data->fn(data->job, data->opaque);

    aio_context_release(aio_context);

    aio_context_release(data->aio_context);

    g_free(data);
}

void block_job_defer_to_main_loop(BlockJob *job,
                                  BlockJobDeferToMainLoopFn *fn,
                                  void *opaque)
{
    BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
    data->job = job;
    data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
    data->aio_context = bdrv_get_aio_context(job->bs);
    data->fn = fn;
    data->opaque = opaque;

    qemu_bh_schedule(data->bh);
}