1 /* 2 * QMP command handlers specific to the system emulators 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or 7 * later. See the COPYING file in the top-level directory. 8 * 9 * This file incorporates work covered by the following copyright and 10 * permission notice: 11 * 12 * Copyright (c) 2003-2008 Fabrice Bellard 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this software and associated documentation files (the "Software"), to deal 16 * in the Software without restriction, including without limitation the rights 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the Software is 19 * furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 * THE SOFTWARE. 31 */ 32 33 #include "qemu/osdep.h" 34 35 #include "qapi/error.h" 36 #include "qapi/qapi-commands-block.h" 37 #include "qapi/qmp/qdict.h" 38 #include "sysemu/block-backend.h" 39 #include "sysemu/blockdev.h" 40 41 static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id, 42 Error **errp) 43 { 44 BlockBackend *blk; 45 46 if (!blk_name == !qdev_id) { 47 error_setg(errp, "Need exactly one of 'device' and 'id'"); 48 return NULL; 49 } 50 51 if (qdev_id) { 52 blk = blk_by_qdev_id(qdev_id, errp); 53 } else { 54 blk = blk_by_name(blk_name); 55 if (blk == NULL) { 56 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 57 "Device '%s' not found", blk_name); 58 } 59 } 60 61 return blk; 62 } 63 64 /* 65 * Attempt to open the tray of @device. 66 * If @force, ignore its tray lock. 67 * Else, if the tray is locked, don't open it, but ask the guest to open it. 68 * On error, store an error through @errp and return -errno. 69 * If @device does not exist, return -ENODEV. 70 * If it has no removable media, return -ENOTSUP. 71 * If it has no tray, return -ENOSYS. 72 * If the guest was asked to open the tray, return -EINPROGRESS. 73 * Else, return 0. 74 */ 75 static int do_open_tray(const char *blk_name, const char *qdev_id, 76 bool force, Error **errp) 77 { 78 BlockBackend *blk; 79 const char *device = qdev_id ?: blk_name; 80 bool locked; 81 82 blk = qmp_get_blk(blk_name, qdev_id, errp); 83 if (!blk) { 84 return -ENODEV; 85 } 86 87 if (!blk_dev_has_removable_media(blk)) { 88 error_setg(errp, "Device '%s' is not removable", device); 89 return -ENOTSUP; 90 } 91 92 if (!blk_dev_has_tray(blk)) { 93 error_setg(errp, "Device '%s' does not have a tray", device); 94 return -ENOSYS; 95 } 96 97 if (blk_dev_is_tray_open(blk)) { 98 return 0; 99 } 100 101 locked = blk_dev_is_medium_locked(blk); 102 if (locked) { 103 blk_dev_eject_request(blk, force); 104 } 105 106 if (!locked || force) { 107 blk_dev_change_media_cb(blk, false, &error_abort); 108 } 109 110 if (locked && !force) { 111 error_setg(errp, "Device '%s' is locked and force was not specified, " 112 "wait for tray to open and try again", device); 113 return -EINPROGRESS; 114 } 115 116 return 0; 117 } 118 119 void qmp_blockdev_open_tray(const char *device, 120 const char *id, 121 bool has_force, bool force, 122 Error **errp) 123 { 124 Error *local_err = NULL; 125 int rc; 126 127 if (!has_force) { 128 force = false; 129 } 130 rc = do_open_tray(device, id, force, &local_err); 131 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) { 132 error_propagate(errp, local_err); 133 return; 134 } 135 error_free(local_err); 136 } 137 138 void qmp_blockdev_close_tray(const char *device, 139 const char *id, 140 Error **errp) 141 { 142 BlockBackend *blk; 143 Error *local_err = NULL; 144 145 blk = qmp_get_blk(device, id, errp); 146 if (!blk) { 147 return; 148 } 149 150 if (!blk_dev_has_removable_media(blk)) { 151 error_setg(errp, "Device '%s' is not removable", device ?: id); 152 return; 153 } 154 155 if (!blk_dev_has_tray(blk)) { 156 /* Ignore this command on tray-less devices */ 157 return; 158 } 159 160 if (!blk_dev_is_tray_open(blk)) { 161 return; 162 } 163 164 blk_dev_change_media_cb(blk, true, &local_err); 165 if (local_err) { 166 error_propagate(errp, local_err); 167 return; 168 } 169 } 170 171 static void blockdev_remove_medium(const char *device, const char *id, 172 Error **errp) 173 { 174 BlockBackend *blk; 175 BlockDriverState *bs; 176 AioContext *aio_context; 177 bool has_attached_device; 178 179 blk = qmp_get_blk(device, id, errp); 180 if (!blk) { 181 return; 182 } 183 184 /* For BBs without a device, we can exchange the BDS tree at will */ 185 has_attached_device = blk_get_attached_dev(blk); 186 187 if (has_attached_device && !blk_dev_has_removable_media(blk)) { 188 error_setg(errp, "Device '%s' is not removable", device ?: id); 189 return; 190 } 191 192 if (has_attached_device && blk_dev_has_tray(blk) && 193 !blk_dev_is_tray_open(blk)) 194 { 195 error_setg(errp, "Tray of device '%s' is not open", device ?: id); 196 return; 197 } 198 199 bs = blk_bs(blk); 200 if (!bs) { 201 return; 202 } 203 204 aio_context = bdrv_get_aio_context(bs); 205 aio_context_acquire(aio_context); 206 207 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { 208 goto out; 209 } 210 211 blk_remove_bs(blk); 212 213 if (!blk_dev_has_tray(blk)) { 214 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be 215 * called at all); therefore, the medium needs to be ejected here. 216 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load 217 * value passed here (i.e. false). */ 218 blk_dev_change_media_cb(blk, false, &error_abort); 219 } 220 221 out: 222 aio_context_release(aio_context); 223 } 224 225 void qmp_blockdev_remove_medium(const char *id, Error **errp) 226 { 227 blockdev_remove_medium(NULL, id, errp); 228 } 229 230 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk, 231 BlockDriverState *bs, Error **errp) 232 { 233 Error *local_err = NULL; 234 bool has_device; 235 int ret; 236 237 /* For BBs without a device, we can exchange the BDS tree at will */ 238 has_device = blk_get_attached_dev(blk); 239 240 if (has_device && !blk_dev_has_removable_media(blk)) { 241 error_setg(errp, "Device is not removable"); 242 return; 243 } 244 245 if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) { 246 error_setg(errp, "Tray of the device is not open"); 247 return; 248 } 249 250 if (blk_bs(blk)) { 251 error_setg(errp, "There already is a medium in the device"); 252 return; 253 } 254 255 ret = blk_insert_bs(blk, bs, errp); 256 if (ret < 0) { 257 return; 258 } 259 260 if (!blk_dev_has_tray(blk)) { 261 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be 262 * called at all); therefore, the medium needs to be pushed into the 263 * slot here. 264 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load 265 * value passed here (i.e. true). */ 266 blk_dev_change_media_cb(blk, true, &local_err); 267 if (local_err) { 268 error_propagate(errp, local_err); 269 blk_remove_bs(blk); 270 return; 271 } 272 } 273 } 274 275 static void blockdev_insert_medium(const char *device, const char *id, 276 const char *node_name, Error **errp) 277 { 278 BlockBackend *blk; 279 BlockDriverState *bs; 280 281 blk = qmp_get_blk(device, id, errp); 282 if (!blk) { 283 return; 284 } 285 286 bs = bdrv_find_node(node_name); 287 if (!bs) { 288 error_setg(errp, "Node '%s' not found", node_name); 289 return; 290 } 291 292 if (bdrv_has_blk(bs)) { 293 error_setg(errp, "Node '%s' is already in use", node_name); 294 return; 295 } 296 297 qmp_blockdev_insert_anon_medium(blk, bs, errp); 298 } 299 300 void qmp_blockdev_insert_medium(const char *id, const char *node_name, 301 Error **errp) 302 { 303 blockdev_insert_medium(NULL, id, node_name, errp); 304 } 305 306 void qmp_blockdev_change_medium(const char *device, 307 const char *id, 308 const char *filename, 309 const char *format, 310 bool has_force, bool force, 311 bool has_read_only, 312 BlockdevChangeReadOnlyMode read_only, 313 Error **errp) 314 { 315 BlockBackend *blk; 316 BlockDriverState *medium_bs = NULL; 317 int bdrv_flags; 318 bool detect_zeroes; 319 int rc; 320 QDict *options = NULL; 321 Error *err = NULL; 322 323 blk = qmp_get_blk(device, id, errp); 324 if (!blk) { 325 goto fail; 326 } 327 328 if (blk_bs(blk)) { 329 blk_update_root_state(blk); 330 } 331 332 bdrv_flags = blk_get_open_flags_from_root_state(blk); 333 bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | 334 BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY); 335 336 if (!has_read_only) { 337 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN; 338 } 339 340 switch (read_only) { 341 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN: 342 break; 343 344 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY: 345 bdrv_flags &= ~BDRV_O_RDWR; 346 break; 347 348 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE: 349 bdrv_flags |= BDRV_O_RDWR; 350 break; 351 352 default: 353 abort(); 354 } 355 356 options = qdict_new(); 357 detect_zeroes = blk_get_detect_zeroes_from_root_state(blk); 358 qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off"); 359 360 if (format) { 361 qdict_put_str(options, "driver", format); 362 } 363 364 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp); 365 if (!medium_bs) { 366 goto fail; 367 } 368 369 rc = do_open_tray(device, id, force, &err); 370 if (rc && rc != -ENOSYS) { 371 error_propagate(errp, err); 372 goto fail; 373 } 374 error_free(err); 375 err = NULL; 376 377 blockdev_remove_medium(device, id, &err); 378 if (err) { 379 error_propagate(errp, err); 380 goto fail; 381 } 382 383 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err); 384 if (err) { 385 error_propagate(errp, err); 386 goto fail; 387 } 388 389 qmp_blockdev_close_tray(device, id, errp); 390 391 fail: 392 /* If the medium has been inserted, the device has its own reference, so 393 * ours must be relinquished; and if it has not been inserted successfully, 394 * the reference must be relinquished anyway */ 395 bdrv_unref(medium_bs); 396 } 397 398 void qmp_eject(const char *device, const char *id, 399 bool has_force, bool force, Error **errp) 400 { 401 Error *local_err = NULL; 402 int rc; 403 404 if (!has_force) { 405 force = false; 406 } 407 408 rc = do_open_tray(device, id, force, &local_err); 409 if (rc && rc != -ENOSYS) { 410 error_propagate(errp, local_err); 411 return; 412 } 413 error_free(local_err); 414 415 blockdev_remove_medium(device, id, errp); 416 } 417 418 /* throttling disk I/O limits */ 419 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) 420 { 421 ThrottleConfig cfg; 422 BlockDriverState *bs; 423 BlockBackend *blk; 424 AioContext *aio_context; 425 426 blk = qmp_get_blk(arg->device, arg->id, errp); 427 if (!blk) { 428 return; 429 } 430 431 aio_context = blk_get_aio_context(blk); 432 aio_context_acquire(aio_context); 433 434 bs = blk_bs(blk); 435 if (!bs) { 436 error_setg(errp, "Device has no medium"); 437 goto out; 438 } 439 440 throttle_config_init(&cfg); 441 cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps; 442 cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd; 443 cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr; 444 445 cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops; 446 cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd; 447 cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr; 448 449 if (arg->has_bps_max) { 450 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max; 451 } 452 if (arg->has_bps_rd_max) { 453 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max; 454 } 455 if (arg->has_bps_wr_max) { 456 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max; 457 } 458 if (arg->has_iops_max) { 459 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max; 460 } 461 if (arg->has_iops_rd_max) { 462 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max; 463 } 464 if (arg->has_iops_wr_max) { 465 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max; 466 } 467 468 if (arg->has_bps_max_length) { 469 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length; 470 } 471 if (arg->has_bps_rd_max_length) { 472 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length; 473 } 474 if (arg->has_bps_wr_max_length) { 475 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length; 476 } 477 if (arg->has_iops_max_length) { 478 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length; 479 } 480 if (arg->has_iops_rd_max_length) { 481 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length; 482 } 483 if (arg->has_iops_wr_max_length) { 484 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length; 485 } 486 487 if (arg->has_iops_size) { 488 cfg.op_size = arg->iops_size; 489 } 490 491 if (!throttle_is_valid(&cfg, errp)) { 492 goto out; 493 } 494 495 if (throttle_enabled(&cfg)) { 496 /* Enable I/O limits if they're not enabled yet, otherwise 497 * just update the throttling group. */ 498 if (!blk_get_public(blk)->throttle_group_member.throttle_state) { 499 blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id); 500 } else if (arg->group) { 501 blk_io_limits_update_group(blk, arg->group); 502 } 503 /* Set the new throttling configuration */ 504 blk_set_io_limits(blk, &cfg); 505 } else if (blk_get_public(blk)->throttle_group_member.throttle_state) { 506 /* If all throttling settings are set to 0, disable I/O limits */ 507 blk_io_limits_disable(blk); 508 } 509 510 out: 511 aio_context_release(aio_context); 512 } 513 514 void qmp_block_latency_histogram_set( 515 const char *id, 516 bool has_boundaries, uint64List *boundaries, 517 bool has_boundaries_read, uint64List *boundaries_read, 518 bool has_boundaries_write, uint64List *boundaries_write, 519 bool has_boundaries_flush, uint64List *boundaries_flush, 520 Error **errp) 521 { 522 BlockBackend *blk = qmp_get_blk(NULL, id, errp); 523 BlockAcctStats *stats; 524 int ret; 525 526 if (!blk) { 527 return; 528 } 529 530 stats = blk_get_stats(blk); 531 532 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write && 533 !has_boundaries_flush) 534 { 535 block_latency_histograms_clear(stats); 536 return; 537 } 538 539 if (has_boundaries || has_boundaries_read) { 540 ret = block_latency_histogram_set( 541 stats, BLOCK_ACCT_READ, 542 has_boundaries_read ? boundaries_read : boundaries); 543 if (ret) { 544 error_setg(errp, "Device '%s' set read boundaries fail", id); 545 return; 546 } 547 } 548 549 if (has_boundaries || has_boundaries_write) { 550 ret = block_latency_histogram_set( 551 stats, BLOCK_ACCT_WRITE, 552 has_boundaries_write ? boundaries_write : boundaries); 553 if (ret) { 554 error_setg(errp, "Device '%s' set write boundaries fail", id); 555 return; 556 } 557 } 558 559 if (has_boundaries || has_boundaries_flush) { 560 ret = block_latency_histogram_set( 561 stats, BLOCK_ACCT_FLUSH, 562 has_boundaries_flush ? boundaries_flush : boundaries); 563 if (ret) { 564 error_setg(errp, "Device '%s' set flush boundaries fail", id); 565 return; 566 } 567 } 568 } 569