| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | #include "qemu/osdep.h" |
| 3 | |
| 4 | #include "system/block-backend.h" |
| 5 | #include "block/block_int.h" |
| 6 | #include "qapi/qapi-commands-block.h" |
| 7 | #include "qapi/error.h" |
| 8 | #include "qemu-io.h" |
| 9 | |
| 10 | void qmp_x_qemu_io(const char *device, const char *qdev, |
| 11 | const char *command, Error **errp) |
| 12 | { |
| 13 | BlockBackend *blk = NULL; |
| 14 | BlockBackend *local_blk = NULL; |
| 15 | BlockDriverState *bs = NULL; |
| 16 | int ret; |
| 17 | |
| 18 | if (!device && !qdev) { |
| 19 | error_setg(errp, "Must specify either device or qdev"); |
| 20 | return; |
| 21 | } |
| 22 | if (qdev && device) { |
| 23 | error_setg(errp, "Cannot specify both qdev and device"); |
| 24 | return; |
| 25 | } |
| 26 | |
| 27 | if (qdev) { |
| 28 | blk = blk_by_qdev_id(qdev, errp); |
| 29 | if (!blk) { |
| 30 | return; |
| 31 | } |
| 32 | } else { |
| 33 | blk = blk_by_name(device); |
| 34 | if (!blk) { |
| 35 | bs = bdrv_lookup_bs(NULL, device, errp); |
| 36 | if (!bs) { |
| 37 | return; |
| 38 | } |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | if (bs) { |
| 43 | blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); |
| 44 | ret = blk_insert_bs(blk, bs, errp); |
| 45 | if (ret < 0) { |
| 46 | goto fail; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | /* |
| 51 | * Notably absent: Proper permission management. This is sad, but it seems |
| 52 | * almost impossible to achieve without changing the semantics and thereby |
| 53 | * limiting the use cases of the qemu-io command. |
| 54 | * |
| 55 | * In an ideal world we would unconditionally create a new BlockBackend for |
| 56 | * qemuio_command(), but we have commands like 'reopen' and want them to |
| 57 | * take effect on the exact BlockBackend whose name the user passed instead |
| 58 | * of just on a temporary copy of it. |
| 59 | * |
| 60 | * Another problem is that deleting the temporary BlockBackend involves |
| 61 | * draining all requests on it first, but some qemu-iotests cases want to |
| 62 | * issue multiple aio_read/write requests and expect them to complete in |
| 63 | * the background while the monitor has already returned. |
| 64 | * |
| 65 | * This is also what prevents us from saving the original permissions and |
| 66 | * restoring them later: We can't revoke permissions until all requests |
| 67 | * have completed, and we don't know when that is nor can we really let |
| 68 | * anything else run before we have revoken them to avoid race conditions. |
| 69 | * |
| 70 | * What happens now is that command() in qemu-io-cmds.c can extend the |
| 71 | * permissions if necessary for the qemu-io command. And they simply stay |
| 72 | * extended, possibly resulting in a read-only guest device keeping write |
| 73 | * permissions. Ugly, but it appears to be the lesser evil. |
| 74 | */ |
| 75 | qemuio_command(blk, command, errp); |
| 76 | |
| 77 | fail: |
| 78 | blk_unref(local_blk); |
| 79 | } |