@@ -87,8 +87,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
87
87
static bool bdrv_recurse_has_child (BlockDriverState * bs ,
88
88
BlockDriverState * child );
89
89
90
+ static void bdrv_child_free (BdrvChild * child );
90
91
static void bdrv_replace_child_noperm (BdrvChild * * child ,
91
- BlockDriverState * new_bs );
92
+ BlockDriverState * new_bs ,
93
+ bool free_empty_child );
92
94
static void bdrv_remove_file_or_backing_child (BlockDriverState * bs ,
93
95
BdrvChild * child ,
94
96
Transaction * tran );
@@ -2256,12 +2258,16 @@ typedef struct BdrvReplaceChildState {
2256
2258
BdrvChild * child ;
2257
2259
BdrvChild * * childp ;
2258
2260
BlockDriverState * old_bs ;
2261
+ bool free_empty_child ;
2259
2262
} BdrvReplaceChildState ;
2260
2263
2261
2264
static void bdrv_replace_child_commit (void * opaque )
2262
2265
{
2263
2266
BdrvReplaceChildState * s = opaque ;
2264
2267
2268
+ if (s -> free_empty_child && !s -> child -> bs ) {
2269
+ bdrv_child_free (s -> child );
2270
+ }
2265
2271
bdrv_unref (s -> old_bs );
2266
2272
}
2267
2273
@@ -2278,22 +2284,26 @@ static void bdrv_replace_child_abort(void *opaque)
2278
2284
* modify the BdrvChild * pointer we indirectly pass to it, i.e. it
2279
2285
* will not modify s->child. From that perspective, it does not matter
2280
2286
* whether we pass s->childp or &s->child.
2281
- * (TODO: Right now, bdrv_replace_child_noperm() never modifies that
2282
- * pointer anyway (though it will in the future), so at this point it
2283
- * absolutely does not matter whether we pass s->childp or &s->child.)
2284
2287
* (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
2285
2288
* it here.
2286
2289
* (3) If new_bs is NULL, *s->childp will have been NULLed by
2287
2290
* bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
2288
2291
* must not pass a NULL *s->childp here.
2289
- * (TODO: In its current state, bdrv_replace_child_noperm() will not
2290
- * have NULLed *s->childp, so this does not apply yet. It will in the
2291
- * future.)
2292
2292
*
2293
2293
* So whether new_bs was NULL or not, we cannot pass s->childp here; and in
2294
2294
* any case, there is no reason to pass it anyway.
2295
2295
*/
2296
- bdrv_replace_child_noperm (& s -> child , s -> old_bs );
2296
+ bdrv_replace_child_noperm (& s -> child , s -> old_bs , true);
2297
+ /*
2298
+ * The child was pre-existing, so s->old_bs must be non-NULL, and
2299
+ * s->child thus must not have been freed
2300
+ */
2301
+ assert (s -> child != NULL );
2302
+ if (!new_bs ) {
2303
+ /* As described above, *s->childp was cleared, so restore it */
2304
+ assert (s -> childp != NULL );
2305
+ * s -> childp = s -> child ;
2306
+ }
2297
2307
bdrv_unref (new_bs );
2298
2308
}
2299
2309
@@ -2310,30 +2320,44 @@ static TransactionActionDrv bdrv_replace_child_drv = {
2310
2320
*
2311
2321
* The function doesn't update permissions, caller is responsible for this.
2312
2322
*
2323
+ * (*childp)->bs must not be NULL.
2324
+ *
2313
2325
* Note that if new_bs == NULL, @childp is stored in a state object attached
2314
2326
* to @tran, so that the old child can be reinstated in the abort handler.
2315
2327
* Therefore, if @new_bs can be NULL, @childp must stay valid until the
2316
2328
* transaction is committed or aborted.
2317
2329
*
2318
- * (TODO: The reinstating does not happen yet, but it will once
2319
- * bdrv_replace_child_noperm() NULLs *childp when new_bs is NULL.)
2330
+ * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
2331
+ * freed (on commit). @free_empty_child should only be false if the
2332
+ * caller will free the BDrvChild themselves (which may be important
2333
+ * if this is in turn called in another transactional context).
2320
2334
*/
2321
2335
static void bdrv_replace_child_tran (BdrvChild * * childp ,
2322
2336
BlockDriverState * new_bs ,
2323
- Transaction * tran )
2337
+ Transaction * tran ,
2338
+ bool free_empty_child )
2324
2339
{
2325
2340
BdrvReplaceChildState * s = g_new (BdrvReplaceChildState , 1 );
2326
2341
* s = (BdrvReplaceChildState ) {
2327
2342
.child = * childp ,
2328
2343
.childp = new_bs == NULL ? childp : NULL ,
2329
2344
.old_bs = (* childp )-> bs ,
2345
+ .free_empty_child = free_empty_child ,
2330
2346
};
2331
2347
tran_add (tran , & bdrv_replace_child_drv , s );
2332
2348
2349
+ /* The abort handler relies on this */
2350
+ assert (s -> old_bs != NULL );
2351
+
2333
2352
if (new_bs ) {
2334
2353
bdrv_ref (new_bs );
2335
2354
}
2336
- bdrv_replace_child_noperm (childp , new_bs );
2355
+ /*
2356
+ * Pass free_empty_child=false, we will free the child (if
2357
+ * necessary) in bdrv_replace_child_commit() (if our
2358
+ * @free_empty_child parameter was true).
2359
+ */
2360
+ bdrv_replace_child_noperm (childp , new_bs , false);
2337
2361
/* old_bs reference is transparently moved from *childp to @s */
2338
2362
}
2339
2363
@@ -2705,8 +2729,22 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
2705
2729
return permissions [qapi_perm ];
2706
2730
}
2707
2731
2732
+ /**
2733
+ * Replace (*childp)->bs by @new_bs.
2734
+ *
2735
+ * If @new_bs is NULL, *childp will be set to NULL, too: BDS parents
2736
+ * generally cannot handle a BdrvChild with .bs == NULL, so clearing
2737
+ * BdrvChild.bs should generally immediately be followed by the
2738
+ * BdrvChild pointer being cleared as well.
2739
+ *
2740
+ * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
2741
+ * freed. @free_empty_child should only be false if the caller will
2742
+ * free the BdrvChild themselves (this may be important in a
2743
+ * transactional context, where it may only be freed on commit).
2744
+ */
2708
2745
static void bdrv_replace_child_noperm (BdrvChild * * childp ,
2709
- BlockDriverState * new_bs )
2746
+ BlockDriverState * new_bs ,
2747
+ bool free_empty_child )
2710
2748
{
2711
2749
BdrvChild * child = * childp ;
2712
2750
BlockDriverState * old_bs = child -> bs ;
@@ -2743,6 +2781,9 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
2743
2781
}
2744
2782
2745
2783
child -> bs = new_bs ;
2784
+ if (!new_bs ) {
2785
+ * childp = NULL ;
2786
+ }
2746
2787
2747
2788
if (new_bs ) {
2748
2789
QLIST_INSERT_HEAD (& new_bs -> parents , child , next_parent );
@@ -2772,6 +2813,10 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
2772
2813
bdrv_parent_drained_end_single (child );
2773
2814
drain_saldo ++ ;
2774
2815
}
2816
+
2817
+ if (free_empty_child && !child -> bs ) {
2818
+ bdrv_child_free (child );
2819
+ }
2775
2820
}
2776
2821
2777
2822
/**
@@ -2801,7 +2846,14 @@ static void bdrv_attach_child_common_abort(void *opaque)
2801
2846
BdrvChild * child = * s -> child ;
2802
2847
BlockDriverState * bs = child -> bs ;
2803
2848
2804
- bdrv_replace_child_noperm (s -> child , NULL );
2849
+ /*
2850
+ * Pass free_empty_child=false, because we still need the child
2851
+ * for the AioContext operations on the parent below; those
2852
+ * BdrvChildClass methods all work on a BdrvChild object, so we
2853
+ * need to keep it as an empty shell (after this function, it will
2854
+ * not be attached to any parent, and it will not have a .bs).
2855
+ */
2856
+ bdrv_replace_child_noperm (s -> child , NULL , false);
2805
2857
2806
2858
if (bdrv_get_aio_context (bs ) != s -> old_child_ctx ) {
2807
2859
bdrv_try_set_aio_context (bs , s -> old_child_ctx , & error_abort );
@@ -2823,7 +2875,6 @@ static void bdrv_attach_child_common_abort(void *opaque)
2823
2875
2824
2876
bdrv_unref (bs );
2825
2877
bdrv_child_free (child );
2826
- * s -> child = NULL ;
2827
2878
}
2828
2879
2829
2880
static TransactionActionDrv bdrv_attach_child_common_drv = {
@@ -2901,7 +2952,9 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
2901
2952
}
2902
2953
2903
2954
bdrv_ref (child_bs );
2904
- bdrv_replace_child_noperm (& new_child , child_bs );
2955
+ bdrv_replace_child_noperm (& new_child , child_bs , true);
2956
+ /* child_bs was non-NULL, so new_child must not have been freed */
2957
+ assert (new_child != NULL );
2905
2958
2906
2959
* child = new_child ;
2907
2960
@@ -2960,8 +3013,7 @@ static void bdrv_detach_child(BdrvChild **childp)
2960
3013
{
2961
3014
BlockDriverState * old_bs = (* childp )-> bs ;
2962
3015
2963
- bdrv_replace_child_noperm (childp , NULL );
2964
- bdrv_child_free (* childp );
3016
+ bdrv_replace_child_noperm (childp , NULL , true);
2965
3017
2966
3018
if (old_bs ) {
2967
3019
/*
@@ -4951,7 +5003,11 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
4951
5003
}
4952
5004
4953
5005
if (child -> bs ) {
4954
- bdrv_replace_child_tran (childp , NULL , tran );
5006
+ /*
5007
+ * Pass free_empty_child=false, we will free the child in
5008
+ * bdrv_remove_filter_or_cow_child_commit()
5009
+ */
5010
+ bdrv_replace_child_tran (childp , NULL , tran , false);
4955
5011
}
4956
5012
4957
5013
s = g_new (BdrvRemoveFilterOrCowChild , 1 );
@@ -4961,8 +5017,6 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
4961
5017
.is_backing = (childp == & bs -> backing ),
4962
5018
};
4963
5019
tran_add (tran , & bdrv_remove_filter_or_cow_child_drv , s );
4964
-
4965
- * childp = NULL ;
4966
5020
}
4967
5021
4968
5022
/*
@@ -5005,7 +5059,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
5005
5059
* Passing a pointer to the local variable @c is fine here, because
5006
5060
* @to is not NULL, and so &c will not be attached to the transaction.
5007
5061
*/
5008
- bdrv_replace_child_tran (& c , to , tran );
5062
+ bdrv_replace_child_tran (& c , to , tran , true );
5009
5063
}
5010
5064
5011
5065
return 0 ;
@@ -5161,7 +5215,9 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
5161
5215
bdrv_drained_begin (old_bs );
5162
5216
bdrv_drained_begin (new_bs );
5163
5217
5164
- bdrv_replace_child_tran (& child , new_bs , tran );
5218
+ bdrv_replace_child_tran (& child , new_bs , tran , true);
5219
+ /* @new_bs must have been non-NULL, so @child must not have been freed */
5220
+ assert (child != NULL );
5165
5221
5166
5222
found = g_hash_table_new (NULL , NULL );
5167
5223
refresh_list = bdrv_topological_dfs (refresh_list , found , old_bs );
0 commit comments