From: Peter Xu <peterx@redhat.com>
To: "Cédric Le Goater" <clg@redhat.com>
Cc: Avihai Horon <avihaih@nvidia.com>,
qemu-devel@nongnu.org,
Alex Williamson <alex.williamson@redhat.com>,
Fabiano Rosas <farosas@suse.de>
Subject: Re: [PATCH 2/3] vfio/migration: Refactor vfio_vmstate_change/_prepare() error reporting
Date: Tue, 22 Oct 2024 10:29:05 -0400 [thread overview]
Message-ID: <Zxe2sZLyIa3XbVeZ@x1n> (raw)
In-Reply-To: <d172a1b8-9e6f-42ef-a78c-decb5c9a2944@redhat.com>
On Tue, Oct 22, 2024 at 03:24:56PM +0200, Cédric Le Goater wrote:
> On 10/22/24 11:38, Avihai Horon wrote:
> >
> > On 21/10/2024 19:54, Peter Xu wrote:
> > > External email: Use caution opening links or attachments
> > >
> > >
> > > On Mon, Oct 21, 2024 at 06:43:13PM +0200, Cédric Le Goater wrote:
> > > > Hello,
> > > >
> > > > > IIUC the migration thread should always see valid migration object, as it
> > > > > takes one refcount at the entrance of migration_thread():
> > > > >
> > > > > object_ref(OBJECT(s));
> > > > Could the migration have failed before ? in migrate_fd_connect()
> > > I just noticed it's a vm state change notifier..
> >
> > Yep.
> > I stumbled upon this bug by accident when running on a buggy machine.
> > Migration wasn't involved, I just started the VM, shut it down and got the assert (as my VFIO device was faulty and errored on RUNNING->STOP state change).
> >
> > You can repro it by forcefully triggering an error on *->STOP transition:
> >
> > diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
> > index 17199b73ae..d41cb7c634 100644
> > --- a/hw/vfio/migration.c
> > +++ b/hw/vfio/migration.c
> > @@ -831,7 +831,9 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state)
> > }
> >
> > ret = vfio_migration_set_state_or_reset(vbasedev, new_state, &local_err);
> > - if (ret) {
> > + if (ret || new_state == VFIO_DEVICE_STATE_STOP) {
> > + ret = -1;
> > + error_setg(&local_err, "%s: forced error", vbasedev->name);
> > /*
> > * Migration should be aborted in this case, but vm_state_notify()
> > * currently does not support reporting failures.
> >
> > >
> > > If so, maybe VFIO could refer to its internal states showing that it's
> > > during a migration first (so as to guarantee the migration object is valid;
> > > e.g., only after save_setup() but before save_cleanup() hooks are invoked).
> >
> > It's an option, but I think it's a bit awkward as we'd need to check
> > that VFIOMigration->data_buffer is set
>
> That's what I was looking at too. It works. It feels a bit awkward
> indeed. We could hide the details in an helper routine though.
>
> > or add a new flag.
>
> yes that's another solution.
>
> Peter,
>
> I wonder if we could grab a ref on current_migration in save_setup(),
> store it under VFIOMigration and drop it save_cleanup() ?
VFIO can definitely do that, but I am not sure how that would help.. as I
think the migration object can never go away anyway during setup->cleanup,
so taking that extra refcount shouldn't change anything.
IOW, AFAICT this bug is triggered only when without migration at all.
>
>
> > Besides that, as Cedric pointed out, VFIO code calls migration_is_setup_or_active() which can also be unsafe, as it might be invoked after migration object has been freed.
> >
> > Maybe a simpler solution would be to extend the the migration object lifetime?
> > Looking at commit history, you can see that commit 1f8956041ad3 ("migration: finalize current_migration object") added migration object finalization at the very end of qemu cleanup.
> > Then came commit 892ae715b6bc ("migration: Cleanup during exit") and moved the migration object finalization to the beginning of qemu cleanup (before stopping the VM etc.).
> >
> > If so, the fix could be something like the below?
> >
> > -------------8<-------------
> > diff --git a/include/migration/misc.h b/include/migration/misc.h
> > index bfadc5613b..5eb099349a 100644
> > --- a/include/migration/misc.h
> > +++ b/include/migration/misc.h
> > @@ -52,6 +52,7 @@ void dump_vmstate_json_to_file(FILE *out_fp);
> >
> > /* migration/migration.c */
> > void migration_object_init(void);
> > +void migration_object_finalize(void);
> > void migration_shutdown(void);
> > bool migration_is_idle(void);
> > bool migration_is_active(void);
> > diff --git a/migration/migration.c b/migration/migration.c
> > index 021faee2f3..9eaa7947bc 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -265,6 +265,11 @@ void migration_object_init(void)
> > dirty_bitmap_mig_init();
> > }
> >
> > +void migration_object_finalize(void)
> > +{
> > + object_unref(OBJECT(current_migration));
> > +}
> > +
> > typedef struct {
> > QEMUBH *bh;
> > QEMUBHFunc *cb;
> > @@ -330,7 +335,6 @@ void migration_shutdown(void)
> > * stop the migration using this structure
> > */
> > migration_cancel(NULL);
> > - object_unref(OBJECT(current_migration));
> >
> > /*
> > * Cancel outgoing migration of dirty bitmaps. It should
> > diff --git a/system/runstate.c b/system/runstate.c
> > index c2c9afa905..fa823f5e72 100644
> > --- a/system/runstate.c
> > +++ b/system/runstate.c
> > @@ -930,5 +930,6 @@ void qemu_cleanup(int status)
> > monitor_cleanup();
> > qemu_chr_cleanup();
> > user_creatable_cleanup();
> > + migration_object_finalize();
> > /* TODO: unref root container, check all devices are ok */
> > }
> > -------------8<-------------
>
> 892ae715b6bc was trying to fix potential use-after-free issues.
>
> I think it is safer to introduce an helper routine checking
> (in some ways) if a migration is in progress than partially
> revert 892ae715b6bc.
Right, Dave also mentioned something in 892ae715b6bc about moving it
earlier:
We do this a bit earlier; so hopefully migration gets out of the way
before all the devices etc are freed.
But I don't know the relationship on device free() v.s. the migration
object. We might at least want to figure that out if we want to move it
again.
I notice that vdpa also started using migration_is_setup_or_active(), so if
it's used in more places, maybe indeed we can consider making them safe to
be called at any phase of QEMU.
Logically it is safe in vm state change hook always because it has the BQL
and the object can only be freed when with BQL.
So let me send a small patch later to hopefully make all these exported
functions (including migration_file_set_error() in this case, logically
anything in migration/misc.h) safe to be called without migration.
--
Peter Xu
next prev parent reply other threads:[~2024-10-22 14:29 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-20 13:01 [PATCH 0/3] vfio/migration: Some bug fixes and cleanups Avihai Horon
2024-10-20 13:01 ` [PATCH 1/3] vfio/migration: Report only stop-copy size in vfio_state_pending_exact() Avihai Horon
2024-10-21 6:48 ` Cédric Le Goater
2024-10-23 10:06 ` Cédric Le Goater
2024-10-25 15:18 ` Michael Tokarev
2024-10-25 16:09 ` Cédric Le Goater
2024-10-20 13:01 ` [PATCH 2/3] vfio/migration: Refactor vfio_vmstate_change/_prepare() error reporting Avihai Horon
2024-10-21 15:14 ` Cédric Le Goater
2024-10-21 15:50 ` Peter Xu
2024-10-21 16:43 ` Cédric Le Goater
2024-10-21 16:54 ` Peter Xu
2024-10-22 9:38 ` Avihai Horon via
2024-10-22 13:24 ` Cédric Le Goater
2024-10-22 14:21 ` Avihai Horon
2024-10-22 14:29 ` Peter Xu [this message]
2024-10-22 14:42 ` Cédric Le Goater
2024-10-22 16:10 ` Peter Xu
2024-10-20 13:01 ` [PATCH 3/3] vfio/migration: Change trace formats from hex to decimal Avihai Horon
2024-10-21 15:17 ` Cédric Le Goater
2024-10-23 15:08 ` [PATCH 0/3] vfio/migration: Some bug fixes and cleanups Cédric Le Goater
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=Zxe2sZLyIa3XbVeZ@x1n \
--to=peterx@redhat.com \
--cc=alex.williamson@redhat.com \
--cc=avihaih@nvidia.com \
--cc=clg@redhat.com \
--cc=farosas@suse.de \
--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 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).