From: Hanna Reitz <hreitz@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
qemu-devel@nongnu.org, qemu-block@nongnu.org
Subject: Re: [PATCH 5/7] block: Pass BdrvChild ** to replace_child_noperm
Date: Mon, 8 Nov 2021 10:58:06 +0100 [thread overview]
Message-ID: <f2b1abfc-707a-c9c7-e3cd-57fa1cac984b@redhat.com> (raw)
In-Reply-To: <YYVKkd1giB7eZ0k2@redhat.com>
On 05.11.21 16:15, Kevin Wolf wrote:
> Am 04.11.2021 um 11:38 hat Hanna Reitz geschrieben:
>> bdrv_replace_child_noperm() modifies BdrvChild.bs, and can potentially
>> set it to NULL. That is dangerous, because BDS parents generally assume
>> that their children's .bs pointer is never NULL. We therefore want to
>> let bdrv_replace_child_noperm() set the corresponding BdrvChild pointer
>> to NULL, too.
>>
>> This patch lays the foundation for it by passing a BdrvChild ** pointer
>> to bdrv_replace_child_noperm() so that it can later use it to NULL the
>> BdrvChild pointer immediately after setting BdrvChild.bs to NULL.
>>
>> Signed-off-by: Hanna Reitz <hreitz@redhat.com>
>> ---
>> block.c | 59 ++++++++++++++++++++++++++++++++-------------------------
>> 1 file changed, 33 insertions(+), 26 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 6d230ad3d1..ff45447686 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -87,7 +87,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
>> static bool bdrv_recurse_has_child(BlockDriverState *bs,
>> BlockDriverState *child);
>>
>> -static void bdrv_replace_child_noperm(BdrvChild *child,
>> +static void bdrv_replace_child_noperm(BdrvChild **child,
>> BlockDriverState *new_bs);
>> static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
>> BdrvChild *child,
>> @@ -2254,6 +2254,7 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
>>
>> typedef struct BdrvReplaceChildState {
>> BdrvChild *child;
>> + BdrvChild **childp;
> Would it be clearer to rename child to old_child now that it can be
> changed?
>
> I would also consider having childp first because this is really the
> object that we're modifying and potentially rolling back now.
>
>> BlockDriverState *old_bs;
>> } BdrvReplaceChildState;
>>
>> @@ -2269,8 +2270,8 @@ static void bdrv_replace_child_abort(void *opaque)
>> BdrvReplaceChildState *s = opaque;
>> BlockDriverState *new_bs = s->child->bs;
>>
>> - /* old_bs reference is transparently moved from @s to @s->child */
>> - bdrv_replace_child_noperm(s->child, s->old_bs);
>> + /* old_bs reference is transparently moved from @s to *s->childp */
>> + bdrv_replace_child_noperm(s->childp, s->old_bs);
>> bdrv_unref(new_bs);
>> }
>>
>> @@ -2287,21 +2288,23 @@ static TransactionActionDrv bdrv_replace_child_drv = {
>> *
>> * The function doesn't update permissions, caller is responsible for this.
>> */
>> -static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
>> +static void bdrv_replace_child_tran(BdrvChild **childp,
>> + BlockDriverState *new_bs,
>> Transaction *tran)
>> {
>> BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
>> *s = (BdrvReplaceChildState) {
>> - .child = child,
>> - .old_bs = child->bs,
>> + .child = *childp,
>> + .childp = childp,
>> + .old_bs = (*childp)->bs,
>> };
>> tran_add(tran, &bdrv_replace_child_drv, s);
>>
>> if (new_bs) {
>> bdrv_ref(new_bs);
>> }
>> - bdrv_replace_child_noperm(child, new_bs);
>> - /* old_bs reference is transparently moved from @child to @s */
>> + bdrv_replace_child_noperm(childp, new_bs);
>> + /* old_bs reference is transparently moved from *childp to @s */
>> }
>>
>> /*
>> @@ -2672,9 +2675,10 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
>> return permissions[qapi_perm];
>> }
>>
>> -static void bdrv_replace_child_noperm(BdrvChild *child,
>> +static void bdrv_replace_child_noperm(BdrvChild **childp,
>> BlockDriverState *new_bs)
>> {
>> + BdrvChild *child = *childp;
>> BlockDriverState *old_bs = child->bs;
>> int new_bs_quiesce_counter;
>> int drain_saldo;
>> @@ -2767,7 +2771,7 @@ static void bdrv_attach_child_common_abort(void *opaque)
>> BdrvChild *child = *s->child;
>> BlockDriverState *bs = child->bs;
>>
>> - bdrv_replace_child_noperm(child, NULL);
>> + bdrv_replace_child_noperm(s->child, NULL);
>>
>> if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
>> bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
>> @@ -2867,7 +2871,7 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
>> }
>>
>> bdrv_ref(child_bs);
>> - bdrv_replace_child_noperm(new_child, child_bs);
>> + bdrv_replace_child_noperm(&new_child, child_bs);
>>
>> *child = new_child;
>>
>> @@ -2927,12 +2931,12 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
>> return 0;
>> }
>>
>> -static void bdrv_detach_child(BdrvChild *child)
>> +static void bdrv_detach_child(BdrvChild **childp)
>> {
>> - BlockDriverState *old_bs = child->bs;
>> + BlockDriverState *old_bs = (*childp)->bs;
>>
>> - bdrv_replace_child_noperm(child, NULL);
>> - bdrv_child_free(child);
>> + bdrv_replace_child_noperm(childp, NULL);
>> + bdrv_child_free(*childp);
>>
>> if (old_bs) {
>> /*
>> @@ -3038,7 +3042,7 @@ void bdrv_root_unref_child(BdrvChild *child)
>> BlockDriverState *child_bs;
>>
>> child_bs = child->bs;
>> - bdrv_detach_child(child);
>> + bdrv_detach_child(&child);
>> bdrv_unref(child_bs);
>> }
>>
>> @@ -4891,30 +4895,33 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
>> BdrvChild *child,
>> Transaction *tran)
>> {
>> + BdrvChild **childp;
>> BdrvRemoveFilterOrCowChild *s;
>>
>> - assert(child == bs->backing || child == bs->file);
>> + if (child == bs->backing) {
>> + childp = &bs->backing;
>> + } else if (child == bs->file) {
>> + childp = &bs->file;
>> + } else {
>> + g_assert_not_reached();
>> + }
>>
>> if (!child) {
>> return;
>> }
>>
>> if (child->bs) {
>> - bdrv_replace_child_tran(child, NULL, tran);
>> + bdrv_replace_child_tran(childp, NULL, tran);
>> }
>>
>> s = g_new(BdrvRemoveFilterOrCowChild, 1);
>> *s = (BdrvRemoveFilterOrCowChild) {
>> .child = child,
>> - .is_backing = (child == bs->backing),
>> + .is_backing = (childp == &bs->backing),
>> };
>> tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
>>
>> - if (s->is_backing) {
>> - bs->backing = NULL;
>> - } else {
>> - bs->file = NULL;
>> - }
>> + *childp = NULL;
>> }
> Hmm... This looks a bit dangerous. Is it guaranteed that bs lives until
> the end of the transaction? I guess it has to because we want to be able
> to roll back, so probably this is okay, though I'm not sure if I would
> bet money on it.
Well, if it should live long enough, a bdrv_ref()+unref() definitely
shouldn’t hurt.
> But...
>
>> @@ -4950,7 +4957,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
>> c->name, from->node_name);
>> return -EPERM;
>> }
>> - bdrv_replace_child_tran(c, to, tran);
>> + bdrv_replace_child_tran(&c, to, tran);
>> }
> ...here, c is a local stack variable that is even reused in a loop.
> bdrv_replace_child_tran() now keeps a pointer to the same variable in
> the transaction state for each BdrvChild in the whole parent list, and
> by the time the transaction is finalised, I think they are all dangling
> pointers anyway because they pointed to stack variables in a function
> that has already returned.
Oh no. Yes, that’s a bit of a problem...
> bdrv_replace_child_tran() should probably have a comment like we already
> have in bdrv_attach_child_common():
>
> * @child is saved to a new entry of @tran, so that *@child could be reverted to
> * NULL on abort(). So referenced variable must live at least until transaction
> * end.
Right. Now just to figure out how to solve the concrete problem... :/
(Yes, a borrow checker would’ve helped :))
Hanna
next prev parent reply other threads:[~2021-11-08 10:01 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-04 10:38 [PATCH 0/7] block: Attempt on fixing 030-reported errors Hanna Reitz
2021-11-04 10:38 ` [PATCH 1/7] stream: Traverse graph after modification Hanna Reitz
2021-11-10 12:17 ` Vladimir Sementsov-Ogievskiy
2021-11-04 10:38 ` [PATCH 2/7] block: Manipulate children list in .attach/.detach Hanna Reitz
2021-11-10 12:46 ` Vladimir Sementsov-Ogievskiy
2021-11-10 15:05 ` Hanna Reitz
2021-11-10 12:51 ` Vladimir Sementsov-Ogievskiy
2021-11-10 15:12 ` Hanna Reitz
2021-11-04 10:38 ` [PATCH 3/7] block: Unite remove_empty_child and child_free Hanna Reitz
2021-11-10 12:52 ` Vladimir Sementsov-Ogievskiy
2021-11-04 10:38 ` [PATCH 4/7] block: Drop detached child from ignore list Hanna Reitz
2021-11-10 13:38 ` Vladimir Sementsov-Ogievskiy via
2021-11-10 17:32 ` Hanna Reitz
2021-11-04 10:38 ` [PATCH 5/7] block: Pass BdrvChild ** to replace_child_noperm Hanna Reitz
2021-11-05 15:15 ` Kevin Wolf
2021-11-08 9:58 ` Hanna Reitz [this message]
2021-11-04 10:38 ` [PATCH 6/7] block: Let replace_child_noperm free children Hanna Reitz
2021-11-05 15:41 ` Kevin Wolf
2021-11-08 10:12 ` Hanna Reitz
2021-11-04 10:38 ` [PATCH 7/7] iotests/030: Unthrottle parallel jobs in reverse Hanna Reitz
2021-11-04 11:58 ` [PATCH 0/7] block: Attempt on fixing 030-reported errors Kevin Wolf
2021-11-04 13:34 ` Hanna Reitz
2021-11-05 15:44 ` Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f2b1abfc-707a-c9c7-e3cd-57fa1cac984b@redhat.com \
--to=hreitz@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=vsementsov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).