diff options
author | Alberto Garcia <berto@igalia.com> | 2015-11-02 16:51:55 +0200 |
---|---|---|
committer | Max Reitz <mreitz@redhat.com> | 2015-11-11 16:55:28 +0100 |
commit | 81b936ae70e635557af9ca80922ee69146cb5f4c (patch) | |
tree | 5f0e78e898987584d69ebe045f0c31825fd515f4 /blockdev.c | |
parent | f636ae85f3db8ffb987c79715869dba1b8217e8a (diff) |
block: Add 'x-blockdev-del' QMP command
This command is still experimental, hence the name.
This is the companion to 'blockdev-add'. It allows deleting a
BlockBackend with its associated BlockDriverState tree, or a
BlockDriverState that is not attached to any backend.
In either case, the command fails if the reference count is greater
than 1 or the BlockDriverState has any parents.
Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 6cfc148c77aca1da942b094d811bfa3fcf7ac7bb.1446475331.git.berto@igalia.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'blockdev.c')
-rw-r--r-- | blockdev.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/blockdev.c b/blockdev.c index 3197791c7b..8607df90a9 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3479,6 +3479,72 @@ fail: qmp_output_visitor_cleanup(ov); } +void qmp_x_blockdev_del(bool has_id, const char *id, + bool has_node_name, const char *node_name, Error **errp) +{ + AioContext *aio_context; + BlockBackend *blk; + BlockDriverState *bs; + + if (has_id && has_node_name) { + error_setg(errp, "Only one of id and node-name must be specified"); + return; + } else if (!has_id && !has_node_name) { + error_setg(errp, "No block device specified"); + return; + } + + if (has_id) { + blk = blk_by_name(id); + if (!blk) { + error_setg(errp, "Cannot find block backend %s", id); + return; + } + if (blk_get_refcnt(blk) > 1) { + error_setg(errp, "Block backend %s is in use", id); + return; + } + bs = blk_bs(blk); + aio_context = blk_get_aio_context(blk); + } else { + bs = bdrv_find_node(node_name); + if (!bs) { + error_setg(errp, "Cannot find node %s", node_name); + return; + } + blk = bs->blk; + if (blk) { + error_setg(errp, "Node %s is in use by %s", + node_name, blk_name(blk)); + return; + } + aio_context = bdrv_get_aio_context(bs); + } + + aio_context_acquire(aio_context); + + if (bs) { + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, errp)) { + goto out; + } + + if (bs->refcnt > 1 || !QLIST_EMPTY(&bs->parents)) { + error_setg(errp, "Block device %s is in use", + bdrv_get_device_or_node_name(bs)); + goto out; + } + } + + if (blk) { + blk_unref(blk); + } else { + bdrv_unref(bs); + } + +out: + aio_context_release(aio_context); +} + BlockJobInfoList *qmp_query_block_jobs(Error **errp) { BlockJobInfoList *head = NULL, **p_next = &head; |