Statistics
| Branch: | Revision:

root / blockjob.c @ feature-archipelago

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 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 (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

    
75
void 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

    
86
void 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 (local_err) {
96
        error_propagate(errp, local_err);
97
        return;
98
    }
99

    
100
    job->speed = speed;
101
}
102

    
103
void 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

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

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

    
123
void 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

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

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

    
143
void 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

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

    
159
static 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

    
168
int 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

    
191
void 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

    
209
BlockJobInfo *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

    
223
static 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

    
232
QObject *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

    
246
void 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

    
253
BlockErrorAction 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
}