Statistics
| Branch: | Revision:

root / blockjob.c @ 6a1751b7

History | View | Annotate | Download (7.6 kB)

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

    
38
void *block_job_create(const BlockJobType *job_type, 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_set_in_use(bs, 1);
49

    
50
    job = g_malloc0(job_type->instance_size);
51
    job->job_type      = job_type;
52
    job->bs            = bs;
53
    job->cb            = cb;
54
    job->opaque        = opaque;
55
    job->busy          = true;
56
    bs->job = job;
57

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

    
62
        block_job_set_speed(job, speed, &local_err);
63
        if (error_is_set(&local_err)) {
64
            bs->job = NULL;
65
            g_free(job);
66
            bdrv_set_in_use(bs, 0);
67
            error_propagate(errp, local_err);
68
            return NULL;
69
        }
70
    }
71
    return job;
72
}
73

    
74
void block_job_completed(BlockJob *job, int ret)
75
{
76
    BlockDriverState *bs = job->bs;
77

    
78
    assert(bs->job == job);
79
    job->cb(job->opaque, ret);
80
    bs->job = NULL;
81
    g_free(job);
82
    bdrv_set_in_use(bs, 0);
83
}
84

    
85
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
86
{
87
    Error *local_err = NULL;
88

    
89
    if (!job->job_type->set_speed) {
90
        error_set(errp, QERR_NOT_SUPPORTED);
91
        return;
92
    }
93
    job->job_type->set_speed(job, speed, &local_err);
94
    if (error_is_set(&local_err)) {
95
        error_propagate(errp, local_err);
96
        return;
97
    }
98

    
99
    job->speed = speed;
100
}
101

    
102
void block_job_complete(BlockJob *job, Error **errp)
103
{
104
    if (job->paused || job->cancelled || !job->job_type->complete) {
105
        error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
106
        return;
107
    }
108

    
109
    job->job_type->complete(job, errp);
110
}
111

    
112
void block_job_pause(BlockJob *job)
113
{
114
    job->paused = true;
115
}
116

    
117
bool block_job_is_paused(BlockJob *job)
118
{
119
    return job->paused;
120
}
121

    
122
void block_job_resume(BlockJob *job)
123
{
124
    job->paused = false;
125
    block_job_iostatus_reset(job);
126
    if (job->co && !job->busy) {
127
        qemu_coroutine_enter(job->co, NULL);
128
    }
129
}
130

    
131
void block_job_cancel(BlockJob *job)
132
{
133
    job->cancelled = true;
134
    block_job_resume(job);
135
}
136

    
137
bool block_job_is_cancelled(BlockJob *job)
138
{
139
    return job->cancelled;
140
}
141

    
142
void block_job_iostatus_reset(BlockJob *job)
143
{
144
    job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
145
    if (job->job_type->iostatus_reset) {
146
        job->job_type->iostatus_reset(job);
147
    }
148
}
149

    
150
struct BlockCancelData {
151
    BlockJob *job;
152
    BlockDriverCompletionFunc *cb;
153
    void *opaque;
154
    bool cancelled;
155
    int ret;
156
};
157

    
158
static void block_job_cancel_cb(void *opaque, int ret)
159
{
160
    struct BlockCancelData *data = opaque;
161

    
162
    data->cancelled = block_job_is_cancelled(data->job);
163
    data->ret = ret;
164
    data->cb(data->opaque, ret);
165
}
166

    
167
int block_job_cancel_sync(BlockJob *job)
168
{
169
    struct BlockCancelData data;
170
    BlockDriverState *bs = job->bs;
171

    
172
    assert(bs->job == job);
173

    
174
    /* Set up our own callback to store the result and chain to
175
     * the original callback.
176
     */
177
    data.job = job;
178
    data.cb = job->cb;
179
    data.opaque = job->opaque;
180
    data.ret = -EINPROGRESS;
181
    job->cb = block_job_cancel_cb;
182
    job->opaque = &data;
183
    block_job_cancel(job);
184
    while (data.ret == -EINPROGRESS) {
185
        qemu_aio_wait();
186
    }
187
    return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
188
}
189

    
190
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
191
{
192
    assert(job->busy);
193

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

    
199
    job->busy = false;
200
    if (block_job_is_paused(job)) {
201
        qemu_coroutine_yield();
202
    } else {
203
        co_sleep_ns(clock, ns);
204
    }
205
    job->busy = true;
206
}
207

    
208
BlockJobInfo *block_job_query(BlockJob *job)
209
{
210
    BlockJobInfo *info = g_new0(BlockJobInfo, 1);
211
    info->type      = g_strdup(job->job_type->job_type);
212
    info->device    = g_strdup(bdrv_get_device_name(job->bs));
213
    info->len       = job->len;
214
    info->busy      = job->busy;
215
    info->paused    = job->paused;
216
    info->offset    = job->offset;
217
    info->speed     = job->speed;
218
    info->io_status = job->iostatus;
219
    return info;
220
}
221

    
222
static void block_job_iostatus_set_err(BlockJob *job, int error)
223
{
224
    if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
225
        job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
226
                                          BLOCK_DEVICE_IO_STATUS_FAILED;
227
    }
228
}
229

    
230

    
231
QObject *qobject_from_block_job(BlockJob *job)
232
{
233
    return qobject_from_jsonf("{ 'type': %s,"
234
                              "'device': %s,"
235
                              "'len': %" PRId64 ","
236
                              "'offset': %" PRId64 ","
237
                              "'speed': %" PRId64 " }",
238
                              job->job_type->job_type,
239
                              bdrv_get_device_name(job->bs),
240
                              job->len,
241
                              job->offset,
242
                              job->speed);
243
}
244

    
245
void block_job_ready(BlockJob *job)
246
{
247
    QObject *data = qobject_from_block_job(job);
248
    monitor_protocol_event(QEVENT_BLOCK_JOB_READY, data);
249
    qobject_decref(data);
250
}
251

    
252
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
253
                                        BlockdevOnError on_err,
254
                                        int is_read, int error)
255
{
256
    BlockErrorAction action;
257

    
258
    switch (on_err) {
259
    case BLOCKDEV_ON_ERROR_ENOSPC:
260
        action = (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
261
        break;
262
    case BLOCKDEV_ON_ERROR_STOP:
263
        action = BDRV_ACTION_STOP;
264
        break;
265
    case BLOCKDEV_ON_ERROR_REPORT:
266
        action = BDRV_ACTION_REPORT;
267
        break;
268
    case BLOCKDEV_ON_ERROR_IGNORE:
269
        action = BDRV_ACTION_IGNORE;
270
        break;
271
    default:
272
        abort();
273
    }
274
    bdrv_emit_qmp_error_event(job->bs, QEVENT_BLOCK_JOB_ERROR, action, is_read);
275
    if (action == BDRV_ACTION_STOP) {
276
        block_job_pause(job);
277
        block_job_iostatus_set_err(job, error);
278
        if (bs != job->bs) {
279
            bdrv_iostatus_set_err(bs, error);
280
        }
281
    }
282
    return action;
283
}