[PATCH] Block, SCSI: notify block layer about runtime PM status change following system resume

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

 



The request-queue-based runtime PM implementation is missing an
ingredient.  There's no way to tell the block layer that a device has
passed directly from runtime-suspended to runtime-resumed without
invoking any runtime-PM callbacks.

Typically this happens during a system resume.  A resume callback
routine will contain some variant of the following:

	if (err == 0) {
		pm_runtime_disable(dev);
		pm_runtime_set_active(dev);
		pm_runtime_enable(dev);
	}

This lets the runtime-PM core know that following the system resume,
the device is back in the active state.  Without a corresponding way
to inform the block layer, the device will become unusable.  Requests
added to the queue will never be dispatched because the device still
appears to be suspended, and attempts to perform a runtime resume will
fail because the runtime-PM core knows the device is already active.
To make matters worse, any attempt to use the device will prevent it
from going back into runtime suspend, because now the request queue
will be non-empty.

This patch remedies the situation by adding a blk_runtime_activate()
function and calling it at the appropriate place in the
scsi_dev_type_resume() routine.

Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Reported-by: Ken Xue <Ken.Xue@xxxxxxx>
Tested-by: Ken Xue <Ken.Xue@xxxxxxx>
CC: <stable@xxxxxxxxxxxxxxx>

---


[as1785]


 block/blk-core.c       |   19 +++++++++++++++++++
 drivers/scsi/scsi_pm.c |    4 +++-
 include/linux/blkdev.h |    2 ++
 3 files changed, 24 insertions(+), 1 deletion(-)

Index: usb-4.2/include/linux/blkdev.h
===================================================================
--- usb-4.2.orig/include/linux/blkdev.h
+++ usb-4.2/include/linux/blkdev.h
@@ -1017,6 +1017,7 @@ extern int blk_pre_runtime_suspend(struc
 extern void blk_post_runtime_suspend(struct request_queue *q, int err);
 extern void blk_pre_runtime_resume(struct request_queue *q);
 extern void blk_post_runtime_resume(struct request_queue *q, int err);
+extern void blk_runtime_activate(struct request_queue *q);
 #else
 static inline void blk_pm_runtime_init(struct request_queue *q,
 	struct device *dev) {}
@@ -1027,6 +1028,7 @@ static inline int blk_pre_runtime_suspen
 static inline void blk_post_runtime_suspend(struct request_queue *q, int err) {}
 static inline void blk_pre_runtime_resume(struct request_queue *q) {}
 static inline void blk_post_runtime_resume(struct request_queue *q, int err) {}
+static inline void blk_runtime_activate(struct request_queue *q) {}
 #endif
 
 /*
Index: usb-4.2/block/blk-core.c
===================================================================
--- usb-4.2.orig/block/blk-core.c
+++ usb-4.2/block/blk-core.c
@@ -3377,6 +3377,25 @@ void blk_post_runtime_resume(struct requ
 	spin_unlock_irq(q->queue_lock);
 }
 EXPORT_SYMBOL(blk_post_runtime_resume);
+
+/**
+ * blk_runtime_activate - Runtime activation processing
+ * @q: the queue of the device
+ *
+ * Description:
+ *	Tell the block layer that the device has changed directly to the
+ *	runtime-resumed state without executing any runtime-PM callbacks,
+ *	(for example, during system resume).  Does the same things as
+ *	blk_post_runtime_resume().
+ *
+ *	This function should be called after pm_runtime_set_active() and
+ *	pm_runtime_enable().
+ */
+void blk_runtime_activate(struct request_queue *q)
+{
+	blk_post_runtime_resume(q, 0);
+}
+EXPORT_SYMBOL(blk_runtime_activate);
 #endif
 
 int __init blk_dev_init(void)
Index: usb-4.2/drivers/scsi/scsi_pm.c
===================================================================
--- usb-4.2.orig/drivers/scsi/scsi_pm.c
+++ usb-4.2/drivers/scsi/scsi_pm.c
@@ -70,17 +70,19 @@ static int scsi_dev_type_suspend(struct
 static int scsi_dev_type_resume(struct device *dev,
 		int (*cb)(struct device *, const struct dev_pm_ops *))
 {
+	struct scsi_device *sdev = to_scsi_device(dev);
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 	int err = 0;
 
 	err = cb(dev, pm);
-	scsi_device_resume(to_scsi_device(dev));
+	scsi_device_resume(sdev);
 	dev_dbg(dev, "scsi resume: %d\n", err);
 
 	if (err == 0) {
 		pm_runtime_disable(dev);
 		pm_runtime_set_active(dev);
 		pm_runtime_enable(dev);
+		blk_runtime_activate(sdev->request_queue);
 	}
 
 	return err;

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux