From: Vipin Sharma <vipinsh@google.com>
To: kexec@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
linux-pci@vger.kernel.org
Cc: ajayachandra@nvidia.com, alex@shazbot.org, amastro@fb.com,
ankita@nvidia.com, apopple@nvidia.com, bhelgaas@google.com,
chrisl@kernel.org, christian.koenig@amd.com, corbet@lwn.net,
dmatlack@google.com, graf@amazon.com,
jacob.pan@linux.microsoft.com, jgg@nvidia.com, jgg@ziepe.ca,
jrhilke@google.com, julianr@linux.ibm.com, kees@kernel.org,
kevin.tian@intel.com, leon@kernel.org, leonro@nvidia.com,
lukas@wunner.de, mattev@meta.com, michal.winiarski@intel.com,
parav@nvidia.com, pasha.tatashin@soleen.com, praan@google.com,
pratyush@kernel.org, rananta@google.com, rdunlap@infradead.org,
rientjes@google.com, rodrigo.vivi@intel.com, rppt@kernel.org,
saeedm@nvidia.com, schnelle@linux.ibm.com,
skhan@linuxfoundation.org, skhawaja@google.com,
vipinsh@google.com, vivek.kasireddy@intel.com, witu@nvidia.com,
yanjun.zhu@linux.dev, yi.l.liu@intel.com
Subject: [PATCH v6 13/27] vfio/pci: Protect incoming preserved devices until they finish Live Update
Date: Mon, 2 Nov 2026 07:36:42 -0800 [thread overview]
Message-ID: <20261102153656.1431701-14-vipinsh@google.com> (raw)
In-Reply-To: <20261102153656.1431701-1-vipinsh@google.com>
Protect incoming preserved devices that were kept running across kexec
from being disturbed before userspace either claims them or finishes the
Live Update session:
* Runtime PM idle D3: In vfio_pci_init_dev(), when
pci_liveupdate_is_incoming(pdev) is true, latch
vdev->disable_idle_d3 = true and vdev->liveupdate_kept_running = true.
Without this, vfio_pci_core_register_device() drops the runtime PM
reference and allows the PCI runtime PM core to transition an idle
incoming device into D3hot, stopping bus mastering and potentially
triggering an internal reset on NoSoftRst- devices.
* Non-noiommu boot fallback: In vfio_pci_core_register_device(), after
vfio_register_group_dev() determines whether the device is in noiommu
mode, if an incoming kept-running device is not in noiommu mode in
this kernel, log a pci_warn(), clear PCI_COMMAND_MASTER immediately to
stop untranslated DMA, and record liveupdate_stopped_early so
finish() resets it without printing a duplicate warning.
* Bus/slot reset guards: Refuse vfio_pci_dev_set_needs_reset() and
vfio_pci_dev_set_hot_reset() (-EBUSY) while any device in the dev_set
has liveupdate_kept_running set, preventing another device in the same
dev_set from resetting an unclaimed kept-running device. When an
unclaimed device finishes Live Update and no device in its dev_set is
open, invoke vfio_pci_dev_set_try_reset() after clearing
liveupdate_kept_running so devices without function-level reset still
receive a bus/slot reset.
* Unbind before finish: In vfio_pci_core_unregister_device(), if a
still-unclaimed incoming device is unbound from vfio-pci before the
session finishes (or if a concurrent finish() deferred its function
reset via liveupdate_reset_pending), clear bus mastering, reset the
function and restore config state via
vfio_pci_core_liveupdate_reset_locked() under the device lock already
held by remove(), and call pci_liveupdate_finish().
Signed-off-by: Vipin Sharma <vipinsh@google.com>
---
drivers/vfio/pci/vfio_pci.c | 1 +
drivers/vfio/pci/vfio_pci_core.c | 19 +++++++-
drivers/vfio/pci/vfio_pci_liveupdate.c | 16 +++++--
drivers/vfio/pci/vfio_pci_priv.h | 62 ++++++++++++++++++++++++--
include/linux/vfio_pci_core.h | 3 +-
5 files changed, 91 insertions(+), 10 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 9d48b250a5e8..d01b5cc9d4d2 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -139,6 +139,7 @@ static int vfio_pci_init_dev(struct vfio_device *core_vdev)
*/
vdev->nointxmask = nointxmask;
vdev->disable_idle_d3 = disable_idle_d3;
+ vfio_pci_liveupdate_init_dev(vdev);
#ifdef CONFIG_VFIO_PCI_VGA
vdev->disable_vga = disable_vga;
#endif
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 60ada3bbb6ff..828d620cf836 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -768,6 +768,15 @@ bool vfio_pci_core_liveupdate_reset(struct vfio_pci_core_device *vdev,
vdev->reset_works = reset_works;
vfio_pci_core_try_reset(vdev);
+ /*
+ * Like vfio_pci_core_disable(), try a bus or slot reset for the devices
+ * in the set that still need one, e.g. this device if it has no usable
+ * function reset, or others whose reset was deferred while this device
+ * was kept running. This device is not open, so none in the set may be.
+ */
+ if (!vfio_device_set_open_count(vdev->vdev.dev_set))
+ vfio_pci_dev_set_try_reset(vdev->vdev.dev_set);
+
return !vdev->needs_reset;
}
EXPORT_SYMBOL_GPL(vfio_pci_core_liveupdate_reset);
@@ -2399,6 +2408,8 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
if (ret)
goto out_power;
+ vfio_pci_liveupdate_check_noiommu(vdev);
+
vfio_pci_core_debugfs_init(vdev);
return 0;
@@ -2642,7 +2653,8 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
list_for_each_entry(vdev, &dev_set->device_list, vdev.dev_set_list) {
bool owned;
- if (vfio_pci_dev_is_frozen(vdev)) {
+ if (vfio_pci_dev_is_frozen(vdev) ||
+ vfio_pci_dev_is_kept_running(vdev)) {
ret = -EBUSY;
break;
}
@@ -2744,8 +2756,11 @@ static bool vfio_pci_dev_set_needs_reset(struct vfio_device_set *dev_set)
if (vfio_device_set_open_count(dev_set) > 1)
return false;
- list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list)
+ list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list) {
+ if (vfio_pci_dev_is_kept_running(cur))
+ return false;
needs_reset |= cur->needs_reset;
+ }
return needs_reset;
}
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 64810010f983..ad757acac400 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -457,7 +457,7 @@ vfio_pci_liveupdate_attach_incoming(struct vfio_pci_core_device *vdev,
{
guard(mutex)(&vdev->vdev.dev_set->lock);
- if (vdev->liveupdate_incoming || vdev->liveupdate_claimed ||
+ if (vdev->liveupdate_incoming || !vdev->liveupdate_kept_running ||
!pci_liveupdate_is_incoming(vdev->pdev))
return -EBUSY;
@@ -558,8 +558,7 @@ static void vfio_pci_liveupdate_finish_vdev(struct vfio_pci_core_device *vdev,
bool was_reset;
scoped_guard(mutex, &vdev->vdev.dev_set->lock) {
- if (!vdev->liveupdate_claimed &&
- pci_liveupdate_is_incoming(pdev)) {
+ if (vdev->liveupdate_kept_running) {
if (vdev->liveupdate_incoming) {
saved_state = vdev->liveupdate_incoming->saved_state;
vdev->liveupdate_incoming->saved_state = NULL;
@@ -572,6 +571,17 @@ static void vfio_pci_liveupdate_finish_vdev(struct vfio_pci_core_device *vdev,
saved_state = NULL;
}
+ /*
+ * The device is stopped below, so stop shielding it from
+ * the dev_set resets, including the fallback done by
+ * vfio_pci_core_liveupdate_reset().
+ */
+ vdev->liveupdate_kept_running = false;
+
+ /* A device stopped early was logged when it was stopped. */
+ if (vdev->liveupdate_stopped_early)
+ reason = NULL;
+
/*
* An unbind of the device waits for the reference held
* by finish() with the device lock held, so the reset
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index d8670dc51bb4..39ea26402312 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -169,6 +169,40 @@ static inline bool vfio_pci_dev_is_frozen(struct vfio_pci_core_device *vdev)
return smp_load_acquire(&vdev->liveupdate_frozen);
}
+static inline bool vfio_pci_dev_is_kept_running(struct vfio_pci_core_device *vdev)
+{
+ return vdev->liveupdate_kept_running;
+}
+
+static inline void vfio_pci_liveupdate_init_dev(struct vfio_pci_core_device *vdev)
+{
+ struct pci_dev *pdev = to_pci_dev(vdev->vdev.dev);
+
+ if (pci_liveupdate_is_incoming(pdev)) {
+ vdev->disable_idle_d3 = true;
+ vdev->liveupdate_kept_running = true;
+ }
+}
+
+/*
+ * Called by probe once the device is registered, with the device lock held.
+ * retrieve() and finish() look the device up with that lock held, see
+ * vfio_pci_liveupdate_find_probed(), so they see the result of this check.
+ */
+static inline void
+vfio_pci_liveupdate_check_noiommu(struct vfio_pci_core_device *vdev)
+{
+ guard(mutex)(&vdev->vdev.dev_set->lock);
+
+ if (vdev->liveupdate_kept_running &&
+ !vfio_device_is_noiommu(&vdev->vdev)) {
+ pci_warn(vdev->pdev,
+ "Stopping device kept running across Live Update: not in noiommu mode\n");
+ pci_clear_master(vdev->pdev);
+ vdev->liveupdate_stopped_early = true;
+ }
+}
+
static inline void
vfio_pci_liveupdate_free_incoming(struct vfio_pci_core_device *vdev)
{
@@ -196,7 +230,7 @@ vfio_pci_liveupdate_claim_incoming(struct vfio_pci_core_device *vdev)
return;
vfio_pci_liveupdate_free_incoming(vdev);
- vdev->liveupdate_claimed = true;
+ vdev->liveupdate_kept_running = false;
}
static inline void
@@ -206,11 +240,17 @@ vfio_pci_liveupdate_unregister_dev(struct vfio_pci_core_device *vdev)
scoped_guard(mutex, &vdev->vdev.dev_set->lock) {
/*
- * Complete a reset that finish() could not do, see
- * vfio_pci_liveupdate_finish_vdev().
+ * Reset a device unbound before finish(), or whose reset
+ * finish() could not do, see vfio_pci_liveupdate_finish_vdev().
*/
- if (vdev->liveupdate_reset_pending) {
+ if (vdev->liveupdate_kept_running ||
+ vdev->liveupdate_reset_pending) {
+ if (vdev->liveupdate_kept_running &&
+ !vdev->liveupdate_stopped_early)
+ pci_warn(pdev,
+ "Resetting device not taken over after Live Update (vfio-pci unbound)\n");
vfio_pci_core_liveupdate_reset_locked(vdev);
+ vdev->liveupdate_kept_running = false;
vdev->liveupdate_reset_pending = false;
}
vfio_pci_liveupdate_free_incoming(vdev);
@@ -234,6 +274,20 @@ static inline bool vfio_pci_dev_is_frozen(struct vfio_pci_core_device *vdev)
return false;
}
+static inline bool vfio_pci_dev_is_kept_running(struct vfio_pci_core_device *vdev)
+{
+ return false;
+}
+
+static inline void vfio_pci_liveupdate_init_dev(struct vfio_pci_core_device *vdev)
+{
+}
+
+static inline void
+vfio_pci_liveupdate_check_noiommu(struct vfio_pci_core_device *vdev)
+{
+}
+
static inline void
vfio_pci_liveupdate_free_incoming(struct vfio_pci_core_device *vdev)
{
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index f5c279d0df1e..9bdbc8099bda 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -152,7 +152,8 @@ struct vfio_pci_core_device {
#ifdef CONFIG_VFIO_PCI_LIVEUPDATE
bool liveupdate_frozen;
bool liveupdate_intx_disabled;
- bool liveupdate_claimed;
+ bool liveupdate_kept_running;
+ bool liveupdate_stopped_early;
bool liveupdate_reset_pending;
struct vfio_pci_liveupdate_incoming *liveupdate_incoming;
#endif
--
2.56.0.317.g454f8302e1-goog
next prev parent reply other threads:[~2026-11-02 15:37 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 15:36 [PATCH v6 00/27] VFIO PCI Live Update (noiommu mode) Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 01/27] vfio/pci: Factor out the reset logic in VFIO PCI device close path Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 02/27] vfio: Export various helpers from VFIO Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 03/27] liveupdate: Export symbols needed by modules Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 04/27] vfio/pci: Register a file handler with Live Update Orchestrator Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 05/27] PCI: liveupdate: Add helpers to preserve struct pci_saved_state Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 06/27] vfio: Add helpers to identify device files that can be preserved Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 07/27] vfio/pci: Preserve vfio-pci device files across Live Update Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 08/27] vfio: Introduce vfio_find_device() helper Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 09/27] vfio: Refactor vfio_device_fops_cdev_open() Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 10/27] vfio: Add API to open cdev device for Live Update restore Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 11/27] vfio/pci: Retrieve preserved device files after Live Update Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 12/27] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD Vipin Sharma
2026-11-02 15:36 ` Vipin Sharma [this message]
2026-11-02 15:36 ` [PATCH v6 14/27] vfio/pci: Take over preserved devices without resetting them Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 15/27] docs: liveupdate: Add documentation for VFIO PCI Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 16/27] vfio: selftests: Build liveupdate library in VFIO selftests Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 17/27] vfio: selftests: Add vfio_pci_liveupdate_uapi_test Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 18/27] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 19/27] vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 20/27] vfio: selftests: Add iommufd noiommu mode Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 21/27] vfio: selftests: Add helpers to map DMA memory at IOVA == PA in " Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 22/27] vfio: selftests: Add helpers for Live Update DMA memory and sysfs state Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 23/27] vfio: selftests: Add an attach() driver op Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 24/27] vfio: selftests: Test preserving noiommu devices in vfio_pci_liveupdate_uapi_test Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 25/27] vfio: selftests: Add vfio_pci_liveupdate_kexec_test Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 26/27] vfio: selftests: Verify that opening VFIO device fails during Live Update Vipin Sharma
2026-11-02 15:36 ` [PATCH v6 27/27] vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test Vipin Sharma
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=20261102153656.1431701-14-vipinsh@google.com \
--to=vipinsh@google.com \
--cc=ajayachandra@nvidia.com \
--cc=alex@shazbot.org \
--cc=amastro@fb.com \
--cc=ankita@nvidia.com \
--cc=apopple@nvidia.com \
--cc=bhelgaas@google.com \
--cc=chrisl@kernel.org \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dmatlack@google.com \
--cc=graf@amazon.com \
--cc=jacob.pan@linux.microsoft.com \
--cc=jgg@nvidia.com \
--cc=jgg@ziepe.ca \
--cc=jrhilke@google.com \
--cc=julianr@linux.ibm.com \
--cc=kees@kernel.org \
--cc=kevin.tian@intel.com \
--cc=kexec@lists.infradead.org \
--cc=kvm@vger.kernel.org \
--cc=leon@kernel.org \
--cc=leonro@nvidia.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-pci@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=mattev@meta.com \
--cc=michal.winiarski@intel.com \
--cc=parav@nvidia.com \
--cc=pasha.tatashin@soleen.com \
--cc=praan@google.com \
--cc=pratyush@kernel.org \
--cc=rananta@google.com \
--cc=rdunlap@infradead.org \
--cc=rientjes@google.com \
--cc=rodrigo.vivi@intel.com \
--cc=rppt@kernel.org \
--cc=saeedm@nvidia.com \
--cc=schnelle@linux.ibm.com \
--cc=skhan@linuxfoundation.org \
--cc=skhawaja@google.com \
--cc=vivek.kasireddy@intel.com \
--cc=witu@nvidia.com \
--cc=yanjun.zhu@linux.dev \
--cc=yi.l.liu@intel.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
all inboxes | Powered by JetHome®