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, QEMUClockType type, 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(type, 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 } 284