From: Fabiano Rosas <farosas@suse.de>
To: "Peter Xu" <peterx@redhat.com>,
"Daniel P. Berrangé" <berrange@redhat.com>
Cc: qemu-devel@nongnu.org, Juraj Marcin <jmarcin@redhat.com>,
Feifan Qian <bea1e@proton.me>
Subject: Re: [PATCH 4/5] migration: Fix rare hang of migration_channel_read_peek()
Date: Tue, 28 Jul 2026 16:59:20 -0300 [thread overview]
Message-ID: <87o6fqopgn.fsf@suse.de> (raw)
In-Reply-To: <amjiLyOJF92okvik@x1.local>
Peter Xu <peterx@redhat.com> writes:
> On Tue, Jul 28, 2026 at 05:24:36PM +0100, Daniel P. Berrangé wrote:
>> On Tue, Jul 28, 2026 at 11:52:46AM -0400, Peter Xu wrote:
>> > In an unlikely case, when a migration stream is attached to the destination
>> > QEMU and only send <4 bytes to the channel as magic, it's possible that
>> > migration_channel_read_peek() may spin forever without yielding in the main
>> > thread causing two unwanted consequences:
>> >
>> > - CPU will spin 100% waiting for the rest bytes until it reaches 4
>> > - (more importantly..) Main thread is stuck during this process as the qio
>> > operation won't really yield the coroutine
>> >
>> > Fix it by consuming the bytes that arrived.
>> >
>> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3889
>> > Cc: Daniel P. Berrangé <berrange@redhat.com>
>> > Reported-by: Feifan Qian <bea1e@proton.me>
>> > Signed-off-by: Peter Xu <peterx@redhat.com>
>> > ---
>> > migration/channel.c | 26 +++++++++++++++++++++++---
>> > 1 file changed, 23 insertions(+), 3 deletions(-)
>> >
>> > diff --git a/migration/channel.c b/migration/channel.c
>> > index 1e2935f926..28fe1d2906 100644
>> > --- a/migration/channel.c
>> > +++ b/migration/channel.c
>> > @@ -294,11 +294,31 @@ int migration_channel_read_peek(QIOChannel *ioc,
>> > return -1;
>> > }
>> >
>> > - if (len == buflen) {
>> > + if (len == iov.iov_len) {
>> > break;
>> > - }
>> > + } else if (len == 0) {
>> > + qio_channel_wait_cond(ioc, G_IO_IN);
>> > + } else {
>> > + ssize_t received = len;
>> >
>> > - qio_channel_wait_cond(ioc, G_IO_IN);
>> > + /*
>> > + * Partially arrived, read out to make qio_channel_wait_cond()
>> > + * won't return immediately, causing an unwanted spin on this
>> > + * CPU.
>> > + */
>> > + iov.iov_len = len;
>> > + len = qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, 0, errp);
>>
>> Sure this breaks the API behaviour that the caller is expecting to
>> see.
>>
>> migration_channel_identify will call migration_channel_read_peek
>> to match the magic bytes.
>>
>> But something later in the flow will actually try to read the magic
>> bytes. By consuming them in this migration_channel_read_peek
>> method, surely we're breaking the code that wants to read the bytes
>> later.
>
> Ah right, stupid me. The best then is for partial read we apply a manual
> wait.
>
> I can also revert 604bb1badc ("migration: Properly wait on G_IO_IN when
> peeking messages"), looping with 1ms interval for data isn't too bad. But
> the best is we only do that for partial, so:
>
> diff --git a/migration/channel.c b/migration/channel.c
> index 1e2935f926..88f89521f8 100644
> --- a/migration/channel.c
> +++ b/migration/channel.c
> @@ -296,9 +296,19 @@ int migration_channel_read_peek(QIOChannel *ioc,
>
> if (len == buflen) {
> break;
> + } else if (len == 0) {
> + qio_channel_wait_cond(ioc, G_IO_IN);
> + } else {
> + /*
> + * When partially ready, we can't use qio_channel_wait_cond()
> + * because it will return immediately. Apply a manual wait.
> + */
> + if (qemu_in_coroutine()) {
There's no coroutine at this point, could replace this with an assert.
> + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
> + } else {
> + g_usleep(1000);
> + }
> }
> -
> - qio_channel_wait_cond(ioc, G_IO_IN);
> }
>
> return 0;
>
> Any preference?
>
> Thanks,
>
>>
>> > + /*
>> > + * QIO_CHANNEL_ERR_BLOCK also shouldn't happen, due to the
>> > + * prior peek just happened. We should be pretty sure we will
>> > + * read what we peeked, or the channel was broken.
>> > + */
>> > + if (len != received) {
>> > + return -1;
>> > + }
>> > + iov.iov_base += received;
>> > + iov.iov_len = buflen - received;
>> > + }
>> > }
>> >
>> > return 0;
>> > --
>> > 2.54.0
>> >
>>
>> With regards,
>> Daniel
>> --
>> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
>> |: https://libvirt.org ~~ https://entangle-photo.org :|
>> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>>
next prev parent reply other threads:[~2026-07-28 20:00 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-28 15:52 [PATCH 0/5] migration: Hardening fixes for 11.2 Peter Xu
2026-07-28 15:52 ` [PATCH 1/5] migration: Fix possible overflow in vmstate_handle_alloc() Peter Xu
2026-07-28 19:19 ` Fabiano Rosas
2026-07-28 15:52 ` [PATCH 2/5] migration/multifd: Validate next_packet_size in zlib/zstd recv Peter Xu
2026-07-28 19:44 ` Fabiano Rosas
2026-07-28 15:52 ` [PATCH 3/5] migration/multifd: Replace assert() with error_setg() in recv paths Peter Xu
2026-07-28 19:51 ` Fabiano Rosas
2026-07-28 20:28 ` Peter Xu
2026-07-28 20:59 ` Fabiano Rosas
2026-07-28 21:07 ` Peter Xu
2026-07-28 15:52 ` [PATCH 4/5] migration: Fix rare hang of migration_channel_read_peek() Peter Xu
2026-07-28 16:24 ` Daniel P. Berrangé
2026-07-28 17:09 ` Peter Xu
2026-07-28 17:12 ` Daniel P. Berrangé
2026-07-28 19:59 ` Fabiano Rosas [this message]
2026-07-28 20:46 ` Peter Xu
2026-07-28 21:00 ` Fabiano Rosas
2026-07-28 21:31 ` Peter Xu
2026-07-28 15:52 ` [PATCH 5/5] migration/ram: Check for RAMBlock size mismatch when parsing Peter Xu
2026-07-28 19:54 ` Fabiano Rosas
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=87o6fqopgn.fsf@suse.de \
--to=farosas@suse.de \
--cc=bea1e@proton.me \
--cc=berrange@redhat.com \
--cc=jmarcin@redhat.com \
--cc=peterx@redhat.com \
--cc=qemu-devel@nongnu.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.