From: Oleksandr Andrushchenko <oleksandr_andrushche...@epam.com>

modify_bars checks if the mapping of the BAR memory has already been
done when mapping other device's BARs or, while unmapping, are still
in use by other devices.

With the existing locking scheme it is possible that there are other
devices trying to do the same in parallel with us, but on other CPUs
as we only hold a read lock without acquiring _pcidevs_lock recursive
lock.

To prevent that upgrade the read lock to normal pcidevs_lock during
BAR overlapping check.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushche...@epam.com>
---
 xen/drivers/vpci/header.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index 75e972740106..c80a8bb5e3e0 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -281,7 +281,11 @@ static int modify_bars(const struct pci_dev *pdev, 
uint16_t cmd, bool rom_only)
     /*
      * Check for overlaps with other BARs. Note that only BARs that are
      * currently mapped (enabled) are checked for overlaps.
+     * We are holding pcidevs_read_lock here, but we need to access
+     * different devices at a time. So, upgrade our current read lock to normal
+     * pcidevs_lock.
      */
+    pcidevs_lock();
     for_each_pdev ( pdev->domain, tmp )
     {
         if ( tmp == pdev )
@@ -321,10 +325,12 @@ static int modify_bars(const struct pci_dev *pdev, 
uint16_t cmd, bool rom_only)
                 printk(XENLOG_G_WARNING "Failed to remove [%lx, %lx]: %d\n",
                        start, end, rc);
                 rangeset_destroy(mem);
+                pcidevs_unlock();
                 return rc;
             }
         }
     }
+    pcidevs_unlock();
 
     ASSERT(dev);
 
-- 
2.25.1


Reply via email to