aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalph Wuerthner <rwuerthn@de.ibm.com>2007-03-19 08:19:14 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2007-03-19 08:19:14 -0400
commitcf352ce0b9104dc6a1c11df52db9f910f1f6cd2e (patch)
tree166082c005e653747eea14d2a761119d8425decb
parentfb1c171992041e1d4bfb8c010548fa97f2106827 (diff)
[S390] zcrypt: fix possible dead lock in AP bus module
AP bus module uses bus_for_each_dev() in software interrupt context to poll for completed requests which might cause dead locks. Solution: use private AP device list for polling in software interrupt context. Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/crypto/ap_bus.c30
-rw-r--r--drivers/s390/crypto/ap_bus.h1
2 files changed, 24 insertions, 7 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index c7d1355237b6..181b51772b1b 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -65,6 +65,8 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000);
65MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on)."); 65MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on).");
66 66
67static struct device *ap_root_device = NULL; 67static struct device *ap_root_device = NULL;
68static DEFINE_SPINLOCK(ap_device_lock);
69static LIST_HEAD(ap_device_list);
68 70
69/** 71/**
70 * Workqueue & timer for bus rescan. 72 * Workqueue & timer for bus rescan.
@@ -457,6 +459,9 @@ static int ap_device_probe(struct device *dev)
457 int rc; 459 int rc;
458 460
459 ap_dev->drv = ap_drv; 461 ap_dev->drv = ap_drv;
462 spin_lock_bh(&ap_device_lock);
463 list_add(&ap_dev->list, &ap_device_list);
464 spin_unlock_bh(&ap_device_lock);
460 rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; 465 rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
461 return rc; 466 return rc;
462} 467}
@@ -497,6 +502,9 @@ static int ap_device_remove(struct device *dev)
497 ap_flush_queue(ap_dev); 502 ap_flush_queue(ap_dev);
498 if (ap_drv->remove) 503 if (ap_drv->remove)
499 ap_drv->remove(ap_dev); 504 ap_drv->remove(ap_dev);
505 spin_lock_bh(&ap_device_lock);
506 list_del_init(&ap_dev->list);
507 spin_unlock_bh(&ap_device_lock);
500 return 0; 508 return 0;
501} 509}
502 510
@@ -772,6 +780,7 @@ static void ap_scan_bus(struct work_struct *unused)
772 spin_lock_init(&ap_dev->lock); 780 spin_lock_init(&ap_dev->lock);
773 INIT_LIST_HEAD(&ap_dev->pendingq); 781 INIT_LIST_HEAD(&ap_dev->pendingq);
774 INIT_LIST_HEAD(&ap_dev->requestq); 782 INIT_LIST_HEAD(&ap_dev->requestq);
783 INIT_LIST_HEAD(&ap_dev->list);
775 if (device_type == 0) 784 if (device_type == 0)
776 ap_probe_device_type(ap_dev); 785 ap_probe_device_type(ap_dev);
777 else 786 else
@@ -1033,14 +1042,13 @@ static void ap_poll_timeout(unsigned long unused)
1033 * polling until bit 2^0 of the control flags is not set. If bit 2^1 1042 * polling until bit 2^0 of the control flags is not set. If bit 2^1
1034 * of the control flags has been set arm the poll timer. 1043 * of the control flags has been set arm the poll timer.
1035 */ 1044 */
1036static int __ap_poll_all(struct device *dev, void *data) 1045static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags)
1037{ 1046{
1038 struct ap_device *ap_dev = to_ap_dev(dev);
1039 int rc; 1047 int rc;
1040 1048
1041 spin_lock(&ap_dev->lock); 1049 spin_lock(&ap_dev->lock);
1042 if (!ap_dev->unregistered) { 1050 if (!ap_dev->unregistered) {
1043 rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data); 1051 rc = ap_poll_queue(ap_dev, flags);
1044 if (rc) 1052 if (rc)
1045 ap_dev->unregistered = 1; 1053 ap_dev->unregistered = 1;
1046 } else 1054 } else
@@ -1054,10 +1062,15 @@ static int __ap_poll_all(struct device *dev, void *data)
1054static void ap_poll_all(unsigned long dummy) 1062static void ap_poll_all(unsigned long dummy)
1055{ 1063{
1056 unsigned long flags; 1064 unsigned long flags;
1065 struct ap_device *ap_dev;
1057 1066
1058 do { 1067 do {
1059 flags = 0; 1068 flags = 0;
1060 bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all); 1069 spin_lock(&ap_device_lock);
1070 list_for_each_entry(ap_dev, &ap_device_list, list) {
1071 __ap_poll_all(ap_dev, &flags);
1072 }
1073 spin_unlock(&ap_device_lock);
1061 } while (flags & 1); 1074 } while (flags & 1);
1062 if (flags & 2) 1075 if (flags & 2)
1063 ap_schedule_poll_timer(); 1076 ap_schedule_poll_timer();
@@ -1075,6 +1088,7 @@ static int ap_poll_thread(void *data)
1075 DECLARE_WAITQUEUE(wait, current); 1088 DECLARE_WAITQUEUE(wait, current);
1076 unsigned long flags; 1089 unsigned long flags;
1077 int requests; 1090 int requests;
1091 struct ap_device *ap_dev;
1078 1092
1079 set_user_nice(current, 19); 1093 set_user_nice(current, 19);
1080 while (1) { 1094 while (1) {
@@ -1092,10 +1106,12 @@ static int ap_poll_thread(void *data)
1092 set_current_state(TASK_RUNNING); 1106 set_current_state(TASK_RUNNING);
1093 remove_wait_queue(&ap_poll_wait, &wait); 1107 remove_wait_queue(&ap_poll_wait, &wait);
1094 1108
1095 local_bh_disable();
1096 flags = 0; 1109 flags = 0;
1097 bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all); 1110 spin_lock_bh(&ap_device_lock);
1098 local_bh_enable(); 1111 list_for_each_entry(ap_dev, &ap_device_list, list) {
1112 __ap_poll_all(ap_dev, &flags);
1113 }
1114 spin_unlock_bh(&ap_device_lock);
1099 } 1115 }
1100 set_current_state(TASK_RUNNING); 1116 set_current_state(TASK_RUNNING);
1101 remove_wait_queue(&ap_poll_wait, &wait); 1117 remove_wait_queue(&ap_poll_wait, &wait);
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 83b69c01cd6e..008559ea742b 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -106,6 +106,7 @@ struct ap_device {
106 struct device device; 106 struct device device;
107 struct ap_driver *drv; /* Pointer to AP device driver. */ 107 struct ap_driver *drv; /* Pointer to AP device driver. */
108 spinlock_t lock; /* Per device lock. */ 108 spinlock_t lock; /* Per device lock. */
109 struct list_head list; /* private list of all AP devices. */
109 110
110 ap_qid_t qid; /* AP queue id. */ 111 ap_qid_t qid; /* AP queue id. */
111 int queue_depth; /* AP queue depth.*/ 112 int queue_depth; /* AP queue depth.*/