On Thu, 10 Aug 2023 10:59:26 -0500 Bjorn Helgaas <helgaas@xxxxxxxxxx> wrote: > On Thu, Aug 03, 2023 at 11:12:32AM -0600, Alex Williamson wrote: > > Unlike default access to config space through sysfs, the vpd read and > > write function don't actively manage the runtime power management state > > of the device during access. Since commit 7ab5e10eda02 ("vfio/pci: Move > > the unused device into low power state with runtime PM"), the vfio-pci > > driver will use runtime power management and release unused devices to > > make use of low power states. Attempting to access VPD information in > > this low power state can result in incorrect information or kernel > > crashes depending on the system behavior. > > > > Wrap the vpd read/write bin attribute handlers in runtime PM and take > > into account the potential quirk to select the correct device to wake. > > > > Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx> > > --- > > drivers/pci/vpd.c | 34 ++++++++++++++++++++++++++++++++-- > > 1 file changed, 32 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c > > index a4fc4d0690fe..81217dd4789f 100644 > > --- a/drivers/pci/vpd.c > > +++ b/drivers/pci/vpd.c > > @@ -275,8 +275,23 @@ static ssize_t vpd_read(struct file *filp, struct kobject *kobj, > > size_t count) > > { > > struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj)); > > + struct pci_dev *vpd_dev = dev; > > + ssize_t ret; > > + > > + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) { > > + vpd_dev = pci_get_func0_dev(dev); > > + if (!vpd_dev) > > + return -ENODEV; > > + } > > + > > + pci_config_pm_runtime_get(vpd_dev); > > + ret = pci_read_vpd(vpd_dev, off, count, buf); > > + pci_config_pm_runtime_put(vpd_dev); > > + > > + if (dev != vpd_dev) > > + pci_dev_put(vpd_dev); > > I first thought this would leak a reference if dev was func0 and had > PCI_DEV_FLAGS_VPD_REF_F0 set, because in that case vpd_dev would be > the same as dev. > > But I think that case can't happen because quirk_f0_vpd_link() does > nothing for func0 devices, so PCI_DEV_FLAGS_VPD_REF_F0 should never be > set for func0. But it seems like this might be easier to analyze as: > > if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) > pci_dev_put(vpd_dev); > > Or am I missing something? Nope, your analysis is correct, it doesn't make any sense to have a flag on func0 redirecting VPD access to func0 so vpd_dev can only be different on non-zero functions. The alternative test is equally valid so if you think it's more intuitive, let's use it. Thanks, Alex