summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2009-03-26 15:24:20 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-03-26 15:24:18 +0100
commit56e25e9777bf15365293e27a3256eb9214a11edf (patch)
tree832f5944f20379e33855cb55418b6407c81141a3 /drivers/s390
parent[S390] cio: remove unused local variable (diff)
downloadlinux-56e25e9777bf15365293e27a3256eb9214a11edf.tar.xz
linux-56e25e9777bf15365293e27a3256eb9214a11edf.zip
[S390] cio: prevent workqueue deadlock
Subchannel reprobing can block the kslowcrw workqueue indefinitely while waiting for device recognition to finish which is also scheduled to run on kslowcrw. Prevent this deadlock by moving the waiting portion of subchannel reprobing to the cio workqueue. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/css.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1f2e424596af..8446d15e4485 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -533,6 +533,17 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
return ret;
}
+static void reprobe_after_idle(struct work_struct *unused)
+{
+ /* Make sure initial subchannel scan is done. */
+ wait_event(ccw_device_init_wq,
+ atomic_read(&ccw_device_init_count) == 0);
+ if (need_reprobe)
+ css_schedule_reprobe();
+}
+
+static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle);
+
/* Work function used to reprobe all unregistered subchannels. */
static void reprobe_all(struct work_struct *unused)
{
@@ -540,10 +551,12 @@ static void reprobe_all(struct work_struct *unused)
CIO_MSG_EVENT(4, "reprobe start\n");
- need_reprobe = 0;
/* Make sure initial subchannel scan is done. */
- wait_event(ccw_device_init_wq,
- atomic_read(&ccw_device_init_count) == 0);
+ if (atomic_read(&ccw_device_init_count) != 0) {
+ queue_work(ccw_device_work, &reprobe_idle_work);
+ return;
+ }
+ need_reprobe = 0;
ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,