block: make bdrv_swap rebuild the bs graph node list field.

Moving only the node_name one field could lead to some inconsitencies where a
node_name was defined on a bs which was not registered in the graph node list.

bdrv_swap between a named node bs and a non named node bs would lead to this.

bdrv_make_anon would then crash because it would try to remove the bs from the
graph node list while it is not in it.

This patch remove named node bses from the graph node list before doing the swap
then insert them back.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Benoît Canet 2014-03-05 23:48:29 +01:00 committed by Kevin Wolf
parent 47ea2de2d6
commit 90ce8a061b

24
block.c
View File

@ -1847,11 +1847,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
/* keep the same entry in graph_bdrv_states
* We do want to swap name but don't want to swap linked list entries
*/
bs_dest->node_list = bs_src->node_list;
}
/*
@ -1870,6 +1865,17 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
{
BlockDriverState tmp;
/* The code needs to swap the node_name but simply swapping node_list won't
* work so first remove the nodes from the graph list, do the swap then
* insert them back if needed.
*/
if (bs_new->node_name[0] != '\0') {
QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list);
}
if (bs_old->node_name[0] != '\0') {
QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
}
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
@ -1898,6 +1904,14 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
/* insert the nodes back into the graph node list if needed */
if (bs_new->node_name[0] != '\0') {
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list);
}
if (bs_old->node_name[0] != '\0') {
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
}
bdrv_rebind(bs_new);
bdrv_rebind(bs_old);
}