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_UNSUPPORTED); 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 } 285