@@ -1573,6 +1573,10 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
1573
1573
if (qemu_opt_get_bool_del (opts , BDRV_OPT_AUTO_READ_ONLY , false)) {
1574
1574
* flags |= BDRV_O_AUTO_RDONLY ;
1575
1575
}
1576
+
1577
+ if (!qemu_opt_get_bool_del (opts , BDRV_OPT_ACTIVE , true)) {
1578
+ * flags |= BDRV_O_INACTIVE ;
1579
+ }
1576
1580
}
1577
1581
1578
1582
static void update_options_from_flags (QDict * options , int flags )
@@ -1799,6 +1803,11 @@ QemuOptsList bdrv_runtime_opts = {
1799
1803
.type = QEMU_OPT_BOOL ,
1800
1804
.help = "Ignore flush requests" ,
1801
1805
},
1806
+ {
1807
+ .name = BDRV_OPT_ACTIVE ,
1808
+ .type = QEMU_OPT_BOOL ,
1809
+ .help = "Node is activated" ,
1810
+ },
1802
1811
{
1803
1812
.name = BDRV_OPT_READ_ONLY ,
1804
1813
.type = QEMU_OPT_BOOL ,
@@ -3077,6 +3086,13 @@ bdrv_attach_child_common(BlockDriverState *child_bs,
3077
3086
assert (child_class -> get_parent_desc );
3078
3087
GLOBAL_STATE_CODE ();
3079
3088
3089
+ if (bdrv_is_inactive (child_bs ) && (perm & ~BLK_PERM_CONSISTENT_READ )) {
3090
+ g_autofree char * perm_names = bdrv_perm_names (perm );
3091
+ error_setg (errp , "Permission '%s' unavailable on inactive node" ,
3092
+ perm_names );
3093
+ return NULL ;
3094
+ }
3095
+
3080
3096
new_child = g_new (BdrvChild , 1 );
3081
3097
* new_child = (BdrvChild ) {
3082
3098
.bs = NULL ,
@@ -3183,6 +3199,11 @@ bdrv_attach_child_noperm(BlockDriverState *parent_bs,
3183
3199
child_bs -> node_name , child_name , parent_bs -> node_name );
3184
3200
return NULL ;
3185
3201
}
3202
+ if (bdrv_is_inactive (child_bs ) && !bdrv_is_inactive (parent_bs )) {
3203
+ error_setg (errp , "Inactive '%s' can't be a %s child of active '%s'" ,
3204
+ child_bs -> node_name , child_name , parent_bs -> node_name );
3205
+ return NULL ;
3206
+ }
3186
3207
3187
3208
bdrv_get_cumulative_perm (parent_bs , & perm , & shared_perm );
3188
3209
bdrv_child_perm (parent_bs , child_bs , NULL , child_role , NULL ,
@@ -6824,6 +6845,10 @@ void bdrv_init_with_whitelist(void)
6824
6845
bdrv_init ();
6825
6846
}
6826
6847
6848
+ bool bdrv_is_inactive (BlockDriverState * bs ) {
6849
+ return bs -> open_flags & BDRV_O_INACTIVE ;
6850
+ }
6851
+
6827
6852
int bdrv_activate (BlockDriverState * bs , Error * * errp )
6828
6853
{
6829
6854
BdrvChild * child , * parent ;
@@ -6955,7 +6980,8 @@ bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
6955
6980
return false;
6956
6981
}
6957
6982
6958
- static int GRAPH_RDLOCK bdrv_inactivate_recurse (BlockDriverState * bs )
6983
+ static int GRAPH_RDLOCK
6984
+ bdrv_inactivate_recurse (BlockDriverState * bs , bool top_level )
6959
6985
{
6960
6986
BdrvChild * child , * parent ;
6961
6987
int ret ;
@@ -6973,7 +6999,14 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
6973
6999
return 0 ;
6974
7000
}
6975
7001
6976
- assert (!(bs -> open_flags & BDRV_O_INACTIVE ));
7002
+ /*
7003
+ * Inactivating an already inactive node on user request is harmless, but if
7004
+ * a child is already inactive before its parent, that's bad.
7005
+ */
7006
+ if (bs -> open_flags & BDRV_O_INACTIVE ) {
7007
+ assert (top_level );
7008
+ return 0 ;
7009
+ }
6977
7010
6978
7011
/* Inactivate this node */
6979
7012
if (bs -> drv -> bdrv_inactivate ) {
@@ -6999,7 +7032,9 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
6999
7032
return - EPERM ;
7000
7033
}
7001
7034
7035
+ bdrv_drained_begin (bs );
7002
7036
bs -> open_flags |= BDRV_O_INACTIVE ;
7037
+ bdrv_drained_end (bs );
7003
7038
7004
7039
/*
7005
7040
* Update permissions, they may differ for inactive nodes.
@@ -7010,7 +7045,7 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
7010
7045
7011
7046
/* Recursively inactivate children */
7012
7047
QLIST_FOREACH (child , & bs -> children , next ) {
7013
- ret = bdrv_inactivate_recurse (child -> bs );
7048
+ ret = bdrv_inactivate_recurse (child -> bs , false );
7014
7049
if (ret < 0 ) {
7015
7050
return ret ;
7016
7051
}
@@ -7019,6 +7054,27 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
7019
7054
return 0 ;
7020
7055
}
7021
7056
7057
+ int bdrv_inactivate (BlockDriverState * bs , Error * * errp )
7058
+ {
7059
+ int ret ;
7060
+
7061
+ GLOBAL_STATE_CODE ();
7062
+ GRAPH_RDLOCK_GUARD_MAINLOOP ();
7063
+
7064
+ if (bdrv_has_bds_parent (bs , true)) {
7065
+ error_setg (errp , "Node has active parent node" );
7066
+ return - EPERM ;
7067
+ }
7068
+
7069
+ ret = bdrv_inactivate_recurse (bs , true);
7070
+ if (ret < 0 ) {
7071
+ error_setg_errno (errp , - ret , "Failed to inactivate node" );
7072
+ return ret ;
7073
+ }
7074
+
7075
+ return 0 ;
7076
+ }
7077
+
7022
7078
int bdrv_inactivate_all (void )
7023
7079
{
7024
7080
BlockDriverState * bs = NULL ;
@@ -7035,7 +7091,7 @@ int bdrv_inactivate_all(void)
7035
7091
if (bdrv_has_bds_parent (bs , false)) {
7036
7092
continue ;
7037
7093
}
7038
- ret = bdrv_inactivate_recurse (bs );
7094
+ ret = bdrv_inactivate_recurse (bs , true );
7039
7095
if (ret < 0 ) {
7040
7096
bdrv_next_cleanup (& it );
7041
7097
break ;
0 commit comments