From: Kevin Wolf <kwolf@redhat.com>
To: Hanna Reitz <hreitz@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>,
Eric Blake <eblake@redhat.com>,
qemu-devel@nongnu.org, qemu-block@nongnu.org
Subject: Re: [PATCH v2 1/3] block: Make bdrv_refresh_limits() non-recursive
Date: Thu, 3 Mar 2022 17:56:26 +0100 [thread overview]
Message-ID: <YiDzOnUmNYy9sABR@redhat.com> (raw)
In-Reply-To: <20220216105355.30729-2-hreitz@redhat.com>
Am 16.02.2022 um 11:53 hat Hanna Reitz geschrieben:
> bdrv_refresh_limits() recurses down to the node's children. That does
> not seem necessary: When we refresh limits on some node, and then
> recurse down and were to change one of its children's BlockLimits, then
> that would mean we noticed the changed limits by pure chance. The fact
> that we refresh the parent's limits has nothing to do with it, so the
> reason for the change probably happened before this point in time, and
> we should have refreshed the limits then.
>
> On the other hand, we do not have infrastructure for noticing that block
> limits change after they have been initialized for the first time (this
> would require propagating the change upwards to the respective node's
> parents), and so evidently we consider this case impossible.
I like your optimistic approach, but my interpretation would have been
that this is simply a bug. ;-)
blockdev-reopen allows changing options that affect the block limits
(most importantly probably request_alignment), so this should be
propagated to the parents. I think we'll actually not see failures if we
forget to do this, but parents can either advertise excessive alignment
requirements or they may run into RMW when accessing the child, so this
would only affect performance. This is probably why nobody reported it
yet.
> If this case is impossible, then we will not need to recurse down in
> bdrv_refresh_limits(). Every node's limits are initialized in
> bdrv_open_driver(), and are refreshed whenever its children change.
> We want to use the childrens' limits to get some initial default, but
> we can just take them, we do not need to refresh them.
I think even if we need to propagate to the parents, we still don't need
to propagate to the children because the children have already been
refreshed by whatever changed their options (like bdrv_reopen_commit()).
And parent limits don't influence the child limits at all.
So this patch looks good to me, just not the reasoning.
Kevin
> The problem with recursing is that bdrv_refresh_limits() is not atomic.
> It begins with zeroing BDS.bl, and only then sets proper, valid limits.
> If we do not drain all nodes whose limits are refreshed, then concurrent
> I/O requests can encounter invalid request_alignment values and crash
> qemu. Therefore, a recursing bdrv_refresh_limits() requires the whole
> subtree to be drained, which is currently not ensured by most callers.
>
> A non-recursive bdrv_refresh_limits() only requires the node in question
> to not receive I/O requests, and this is done by most callers in some
> way or another:
> - bdrv_open_driver() deals with a new node with no parents yet
> - bdrv_set_file_or_backing_noperm() acts on a drained node
> - bdrv_reopen_commit() acts only on drained nodes
> - bdrv_append() should in theory require the node to be drained; in
> practice most callers just lock the AioContext, which should at least
> be enough to prevent concurrent I/O requests from accessing invalid
> limits
>
> So we can resolve the bug by making bdrv_refresh_limits() non-recursive.
>
> Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1879437
> Signed-off-by: Hanna Reitz <hreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
> block/io.c | 4 ----
> 1 file changed, 4 deletions(-)
>
> diff --git a/block/io.c b/block/io.c
> index 4e4cb556c5..c3e7301613 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -189,10 +189,6 @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp)
> QLIST_FOREACH(c, &bs->children, next) {
> if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW))
> {
> - bdrv_refresh_limits(c->bs, tran, errp);
> - if (*errp) {
> - return;
> - }
> bdrv_merge_limits(&bs->bl, &c->bs->bl);
> have_limits = true;
> }
> --
> 2.34.1
>
next prev parent reply other threads:[~2022-03-03 16:58 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-16 10:53 [PATCH v2 0/3] block: Make bdrv_refresh_limits() non-recursive Hanna Reitz
2022-02-16 10:53 ` [PATCH v2 1/3] " Hanna Reitz
2022-03-03 16:56 ` Kevin Wolf [this message]
2022-03-04 12:44 ` Hanna Reitz
2022-03-04 14:14 ` Kevin Wolf
2022-03-04 14:59 ` Hanna Reitz
2022-02-16 10:53 ` [PATCH v2 2/3] iotests: Allow using QMP with the QSD Hanna Reitz
2022-02-25 18:54 ` Eric Blake
2022-02-16 10:53 ` [PATCH v2 3/3] iotests/graph-changes-while-io: New test Hanna Reitz
2022-02-28 14:42 ` [PATCH v2 0/3] block: Make bdrv_refresh_limits() non-recursive Stefan Hajnoczi
2022-03-04 13:36 ` 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=YiDzOnUmNYy9sABR@redhat.com \
--to=kwolf@redhat.com \
--cc=eblake@redhat.com \
--cc=hreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.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).