From: no-reply@sashiko.virtuozzo.com
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
svt-core@virtuozzo.com
Cc: andrey.drobyshev@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v3 18/28] kvm: tolerate ioctls after kvm_close()
Date: Fri, 16 Oct 2026 15:44:16 +0000 [thread overview]
Message-ID: <010701a14562a9c8-9cf64716-e63e-4c1a-83f5-e3405985689d-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261016-vfio_v1-v3-18-47487cb5a8e5@virtuozzo.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] kvm: late INTx via kvm_set_irq() still crashes after kvm_close()
- [Medium] kvm: kvm_set_ioeventfd_mmio() returns stale -errno on new -ENODEV path
- [Low] kvm: unsynchronized closed-state check in ioctl wrappers races with kvm_close()
--
commit 6d5d5f6faa5b401fc25d81071e7ee69ce2c8465b
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
kvm: tolerate ioctls after kvm_close()
This patch makes kvm_ioctl(), kvm_vm_ioctl() and kvm_vcpu_ioctl() return
-ENODEV once kvm_close() has run. It also stops kvm_send_msi() from
printing the "MSI lost" warning for that case. The goal is to stop the
retired cpr-transfer source from crashing on late interrupts.
> kvm: tolerate ioctls after kvm_close()
> Make the ioctl wrappers honour the closed state instead of assuming a
> live KVMState: kvm_ioctl(), kvm_vm_ioctl() and kvm_vcpu_ioctl() return
> -ENODEV when kvm_close() has already been called, so any late interrupt
> or query on the retired source fails gracefully.
The commit message says any late interrupt fails gracefully. Is that
accurate? Only the MSI path through kvm_send_msi() is fixed. The
findings below describe other late-interrupt paths that still crash.
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
[ ... ]
> @@ -3389,6 +3394,11 @@ int kvm_vm_ioctl(KVMState *s, unsigned long type, ...)
> arg = va_arg(ap, void *);
> va_end(ap);
>
> + /* kvm_close() has been called: there is no VM to talk to any more */
> + if (!s || s->vmfd == -1) {
> + return -ENODEV;
> + }
> +
> trace_kvm_vm_ioctl(type, arg);
> accel_ioctl_begin();
> ret = ioctl(s->vmfd, type, arg);
[Severity: Medium]
Can a late INTx or GSI line interrupt still crash after kvm_close()?
kvm_close() sets kvm_state to NULL, but kvm_kernel_irqchip and
kvm_async_interrupts_allowed stay true. A late line interrupt then takes
this path:
kvm_ioapic_set_irq() / kvm_pic_set_irq()
kvm_set_irq(kvm_state = NULL, ...)
kvm_vm_ioctl(s, s->irq_set_ioctl, &event)
The argument s->irq_set_ioctl is evaluated in kvm_set_irq() before
kvm_vm_ioctl() runs. With s == NULL it faults there, so the new "!s"
check is never reached.
If s were non-NULL but closed, the new -ENODEV would make this code take
the error branch:
ret = kvm_vm_ioctl(s, s->irq_set_ioctl, &event);
if (ret < 0) {
perror("kvm_set_irq");
abort();
}
That would turn the late interrupt into an abort() instead.
kvm_irqchip_commit_routes() has the same problem:
ret = kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
assert(ret == 0);
The new -ENODEV would trip the assert.
I compared the end of the series against this patch for accel/kvm and
hw/i386/kvm. The only change there is the coalesced MMIO ring handling in
kvm_close(). Nothing guards kvm_set_irq(), the IOAPIC and PIC callbacks,
or the irqchip route helpers. Should those callers be taught about the
closed state as well?
[Severity: Low]
Is the new closed-state check safe against a concurrent kvm_close()?
The check is a plain, unlocked load of s->vmfd:
if (!s || s->vmfd == -1) {
return -ENODEV;
}
...
accel_ioctl_begin();
ret = ioctl(s->vmfd, type, arg);
It is not atomic with the later use of s->vmfd. accel_ioctl_begin()
returns immediately when the BQL is held and only takes the lockcnt for
non-BQL callers. kvm_close() does not call kvm_ioctl_inhibit_begin().
kvm_close() also closes the fd before it stores -1:
close(kvm_state->vmfd);
kvm_state->vmfd = -1;
Can a non-BQL thread pass the -1 check and then call ioctl() on a closed
or recycled descriptor? The likely result is a spurious -EBADF. A
recycled fd number could refer to another file.
I did not find a specific non-BQL caller that runs during kvm_close().
The wrappers just don't exclude one. The BQL-held callers and the vCPU
threads (stopped by cpu_remove_sync()) are covered.
The same applies to kvm_vcpu_ioctl() and cpu->kvm_fd:
> @@ -3409,6 +3419,11 @@ int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...)
> arg = va_arg(ap, void *);
> va_end(ap);
>
> + /* kvm_close() has been called: the vCPU fds are gone */
> + if (cpu->kvm_fd == -1) {
> + return -ENODEV;
> + }
> +
> trace_kvm_vcpu_ioctl(cpu->cpu_index, type, arg);
> accel_cpu_ioctl_begin(cpu);
> ret = ioctl(cpu->kvm_fd, type, arg);
Similarly, kvm_send_msi() reads the global kvm_state without any
synchronization against kvm_close() setting it to NULL. The KVMState
object itself is never freed, so only the fd value is racy.
[Severity: Medium]
Can the new early return in kvm_vm_ioctl() give kvm_set_ioeventfd_mmio()
a stale errno?
kvm_vm_ioctl() already returns a negative errno value. The new -ENODEV
return never calls ioctl(), so errno is not set. kvm_set_ioeventfd_mmio()
ignores the returned value and re-reads errno:
ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd);
if (ret < 0) {
return -errno;
}
After kvm_close() this returns whatever errno an earlier failed syscall
left behind. If errno is 0, the failure is reported as success. If errno
is non-zero, the caller reports a misleading error.
The callers kvm_mem_ioeventfd_add() and kvm_mem_ioeventfd_del() abort()
on any negative return:
r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space,
data, true, int128_get64(section->size),
match_data);
if (r < 0) {
fprintf(stderr, "%s: error adding ioeventfd: %s (%d)\n",
__func__, strerror(-r), -r);
abort();
}
Should kvm_set_ioeventfd_mmio() return ret instead of -errno? The
sibling kvm_set_ioeventfd_pio() already returns the kvm_vm_ioctl() value
directly.
I did not confirm that kvm_enabled() stays true after kvm_close(). I also
did not find a path that deletes an ioeventfd after kvm_close(), such as
device unrealize during qemu_cleanup. So I'm not sure this can be
triggered today.
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261016-vfio_v1-v3-0-47487cb5a8e5@virtuozzo.com?part=18
next prev parent reply other threads:[~2026-10-16 15:44 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 15:25 [PATCH QEMU HCI-8.1 v3 00/28] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-10-16 15:25 ` [PATCH QEMU HCI-8.1 v3 01/28] VZ: migration/cpr-exec: fix Error leak in preserve_ram() Andrey Drobyshev
2026-10-16 15:28 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 02/28] migration/cpr-exec: restore RAM write access if exec fails Andrey Drobyshev
2026-10-16 15:28 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 03/28] vfio/region: create BAR dma-bufs with O_CLOEXEC Andrey Drobyshev
2026-10-16 15:30 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 04/28] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-10-16 15:29 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 05/28] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-10-16 15:30 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 06/28] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-10-16 15:30 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 07/28] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-10-16 15:31 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 08/28] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-10-16 15:32 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 09/28] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-10-16 15:31 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 10/28] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-10-16 15:33 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 11/28] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-10-16 15:32 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 12/28] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-10-16 15:35 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 13/28] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-10-16 15:38 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 14/28] migration: yank: Move register instance earlier Andrey Drobyshev
2026-10-16 15:41 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 15/28] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-10-16 15:39 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 16/28] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-10-16 15:40 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 17/28] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-10-16 15:44 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 18/28] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-10-16 15:44 ` no-reply [this message]
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 19/28] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-10-16 15:46 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 20/28] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-10-16 15:46 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 21/28] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-10-16 15:55 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 22/28] vfio/listener: skip dirty page tracking " Andrey Drobyshev
2026-10-16 15:50 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 23/28] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-10-16 15:52 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 24/28] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-10-16 15:55 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 25/28] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-10-16 15:58 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 26/28] VZ: migration/cpr-exec: don't exec if a vhost-net device can't be released Andrey Drobyshev
2026-10-16 15:56 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 27/28] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-10-16 16:02 ` no-reply
2026-10-16 15:26 ` [PATCH QEMU HCI-8.1 v3 28/28] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-10-16 15:59 ` no-reply
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=010701a14562a9c8-9cf64716-e63e-4c1a-83f5-e3405985689d-000000@eu-central-1.amazonses.com \
--to=no-reply@sashiko.virtuozzo.com \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=svt-core@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