From: Steven Sistare <steven.sistare@oracle.com>
To: Peter Xu <peterx@redhat.com>, Peter Maydell <peter.maydell@linaro.org>
Cc: Fabiano Rosas <farosas@suse.de>,
qemu-devel@nongnu.org, Markus Armbruster <armbru@redhat.com>
Subject: Re: [PULL 17/42] migration: cpr-transfer mode
Date: Tue, 4 Feb 2025 11:52:42 -0500 [thread overview]
Message-ID: <27c6ee8f-d4dd-4ee6-bda8-e9b21289d7d7@oracle.com> (raw)
In-Reply-To: <Z6I_zJF1dljLK-YI@x1.local>
On 2/4/2025 11:26 AM, Peter Xu wrote:
> On Tue, Feb 04, 2025 at 01:40:34PM +0000, Peter Maydell wrote:
>> On Wed, 29 Jan 2025 at 16:11, Fabiano Rosas <farosas@suse.de> wrote:
>>>
>>> From: Steve Sistare <steven.sistare@oracle.com>
>>>
>>> Add the cpr-transfer migration mode, which allows the user to transfer
>>> a guest to a new QEMU instance on the same host with minimal guest pause
>>> time, by preserving guest RAM in place, albeit with new virtual addresses
>>> in new QEMU, and by preserving device file descriptors. Pages that were
>>> locked in memory for DMA in old QEMU remain locked in new QEMU, because the
>>> descriptor of the device that locked them remains open.
>>>
>>> cpr-transfer preserves memory and devices descriptors by sending them to
>>> new QEMU over a unix domain socket using SCM_RIGHTS. Such CPR state cannot
>>> be sent over the normal migration channel, because devices and backends
>>> are created prior to reading the channel, so this mode sends CPR state
>>> over a second "cpr" migration channel. New QEMU reads the cpr channel
>>> prior to creating devices or backends. The user specifies the cpr channel
>>> in the channel arguments on the outgoing side, and in a second -incoming
>>> command-line parameter on the incoming side.
>>>
>>> The user must start old QEMU with the the '-machine aux-ram-share=on' option,
>>> which allows anonymous memory to be transferred in place to the new process
>>> by transferring a memory descriptor for each ram block. Memory-backend
>>> objects must have the share=on attribute, but memory-backend-epc is not
>>> supported.
>>>
>>> The user starts new QEMU on the same host as old QEMU, with command-line
>>> arguments to create the same machine, plus the -incoming option for the
>>> main migration channel, like normal live migration. In addition, the user
>>> adds a second -incoming option with channel type "cpr". This CPR channel
>>> must support file descriptor transfer with SCM_RIGHTS, i.e. it must be a
>>> UNIX domain socket.
>>>
>>> To initiate CPR, the user issues a migrate command to old QEMU, adding
>>> a second migration channel of type "cpr" in the channels argument.
>>> Old QEMU stops the VM, saves state to the migration channels, and enters
>>> the postmigrate state. New QEMU mmap's memory descriptors, and execution
>>> resumes.
>>>
>>> The implementation splits qmp_migrate into start and finish functions.
>>> Start sends CPR state to new QEMU, which responds by closing the CPR
>>> channel. Old QEMU detects the HUP then calls finish, which connects the
>>> main migration channel.
>>>
>>> In summary, the usage is:
>>>
>>> qemu-system-$arch -machine aux-ram-share=on ...
>>>
>>> start new QEMU with "-incoming <main-uri> -incoming <cpr-channel>"
>>>
>>> Issue commands to old QEMU:
>>> migrate_set_parameter mode cpr-transfer
>>>
>>> {"execute": "migrate", ...
>>> {"channel-type": "main"...}, {"channel-type": "cpr"...} ... }
>>>
>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>>> Reviewed-by: Peter Xu <peterx@redhat.com>
>>> Acked-by: Markus Armbruster <armbru@redhat.com>
>>> Link: https://lore.kernel.org/r/1736967650-129648-17-git-send-email-steven.sistare@oracle.com
>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>
>> Hi; this commit includes some code that has confused
>> Coverity (CID 1590980) and it also confused me, so maybe
>> it could be usefully made clearer?
>>
>>
>>> void qmp_migrate(const char *uri, bool has_channels,
>>> MigrationChannelList *channels, bool has_detach, bool detach,
>>> bool has_resume, bool resume, Error **errp)
>>> @@ -2056,6 +2118,7 @@ void qmp_migrate(const char *uri, bool has_channels,
>>> g_autoptr(MigrationChannel) channel = NULL;
>>> MigrationAddress *addr = NULL;
>>> MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
>>> + MigrationChannel *cpr_channel = NULL;
>>>
>>> /*
>>> * Having preliminary checks for uri and channel
>>> @@ -2076,6 +2139,7 @@ void qmp_migrate(const char *uri, bool has_channels,
>>> }
>>> channelv[type] = channels->value;
>>> }
>>> + cpr_channel = channelv[MIGRATION_CHANNEL_TYPE_CPR];
>>> addr = channelv[MIGRATION_CHANNEL_TYPE_MAIN]->addr;
>>> if (!addr) {
>>> error_setg(errp, "Channel list has no main entry");
>>> @@ -2096,12 +2160,52 @@ void qmp_migrate(const char *uri, bool has_channels,
>>> return;
>>> }
>>>
>>> + if (s->parameters.mode == MIG_MODE_CPR_TRANSFER && !cpr_channel) {
>>> + error_setg(errp, "missing 'cpr' migration channel");
>>> + return;
>>> + }
>>
>> Here in qmp_migrate() we bail out if cpr_channel is NULL,
>> provided that s->parameters.mode is MIG_MODE_CPR_TRANSFER...
>>
>>> +
>>> resume_requested = has_resume && resume;
>>> if (!migrate_prepare(s, resume_requested, errp)) {
>>> /* Error detected, put into errp */
>>> return;
>>> }
>>>
>>> + if (cpr_state_save(cpr_channel, &local_err)) {
>>
>> ...but in cpr_state_save() when we decide whether to dereference
>> cpr_channel or not, we aren't checking s->parameters.mode,
>> we call migrate_mode() and check the result of that.
>> And migrate_mode() isn't completely trivial: it calls
>> cpr_get_incoming_mode(), so it's not obvious that it's
>> necessarily going to be the same value as s->parameters.mode.
>> So Coverity complains that it sees a code path where we
>> might dereference cpr_channel even when it's NULL.
>>
>> Could this be made a bit clearer somehow, do you think?
>
> That migrate_mode() is indeed tricky, and should only be needed for
> incoming side QEMU to workaround current limitation that the migration
> parameter "mode" cannot be set as early as when cpr_state_load() happens..
>
> I think we could check s->parameters.mode here before doing
> cpr_state_save(), it can also be more readable.
>
> Steve, do you want to send a patch?
I am busy today but I will submit a patch tomorrow. cpr_state_save
is only used on the outgoing side, so internally it can check
s->parameters.mode instead of migrate_mode().
- Steve
next prev parent reply other threads:[~2025-02-04 16:53 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-29 16:00 [PULL 00/42] Migration patches for 2025-01-29 Fabiano Rosas
2025-01-29 16:00 ` [PULL 01/42] migration: fix -Werror=maybe-uninitialized Fabiano Rosas
2025-01-29 16:00 ` [PULL 02/42] backends/hostmem-shm: factor out allocation of "anonymous shared memory with an fd" Fabiano Rosas
2025-01-29 16:00 ` [PULL 03/42] physmem: fix qemu_ram_alloc_from_fd size calculation Fabiano Rosas
2025-01-29 16:00 ` [PULL 04/42] physmem: qemu_ram_alloc_from_fd extensions Fabiano Rosas
2025-01-29 16:00 ` [PULL 05/42] physmem: fd-based shared memory Fabiano Rosas
2025-01-29 16:00 ` [PULL 06/42] memory: add RAM_PRIVATE Fabiano Rosas
2025-01-29 16:00 ` [PULL 07/42] machine: aux-ram-share option Fabiano Rosas
2025-01-29 16:00 ` [PULL 08/42] migration: cpr-state Fabiano Rosas
2025-01-29 16:00 ` [PULL 09/42] physmem: preserve ram blocks for cpr Fabiano Rosas
2025-01-29 16:00 ` [PULL 10/42] hostmem-memfd: preserve " Fabiano Rosas
2025-01-29 16:00 ` [PULL 11/42] hostmem-shm: " Fabiano Rosas
2025-01-29 16:00 ` [PULL 12/42] migration: enhance migrate_uri_parse Fabiano Rosas
2025-01-29 16:00 ` [PULL 13/42] migration: incoming channel Fabiano Rosas
2025-01-29 16:00 ` [PULL 14/42] migration: SCM_RIGHTS for QEMUFile Fabiano Rosas
2025-01-29 16:00 ` [PULL 15/42] migration: VMSTATE_FD Fabiano Rosas
2025-01-29 16:00 ` [PULL 16/42] migration: cpr-transfer save and load Fabiano Rosas
2025-01-29 16:00 ` [PULL 17/42] migration: cpr-transfer mode Fabiano Rosas
2025-02-04 13:40 ` Peter Maydell
2025-02-04 16:26 ` Peter Xu
2025-02-04 16:52 ` Steven Sistare [this message]
2025-01-29 16:00 ` [PULL 18/42] migration-test: memory_backend Fabiano Rosas
2025-01-29 16:00 ` [PULL 19/42] tests/qtest: optimize migrate_set_ports Fabiano Rosas
2025-01-29 16:00 ` [PULL 20/42] tests/qtest: defer connection Fabiano Rosas
2025-01-29 16:00 ` [PULL 21/42] migration-test: " Fabiano Rosas
2025-01-29 16:00 ` [PULL 22/42] tests/qtest: enhance migration channels Fabiano Rosas
2025-01-29 16:00 ` [PULL 23/42] tests/qtest: assert qmp connected Fabiano Rosas
2025-01-29 16:00 ` [PULL 24/42] migration-test: cpr-transfer Fabiano Rosas
2025-01-29 16:00 ` [PULL 25/42] migration: cpr-transfer documentation Fabiano Rosas
2025-01-29 16:00 ` [PULL 26/42] migration: Remove postcopy implications in should_send_vmdesc() Fabiano Rosas
2025-01-29 16:00 ` [PULL 27/42] migration: Do not construct JSON description if suppressed Fabiano Rosas
2025-01-29 16:00 ` [PULL 28/42] migration: Optimize postcopy on downtime by avoiding JSON writer Fabiano Rosas
2025-01-29 16:00 ` [PULL 29/42] migration: Avoid two src-downtime-end tracepoints for postcopy Fabiano Rosas
2025-01-29 16:00 ` [PULL 30/42] migration: Drop inactivate_disk param in qemu_savevm_state_complete* Fabiano Rosas
2025-01-29 16:00 ` [PULL 31/42] migration: Synchronize all CPU states only for non-iterable dump Fabiano Rosas
2025-01-29 16:00 ` [PULL 32/42] migration: Adjust postcopy bandwidth during switchover Fabiano Rosas
2025-01-29 16:00 ` [PULL 33/42] migration: Adjust locking in migration_maybe_pause() Fabiano Rosas
2025-01-29 16:00 ` [PULL 34/42] migration: Drop cached migration state " Fabiano Rosas
2025-01-29 16:00 ` [PULL 35/42] migration: Take BQL slightly longer in postcopy_start() Fabiano Rosas
2025-01-29 16:00 ` [PULL 36/42] migration: Notify COMPLETE once for postcopy Fabiano Rosas
2025-01-29 16:00 ` [PULL 37/42] migration: Unwrap qemu_savevm_state_complete_precopy() in postcopy Fabiano Rosas
2025-01-29 16:00 ` [PULL 38/42] migration: Cleanup qemu_savevm_state_complete_precopy() Fabiano Rosas
2025-01-29 16:00 ` [PULL 39/42] migration: Always set DEVICE state Fabiano Rosas
2025-01-29 16:00 ` [PULL 40/42] migration: Merge precopy/postcopy on switchover start Fabiano Rosas
2025-01-29 16:00 ` [PULL 41/42] migration: Trivial cleanup on JSON writer of vmstate_save() Fabiano Rosas
2025-01-29 16:00 ` [PULL 42/42] migration: refactor ram_save_target_page functions Fabiano Rosas
2025-02-01 3:03 ` [PULL 00/42] Migration patches for 2025-01-29 Stefan Hajnoczi
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=27c6ee8f-d4dd-4ee6-bda8-e9b21289d7d7@oracle.com \
--to=steven.sistare@oracle.com \
--cc=armbru@redhat.com \
--cc=farosas@suse.de \
--cc=peter.maydell@linaro.org \
--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 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).