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 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.