1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: qdio: add missing tiq_list locking
3 References: bnc#484767,LTC#52205
5 Symptom: The system may hang if multiple qdio devices are added or
7 Problem: Although reading the tiq_list is done using RCU adding and
8 removing elements from the list must still happen locked since
9 multiple qdio devices may change the list in parallel otherwise.
10 Solution: Add a mutex to protect the tiq_list.
12 Acked-by: John Jolly <jjolly@suse.de>
14 drivers/s390/cio/qdio_main.c | 1 +
15 drivers/s390/cio/qdio_thinint.c | 10 +++++++---
16 2 files changed, 8 insertions(+), 3 deletions(-)
18 Index: linux-sles11/drivers/s390/cio/qdio_main.c
19 ===================================================================
20 --- linux-sles11.orig/drivers/s390/cio/qdio_main.c
21 +++ linux-sles11/drivers/s390/cio/qdio_main.c
22 @@ -1094,6 +1094,7 @@ int qdio_shutdown(struct ccw_device *cde
26 + BUG_ON(irqs_disabled());
27 DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no);
29 mutex_lock(&irq_ptr->setup_mutex);
30 Index: linux-sles11/drivers/s390/cio/qdio_thinint.c
31 ===================================================================
32 --- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c
33 +++ linux-sles11/drivers/s390/cio/qdio_thinint.c
36 /* list of thin interrupt input queues */
37 static LIST_HEAD(tiq_list);
38 +DEFINE_MUTEX(tiq_list_lock);
40 /* adapter local summary indicator */
41 static unsigned char *tiqdio_alsi;
42 @@ -95,10 +96,10 @@ void tiqdio_add_input_queues(struct qdio
43 if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)
44 css_qdio_omit_svs = 1;
46 - for_each_input_queue(irq_ptr, q, i) {
47 + mutex_lock(&tiq_list_lock);
48 + for_each_input_queue(irq_ptr, q, i)
49 list_add_rcu(&q->entry, &tiq_list);
52 + mutex_unlock(&tiq_list_lock);
53 xchg(irq_ptr->dsci, 1);
54 tasklet_schedule(&tiqdio_tasklet);
56 @@ -118,7 +119,10 @@ void tiqdio_remove_input_queues(struct q
57 /* if establish triggered an error */
58 if (!q || !q->entry.prev || !q->entry.next)
61 + mutex_lock(&tiq_list_lock);
62 list_del_rcu(&q->entry);
63 + mutex_unlock(&tiq_list_lock);