the task (Benjamin Block) - Added Reviewed-by and Tested-by from Benjamin Block (IBM) Changes in v3: - Rebased on linux-next (next-20260225) - Added Tested-by from Dragos Tatulea (NVIDIA) - No code changes from v2 Changes in v2: - Renamed from pci_lock_rescan_remove_nested() to pci_lock_rescan_remove_reentrant() to avoid confusion with mutex_lock_nested() lockdep annotations (Benjamin Block) - Added pci_unlock_rescan_remove_reentrant(const bool locked) helper to avoid open-coding conditional unlock at each call site (Benjamin Block) - Moved declarations from drivers/pci/pci.h to include/linux/pci.h alongside existing lock/unlock declarations (Benjamin Block) - Simplified callers: removed negation of return value and manual conditional unlock in favor of the paired lock/unlock helpers drivers/pci/iov.c | 7 +++++++ drivers/pci/probe.c | 19 +++++++++++++++++++ include/linux/pci.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 91ac4e37ecb9c..adbe4ecc587c9 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -629,19 +629,23 @@ static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) { unsigned int i; int rc; + bool locked; if (dev->no_vf_scan) return 0; + locked = pci_lock_rescan_remove_reentrant(); for (i = 0; i < num_vfs; i++) { rc = pci_iov_add_virtfn(dev, i); if (rc) goto failed; } + pci_unlock_rescan_remove_reentrant(locked); return 0; failed: while (i--) pci_iov_remove_virtfn(dev, i); + pci_unlock_rescan_remove_reentrant(locked); return rc; } @@ -764,10 +768,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) static void sriov_del_vfs(struct pci_dev *dev) { struct pci_sriov *iov = dev->sriov; + bool locked; int i; + locked = pci_lock_rescan_remove_reentrant(); for (i = 0; i < iov->num_VFs; i++) pci_iov_remove_virtfn(dev, i); + pci_unlock_rescan_remove_reentrant(locked); } static void sriov_disable(struct pci_dev *dev) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index bccc7a4bdd794..c7f672eac0698 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -3509,19 +3509,38 @@ EXPORT_SYMBOL_GPL(pci_rescan_bus); * routines should always be executed under this mutex. */ DEFINE_MUTEX(pci_rescan_remove_lock); +static const struct task_struct *pci_rescan_remove_owner; void pci_lock_rescan_remove(void) { mutex_lock(&pci_rescan_remove_lock); + pci_rescan_remove_owner = current; } EXPORT_SYMBOL_GPL(pci_lock_rescan_remove); void pci_unlock_rescan_remove(void) { + pci_rescan_remove_owner = NULL; mutex_unlock(&pci_rescan_remove_lock); } EXPORT_SYMBOL_GPL(pci_unlock_rescan_remove); +bool pci_lock_rescan_remove_reentrant(void) +{ + if (pci_rescan_remove_owner == current) + return false; + pci_lock_rescan_remove(); + return true; +} +EXPORT_SYMBOL_GPL(pci_lock_rescan_remove_reentrant); + +void pci_unlock_rescan_remove_reentrant(const bool locked) +{ + if (locked) + pci_unlock_rescan_remove(); +} +EXPORT_SYMBOL_GPL(pci_unlock_rescan_remove_reentrant); + static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 1c270f1d51230..080950f0bab33 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1535,6 +1535,8 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev); unsigned int pci_rescan_bus(struct pci_bus *bus); void pci_lock_rescan_remove(void); void pci_unlock_rescan_remove(void); +bool pci_lock_rescan_remove_reentrant(void); +void pci_unlock_rescan_remove_reentrant(const bool locked); /* Vital Product Data routines */ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); -- 2.53.0[PATCH v4 1/1] PCI/IOV: Add reentrant locking in sriov_add_vfs/sriov_del_vfs for complete serialization"Ionut Nechita (Wind River)" undefinedbhelgaas@google.com undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined