Patch "PCI/PM: Drain runtime-idle callbacks before driver removal" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    PCI/PM: Drain runtime-idle callbacks before driver removal

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     pci-pm-drain-runtime-idle-callbacks-before-driver-re.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 878622ad09e8feba6709de91cefc2a9ddab571ef
Author: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Date:   Tue Mar 5 11:45:38 2024 +0100

    PCI/PM: Drain runtime-idle callbacks before driver removal
    
    [ Upstream commit 9d5286d4e7f68beab450deddbb6a32edd5ecf4bf ]
    
    A race condition between the .runtime_idle() callback and the .remove()
    callback in the rtsx_pcr PCI driver leads to a kernel crash due to an
    unhandled page fault [1].
    
    The problem is that rtsx_pci_runtime_idle() is not expected to be running
    after pm_runtime_get_sync() has been called, but the latter doesn't really
    guarantee that.  It only guarantees that the suspend and resume callbacks
    will not be running when it returns.
    
    However, if a .runtime_idle() callback is already running when
    pm_runtime_get_sync() is called, the latter will notice that the runtime PM
    status of the device is RPM_ACTIVE and it will return right away without
    waiting for the former to complete.  In fact, it cannot wait for
    .runtime_idle() to complete because it may be called from that callback (it
    arguably does not make much sense to do that, but it is not strictly
    prohibited).
    
    Thus in general, whoever is providing a .runtime_idle() callback needs
    to protect it from running in parallel with whatever code runs after
    pm_runtime_get_sync().  [Note that .runtime_idle() will not start after
    pm_runtime_get_sync() has returned, but it may continue running then if it
    has started earlier.]
    
    One way to address that race condition is to call pm_runtime_barrier()
    after pm_runtime_get_sync() (not before it, because a nonzero value of the
    runtime PM usage counter is necessary to prevent runtime PM callbacks from
    being invoked) to wait for the .runtime_idle() callback to complete should
    it be running at that point.  A suitable place for doing that is in
    pci_device_remove() which calls pm_runtime_get_sync() before removing the
    driver, so it may as well call pm_runtime_barrier() subsequently, which
    will prevent the race in question from occurring, not just in the rtsx_pcr
    driver, but in any PCI drivers providing .runtime_idle() callbacks.
    
    Link: https://lore.kernel.org/lkml/20240229062201.49500-1-kai.heng.feng@xxxxxxxxxxxxx/ # [1]
    Link: https://lore.kernel.org/r/5761426.DvuYhMxLoT@kreacher
    Reported-by: Kai-Heng Feng <kai.heng.feng@xxxxxxxxxxxxx>
    Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
    Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
    Tested-by: Ricky Wu <ricky_wu@xxxxxxxxxxx>
    Acked-by: Kai-Heng Feng <kai.heng.feng@xxxxxxxxxxxxx>
    Cc: <stable@xxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 3a9c49b0d05b0..46b82bacaff68 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -461,6 +461,13 @@ static void pci_device_remove(struct device *dev)
 
 	if (drv->remove) {
 		pm_runtime_get_sync(dev);
+		/*
+		 * If the driver provides a .runtime_idle() callback and it has
+		 * started to run already, it may continue to run in parallel
+		 * with the code below, so wait until all of the runtime PM
+		 * activity has completed.
+		 */
+		pm_runtime_barrier(dev);
 		drv->remove(pci_dev);
 		pm_runtime_put_noidle(dev);
 	}




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux