Am 21.05.25 um 18:05 schrieb Kevin Wolf:
> Am 20.05.2025 um 12:29 hat Fiona Ebner geschrieben:
>> This is in preparation to mark bdrv_drained_begin() as GRAPH_UNLOCKED.
>>
>> Note that even if bdrv_drained_begin() would already be marked as
> 
> "if ... were already marked"

Ack.

---snip 8<---

>> diff --git a/block.c b/block.c
>> index 01144c895e..7148618504 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -106,9 +106,9 @@ static void bdrv_reopen_abort(BDRVReopenState 
>> *reopen_state);
>>  
>>  static bool bdrv_backing_overridden(BlockDriverState *bs);
>>  
>> -static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
>> -                                    GHashTable *visited, Transaction *tran,
>> -                                    Error **errp);
>> +static bool GRAPH_RDLOCK
>> +bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
>> +                        GHashTable *visited, Transaction *tran, Error 
>> **errp);
> 
> For static functions, we should have rhe GRAPH_RDLOCK annotation both
> here and in the actual definition, too.

Will fix in v3!

>>  /* If non-zero, use only whitelisted block drivers */
>>  static int use_bdrv_whitelist;
>> @@ -3040,8 +3040,10 @@ static void GRAPH_WRLOCK 
>> bdrv_attach_child_common_abort(void *opaque)
>>  
>>          /* No need to visit `child`, because it has been detached already */
>>          visited = g_hash_table_new(NULL, NULL);
>> +        bdrv_drain_all_begin();
>>          ret = s->child->klass->change_aio_ctx(s->child, s->old_parent_ctx,
>>                                                visited, tran, &error_abort);
>> +        bdrv_drain_all_end();
>>          g_hash_table_destroy(visited);
>>  
>>          /* transaction is supposed to always succeed */
>> @@ -3122,9 +3124,11 @@ bdrv_attach_child_common(BlockDriverState *child_bs,
>>              bool ret_child;
>>  
>>              g_hash_table_add(visited, new_child);
>> +            bdrv_drain_all_begin();
>>              ret_child = child_class->change_aio_ctx(new_child, child_ctx,
>>                                                      visited, aio_ctx_tran,
>>                                                      NULL);
>> +            bdrv_drain_all_end();
>>              if (ret_child == true) {
>>                  error_free(local_err);
>>                  ret = 0;
> 
> Should we document in the header file that BdrvChildClass.change_aio_ctx
> is called with the node drained?
> 
> We could add assertions to bdrv_child/parent_change_aio_context or at
> least comments to this effect. (Assertions might be over the top because
> it's easy to verify that both are only called from
> bdrv_change_aio_context().)

Sounds good. Would the following be okay?

For bdrv_parent_change_aio_context() and for change_aio_ctx() the same
(except the name of @child is @c for the former):

> /*
>  * Changes the AioContext of for @child to @ctx and recursively for the
>  * associated block nodes and all their children and parents. Returns true if
>  * the change is possible and the transaction @tran can be continued. Returns
>  * false and sets @errp if not and the transaction must be aborted.
>  *
>  * @visited will accumulate all visited BdrvChild objects. The caller is
>  * responsible for freeing the list afterwards.
>  *
>  * Must be called with the affected block nodes drained.
>  */

and for bdrv_child_change_aio_context() slightly different:

> /*
>  * Changes the AioContext of for @c->bs to @ctx and recursively for all its
>  * children and parents. Returns true if the change is possible and the
>  * transaction @tran can be continued. Returns false and sets @errp if not and
>  * the transaction must be aborted.
>  *
>  * @visited will accumulate all visited BdrvChild objects. The caller is
>  * responsible for freeing the list afterwards.
>  *
>  * Must be called with the affected block nodes drained.
>  */

---snip 8<---

>> @@ -7720,7 +7717,11 @@ int bdrv_try_change_aio_context(BlockDriverState *bs, 
>> AioContext *ctx,
>>      if (ignore_child) {
>>          g_hash_table_add(visited, ignore_child);
>>      }
>> +    bdrv_drain_all_begin();
>> +    bdrv_graph_rdlock_main_loop();
>>      ret = bdrv_change_aio_context(bs, ctx, visited, tran, errp);
>> +    bdrv_graph_rdunlock_main_loop();
>> +    bdrv_drain_all_end();
>>      g_hash_table_destroy(visited);
> 
> I think you're ending the drained section too early here. Previously,
> the nodes were kept drained until after tran_abort/commit(), and I think
> that's important (tran_commit() is the thing that actually switches the
> AioContext).

Right, I'll change this in v3.

Best Regards,
Fiona


Reply via email to