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>
This commit is contained in:
		
							parent
							
								
									f636ae85f3
								
							
						
					
					
						commit
						81b936ae70
					
				
							
								
								
									
										66
									
								
								blockdev.c
								
								
								
								
							
							
						
						
									
										66
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1895,8 +1895,8 @@
 | 
			
		|||
# level and no BlockBackend will be created.
 | 
			
		||||
#
 | 
			
		||||
# This command is still a work in progress.  It doesn't support all
 | 
			
		||||
# block drivers, it lacks a matching blockdev-del, and more.  Stay
 | 
			
		||||
# away from it unless you want to help with its development.
 | 
			
		||||
# block drivers among other things.  Stay away from it unless you want
 | 
			
		||||
# to help with its development.
 | 
			
		||||
#
 | 
			
		||||
# @options: block device options for the new device
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -1904,6 +1904,34 @@
 | 
			
		|||
##
 | 
			
		||||
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @x-blockdev-del:
 | 
			
		||||
#
 | 
			
		||||
# Deletes a block device that has been added using blockdev-add.
 | 
			
		||||
# The selected device can be either a block backend or a graph node.
 | 
			
		||||
#
 | 
			
		||||
# In the former case the backend will be destroyed, along with its
 | 
			
		||||
# inserted medium if there's any. The command will fail if the backend
 | 
			
		||||
# or its medium are in use.
 | 
			
		||||
#
 | 
			
		||||
# In the latter case the node will be destroyed. The command will fail
 | 
			
		||||
# if the node is attached to a block backend or is otherwise being
 | 
			
		||||
# used.
 | 
			
		||||
#
 | 
			
		||||
# One of @id or @node-name must be specified, but not both.
 | 
			
		||||
#
 | 
			
		||||
# This command is still a work in progress and is considered
 | 
			
		||||
# experimental. Stay away from it unless you want to help with its
 | 
			
		||||
# development.
 | 
			
		||||
#
 | 
			
		||||
# @id: #optional Name of the block backend device to delete.
 | 
			
		||||
#
 | 
			
		||||
# @node-name: #optional Name of the graph node to delete.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'x-blockdev-del', 'data': { '*id': 'str', '*node-name': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @blockdev-open-tray:
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3946,8 +3946,8 @@ blockdev-add
 | 
			
		|||
Add a block device.
 | 
			
		||||
 | 
			
		||||
This command is still a work in progress.  It doesn't support all
 | 
			
		||||
block drivers, it lacks a matching blockdev-del, and more.  Stay away
 | 
			
		||||
from it unless you want to help with its development.
 | 
			
		||||
block drivers among other things.  Stay away from it unless you want
 | 
			
		||||
to help with its development.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3990,6 +3990,63 @@ Example (2):
 | 
			
		|||
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
EQMP
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "x-blockdev-del",
 | 
			
		||||
        .args_type  = "id:s?,node-name:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_x_blockdev_del,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
x-blockdev-del
 | 
			
		||||
------------
 | 
			
		||||
Since 2.5
 | 
			
		||||
 | 
			
		||||
Deletes a block device thas has been added using blockdev-add.
 | 
			
		||||
The selected device can be either a block backend or a graph node.
 | 
			
		||||
 | 
			
		||||
In the former case the backend will be destroyed, along with its
 | 
			
		||||
inserted medium if there's any. The command will fail if the backend
 | 
			
		||||
or its medium are in use.
 | 
			
		||||
 | 
			
		||||
In the latter case the node will be destroyed. The command will fail
 | 
			
		||||
if the node is attached to a block backend or is otherwise being
 | 
			
		||||
used.
 | 
			
		||||
 | 
			
		||||
One of "id" or "node-name" must be specified, but not both.
 | 
			
		||||
 | 
			
		||||
This command is still a work in progress and is considered
 | 
			
		||||
experimental. Stay away from it unless you want to help with its
 | 
			
		||||
development.
 | 
			
		||||
 | 
			
		||||
Arguments:
 | 
			
		||||
 | 
			
		||||
- "id": Name of the block backend device to delete (json-string, optional)
 | 
			
		||||
- "node-name": Name of the graph node to delete (json-string, optional)
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "blockdev-add",
 | 
			
		||||
     "arguments": {
 | 
			
		||||
         "options": {
 | 
			
		||||
             "driver": "qcow2",
 | 
			
		||||
             "id": "drive0",
 | 
			
		||||
             "file": {
 | 
			
		||||
                 "driver": "file",
 | 
			
		||||
                 "filename": "test.qcow2"
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
-> { "execute": "x-blockdev-del",
 | 
			
		||||
     "arguments": { "id": "drive0" }
 | 
			
		||||
   }
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
EQMP
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue