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(bool has_device, const char *device, 120 bool has_id, 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(has_device ? device : NULL, 131 has_id ? id : NULL, 132 force, &local_err); 133 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) { 134 error_propagate(errp, local_err); 135 return; 136 } 137 error_free(local_err); 138 } 139 140 void qmp_blockdev_close_tray(bool has_device, const char *device, 141 bool has_id, const char *id, 142 Error **errp) 143 { 144 BlockBackend *blk; 145 Error *local_err = NULL; 146 147 device = has_device ? device : NULL; 148 id = has_id ? id : NULL; 149 150 blk = qmp_get_blk(device, id, errp); 151 if (!blk) { 152 return; 153 } 154 155 if (!blk_dev_has_removable_media(blk)) { 156 error_setg(errp, "Device '%s' is not removable", device ?: id); 157 return; 158 } 159 160 if (!blk_dev_has_tray(blk)) { 161 /* Ignore this command on tray-less devices */ 162 return; 163 } 164 165 if (!blk_dev_is_tray_open(blk)) { 166 return; 167 } 168 169 blk_dev_change_media_cb(blk, true, &local_err); 170 if (local_err) { 171 error_propagate(errp, local_err); 172 return; 173 } 174 } 175 176 static void blockdev_remove_medium(bool has_device, const char *device, 177 bool has_id, const char *id, Error **errp) 178 { 179 BlockBackend *blk; 180 BlockDriverState *bs; 181 AioContext *aio_context; 182 bool has_attached_device; 183 184 device = has_device ? device : NULL; 185 id = has_id ? id : NULL; 186 187 blk = qmp_get_blk(device, id, errp); 188 if (!blk) { 189 return; 190 } 191 192 /* For BBs without a device, we can exchange the BDS tree at will */ 193 has_attached_device = blk_get_attached_dev(blk); 194 195 if (has_attached_device && !blk_dev_has_removable_media(blk)) { 196 error_setg(errp, "Device '%s' is not removable", device ?: id); 197 return; 198 } 199 200 if (has_attached_device && blk_dev_has_tray(blk) && 201 !blk_dev_is_tray_open(blk)) 202 { 203 error_setg(errp, "Tray of device '%s' is not open", device ?: id); 204 return; 205 } 206 207 bs = blk_bs(blk); 208 if (!bs) { 209 return; 210 } 211 212 aio_context = bdrv_get_aio_context(bs); 213 aio_context_acquire(aio_context); 214 215 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { 216 goto out; 217 } 218 219 blk_remove_bs(blk); 220 221 if (!blk_dev_has_tray(blk)) { 222 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be 223 * called at all); therefore, the medium needs to be ejected here. 224 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load 225 * value passed here (i.e. false). */ 226 blk_dev_change_media_cb(blk, false, &error_abort); 227 } 228 229 out: 230 aio_context_release(aio_context); 231 } 232 233 void qmp_blockdev_remove_medium(const char *id, Error **errp) 234 { 235 blockdev_remove_medium(false, NULL, true, id, errp); 236 } 237 238 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk, 239 BlockDriverState *bs, Error **errp) 240 { 241 Error *local_err = NULL; 242 bool has_device; 243 int ret; 244 245 /* For BBs without a device, we can exchange the BDS tree at will */ 246 has_device = blk_get_attached_dev(blk); 247 248 if (has_device && !blk_dev_has_removable_media(blk)) { 249 error_setg(errp, "Device is not removable"); 250 return; 251 } 252 253 if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) { 254 error_setg(errp, "Tray of the device is not open"); 255 return; 256 } 257 258 if (blk_bs(blk)) { 259 error_setg(errp, "There already is a medium in the device"); 260 return; 261 } 262 263 ret = blk_insert_bs(blk, bs, errp); 264 if (ret < 0) { 265 return; 266 } 267 268 if (!blk_dev_has_tray(blk)) { 269 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be 270 * called at all); therefore, the medium needs to be pushed into the 271 * slot here. 272 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load 273 * value passed here (i.e. true). */ 274 blk_dev_change_media_cb(blk, true, &local_err); 275 if (local_err) { 276 error_propagate(errp, local_err); 277 blk_remove_bs(blk); 278 return; 279 } 280 } 281 } 282 283 static void blockdev_insert_medium(bool has_device, const char *device, 284 bool has_id, const char *id, 285 const char *node_name, Error **errp) 286 { 287 BlockBackend *blk; 288 BlockDriverState *bs; 289 290 blk = qmp_get_blk(has_device ? device : NULL, 291 has_id ? id : NULL, 292 errp); 293 if (!blk) { 294 return; 295 } 296 297 bs = bdrv_find_node(node_name); 298 if (!bs) { 299 error_setg(errp, "Node '%s' not found", node_name); 300 return; 301 } 302 303 if (bdrv_has_blk(bs)) { 304 error_setg(errp, "Node '%s' is already in use", node_name); 305 return; 306 } 307 308 qmp_blockdev_insert_anon_medium(blk, bs, errp); 309 } 310 311 void qmp_blockdev_insert_medium(const char *id, const char *node_name, 312 Error **errp) 313 { 314 blockdev_insert_medium(false, NULL, true, id, node_name, errp); 315 } 316 317 void qmp_blockdev_change_medium(bool has_device, const char *device, 318 bool has_id, const char *id, 319 const char *filename, 320 bool has_format, const char *format, 321 bool has_force, bool force, 322 bool has_read_only, 323 BlockdevChangeReadOnlyMode read_only, 324 Error **errp) 325 { 326 BlockBackend *blk; 327 BlockDriverState *medium_bs = NULL; 328 int bdrv_flags; 329 bool detect_zeroes; 330 int rc; 331 QDict *options = NULL; 332 Error *err = NULL; 333 334 blk = qmp_get_blk(has_device ? device : NULL, 335 has_id ? id : NULL, 336 errp); 337 if (!blk) { 338 goto fail; 339 } 340 341 if (blk_bs(blk)) { 342 blk_update_root_state(blk); 343 } 344 345 bdrv_flags = blk_get_open_flags_from_root_state(blk); 346 bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | 347 BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY); 348 349 if (!has_read_only) { 350 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN; 351 } 352 353 switch (read_only) { 354 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN: 355 break; 356 357 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY: 358 bdrv_flags &= ~BDRV_O_RDWR; 359 break; 360 361 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE: 362 bdrv_flags |= BDRV_O_RDWR; 363 break; 364 365 default: 366 abort(); 367 } 368 369 options = qdict_new(); 370 detect_zeroes = blk_get_detect_zeroes_from_root_state(blk); 371 qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off"); 372 373 if (has_format) { 374 qdict_put_str(options, "driver", format); 375 } 376 377 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp); 378 if (!medium_bs) { 379 goto fail; 380 } 381 382 rc = do_open_tray(has_device ? device : NULL, 383 has_id ? id : NULL, 384 force, &err); 385 if (rc && rc != -ENOSYS) { 386 error_propagate(errp, err); 387 goto fail; 388 } 389 error_free(err); 390 err = NULL; 391 392 blockdev_remove_medium(has_device, device, has_id, id, &err); 393 if (err) { 394 error_propagate(errp, err); 395 goto fail; 396 } 397 398 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err); 399 if (err) { 400 error_propagate(errp, err); 401 goto fail; 402 } 403 404 qmp_blockdev_close_tray(has_device, device, has_id, id, errp); 405 406 fail: 407 /* If the medium has been inserted, the device has its own reference, so 408 * ours must be relinquished; and if it has not been inserted successfully, 409 * the reference must be relinquished anyway */ 410 bdrv_unref(medium_bs); 411 } 412 413 void qmp_eject(bool has_device, const char *device, 414 bool has_id, const char *id, 415 bool has_force, bool force, Error **errp) 416 { 417 Error *local_err = NULL; 418 int rc; 419 420 if (!has_force) { 421 force = false; 422 } 423 424 rc = do_open_tray(has_device ? device : NULL, 425 has_id ? id : NULL, 426 force, &local_err); 427 if (rc && rc != -ENOSYS) { 428 error_propagate(errp, local_err); 429 return; 430 } 431 error_free(local_err); 432 433 blockdev_remove_medium(has_device, device, has_id, id, errp); 434 } 435 436 /* throttling disk I/O limits */ 437 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) 438 { 439 ThrottleConfig cfg; 440 BlockDriverState *bs; 441 BlockBackend *blk; 442 AioContext *aio_context; 443 444 blk = qmp_get_blk(arg->has_device ? arg->device : NULL, 445 arg->has_id ? arg->id : NULL, 446 errp); 447 if (!blk) { 448 return; 449 } 450 451 aio_context = blk_get_aio_context(blk); 452 aio_context_acquire(aio_context); 453 454 bs = blk_bs(blk); 455 if (!bs) { 456 error_setg(errp, "Device has no medium"); 457 goto out; 458 } 459 460 throttle_config_init(&cfg); 461 cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps; 462 cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd; 463 cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr; 464 465 cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops; 466 cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd; 467 cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr; 468 469 if (arg->has_bps_max) { 470 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max; 471 } 472 if (arg->has_bps_rd_max) { 473 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max; 474 } 475 if (arg->has_bps_wr_max) { 476 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max; 477 } 478 if (arg->has_iops_max) { 479 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max; 480 } 481 if (arg->has_iops_rd_max) { 482 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max; 483 } 484 if (arg->has_iops_wr_max) { 485 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max; 486 } 487 488 if (arg->has_bps_max_length) { 489 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length; 490 } 491 if (arg->has_bps_rd_max_length) { 492 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length; 493 } 494 if (arg->has_bps_wr_max_length) { 495 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length; 496 } 497 if (arg->has_iops_max_length) { 498 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length; 499 } 500 if (arg->has_iops_rd_max_length) { 501 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length; 502 } 503 if (arg->has_iops_wr_max_length) { 504 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length; 505 } 506 507 if (arg->has_iops_size) { 508 cfg.op_size = arg->iops_size; 509 } 510 511 if (!throttle_is_valid(&cfg, errp)) { 512 goto out; 513 } 514 515 if (throttle_enabled(&cfg)) { 516 /* Enable I/O limits if they're not enabled yet, otherwise 517 * just update the throttling group. */ 518 if (!blk_get_public(blk)->throttle_group_member.throttle_state) { 519 blk_io_limits_enable(blk, 520 arg->has_group ? arg->group : 521 arg->has_device ? arg->device : 522 arg->id); 523 } else if (arg->has_group) { 524 blk_io_limits_update_group(blk, arg->group); 525 } 526 /* Set the new throttling configuration */ 527 blk_set_io_limits(blk, &cfg); 528 } else if (blk_get_public(blk)->throttle_group_member.throttle_state) { 529 /* If all throttling settings are set to 0, disable I/O limits */ 530 blk_io_limits_disable(blk); 531 } 532 533 out: 534 aio_context_release(aio_context); 535 } 536 537 void qmp_block_latency_histogram_set( 538 const char *id, 539 bool has_boundaries, uint64List *boundaries, 540 bool has_boundaries_read, uint64List *boundaries_read, 541 bool has_boundaries_write, uint64List *boundaries_write, 542 bool has_boundaries_flush, uint64List *boundaries_flush, 543 Error **errp) 544 { 545 BlockBackend *blk = qmp_get_blk(NULL, id, errp); 546 BlockAcctStats *stats; 547 int ret; 548 549 if (!blk) { 550 return; 551 } 552 553 stats = blk_get_stats(blk); 554 555 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write && 556 !has_boundaries_flush) 557 { 558 block_latency_histograms_clear(stats); 559 return; 560 } 561 562 if (has_boundaries || has_boundaries_read) { 563 ret = block_latency_histogram_set( 564 stats, BLOCK_ACCT_READ, 565 has_boundaries_read ? boundaries_read : boundaries); 566 if (ret) { 567 error_setg(errp, "Device '%s' set read boundaries fail", id); 568 return; 569 } 570 } 571 572 if (has_boundaries || has_boundaries_write) { 573 ret = block_latency_histogram_set( 574 stats, BLOCK_ACCT_WRITE, 575 has_boundaries_write ? boundaries_write : boundaries); 576 if (ret) { 577 error_setg(errp, "Device '%s' set write boundaries fail", id); 578 return; 579 } 580 } 581 582 if (has_boundaries || has_boundaries_flush) { 583 ret = block_latency_histogram_set( 584 stats, BLOCK_ACCT_FLUSH, 585 has_boundaries_flush ? boundaries_flush : boundaries); 586 if (ret) { 587 error_setg(errp, "Device '%s' set flush boundaries fail", id); 588 return; 589 } 590 } 591 } 592