]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: iucv: provide second per-cpu IUCV command parameter block | |
3 | References: bnc#482818,LTC#52502 | |
4 | ||
5 | Symptom: failing connect during cpu hotplugging | |
6 | Problem: Some of the IUCV commands can be invoked in interrupt | |
7 | context. If they use the same per-cpu IUCV command | |
8 | parameter block as another IUCV command invoked in | |
9 | process context and running in parallel, the IUCV command | |
10 | parameter of the not yet finished IUCV command invocation | |
11 | in process context might be overwritten. | |
12 | Solution: Provide a different per-cpu IUCV command parameter block | |
13 | for IUCV commands that can be invoked in interrupt | |
14 | context. | |
15 | ||
16 | Acked-by: John Jolly <jjolly@suse.de> | |
17 | --- | |
18 | ||
19 | net/iucv/iucv.c | 41 +++++++++++++++++++++++++++++++---------- | |
20 | 1 file changed, 31 insertions(+), 10 deletions(-) | |
21 | ||
22 | Index: linux-sles11/net/iucv/iucv.c | |
23 | =================================================================== | |
24 | --- linux-sles11.orig/net/iucv/iucv.c | |
25 | +++ linux-sles11/net/iucv/iucv.c | |
26 | @@ -280,6 +280,7 @@ union iucv_param { | |
27 | * Anchor for per-cpu IUCV command parameter block. | |
28 | */ | |
29 | static union iucv_param *iucv_param[NR_CPUS]; | |
30 | +static union iucv_param *iucv_param_irq[NR_CPUS]; | |
31 | ||
32 | /** | |
33 | * iucv_call_b2f0 | |
34 | @@ -358,7 +359,7 @@ static void iucv_allow_cpu(void *data) | |
35 | * 0x10 - Flag to allow priority message completion interrupts | |
36 | * 0x08 - Flag to allow IUCV control interrupts | |
37 | */ | |
38 | - parm = iucv_param[cpu]; | |
39 | + parm = iucv_param_irq[cpu]; | |
40 | memset(parm, 0, sizeof(union iucv_param)); | |
41 | parm->set_mask.ipmask = 0xf8; | |
42 | iucv_call_b2f0(IUCV_SETMASK, parm); | |
43 | @@ -379,7 +380,7 @@ static void iucv_block_cpu(void *data) | |
44 | union iucv_param *parm; | |
45 | ||
46 | /* Disable all iucv interrupts. */ | |
47 | - parm = iucv_param[cpu]; | |
48 | + parm = iucv_param_irq[cpu]; | |
49 | memset(parm, 0, sizeof(union iucv_param)); | |
50 | iucv_call_b2f0(IUCV_SETMASK, parm); | |
51 | ||
52 | @@ -403,7 +404,7 @@ static void iucv_declare_cpu(void *data) | |
53 | return; | |
54 | ||
55 | /* Declare interrupt buffer. */ | |
56 | - parm = iucv_param[cpu]; | |
57 | + parm = iucv_param_irq[cpu]; | |
58 | memset(parm, 0, sizeof(union iucv_param)); | |
59 | parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); | |
60 | rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); | |
61 | @@ -460,7 +461,7 @@ static void iucv_retrieve_cpu(void *data | |
62 | iucv_block_cpu(NULL); | |
63 | ||
64 | /* Retrieve interrupt buffer. */ | |
65 | - parm = iucv_param[cpu]; | |
66 | + parm = iucv_param_irq[cpu]; | |
67 | iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); | |
68 | ||
69 | /* Clear indication that an iucv buffer exists for this cpu. */ | |
70 | @@ -574,11 +575,22 @@ static int __cpuinit iucv_cpu_notify(str | |
71 | iucv_irq_data[cpu] = NULL; | |
72 | return NOTIFY_BAD; | |
73 | } | |
74 | + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), | |
75 | + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); | |
76 | + if (!iucv_param_irq[cpu]) { | |
77 | + kfree(iucv_param[cpu]); | |
78 | + iucv_param[cpu] = NULL; | |
79 | + kfree(iucv_irq_data[cpu]); | |
80 | + iucv_irq_data[cpu] = NULL; | |
81 | + return NOTIFY_BAD; | |
82 | + } | |
83 | break; | |
84 | case CPU_UP_CANCELED: | |
85 | case CPU_UP_CANCELED_FROZEN: | |
86 | case CPU_DEAD: | |
87 | case CPU_DEAD_FROZEN: | |
88 | + kfree(iucv_param_irq[cpu]); | |
89 | + iucv_param_irq[cpu] = NULL; | |
90 | kfree(iucv_param[cpu]); | |
91 | iucv_param[cpu] = NULL; | |
92 | kfree(iucv_irq_data[cpu]); | |
93 | @@ -625,7 +637,7 @@ static int iucv_sever_pathid(u16 pathid, | |
94 | { | |
95 | union iucv_param *parm; | |
96 | ||
97 | - parm = iucv_param[smp_processor_id()]; | |
98 | + parm = iucv_param_irq[smp_processor_id()]; | |
99 | memset(parm, 0, sizeof(union iucv_param)); | |
100 | if (userdata) | |
101 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | |
102 | @@ -918,10 +930,8 @@ int iucv_path_sever(struct iucv_path *pa | |
103 | if (iucv_active_cpu != smp_processor_id()) | |
104 | spin_lock_bh(&iucv_table_lock); | |
105 | rc = iucv_sever_pathid(path->pathid, userdata); | |
106 | - if (!rc) { | |
107 | - iucv_path_table[path->pathid] = NULL; | |
108 | - list_del_init(&path->list); | |
109 | - } | |
110 | + iucv_path_table[path->pathid] = NULL; | |
111 | + list_del_init(&path->list); | |
112 | if (iucv_active_cpu != smp_processor_id()) | |
113 | spin_unlock_bh(&iucv_table_lock); | |
114 | preempt_enable(); | |
115 | @@ -1333,7 +1343,7 @@ static void iucv_path_severed(struct iuc | |
116 | else { | |
117 | iucv_sever_pathid(path->pathid, NULL); | |
118 | iucv_path_table[path->pathid] = NULL; | |
119 | - list_del_init(&path->list); | |
120 | + list_del(&path->list); | |
121 | iucv_path_free(path); | |
122 | } | |
123 | } | |
124 | @@ -1637,6 +1647,13 @@ static int __init iucv_init(void) | |
125 | rc = -ENOMEM; | |
126 | goto out_free; | |
127 | } | |
128 | + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), | |
129 | + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); | |
130 | + if (!iucv_param_irq[cpu]) { | |
131 | + rc = -ENOMEM; | |
132 | + goto out_free; | |
133 | + } | |
134 | + | |
135 | } | |
136 | rc = register_hotcpu_notifier(&iucv_cpu_notifier); | |
137 | if (rc) | |
138 | @@ -1654,6 +1671,8 @@ out_cpu: | |
139 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | |
140 | out_free: | |
141 | for_each_possible_cpu(cpu) { | |
142 | + kfree(iucv_param_irq[cpu]); | |
143 | + iucv_param_irq[cpu] = NULL; | |
144 | kfree(iucv_param[cpu]); | |
145 | iucv_param[cpu] = NULL; | |
146 | kfree(iucv_irq_data[cpu]); | |
147 | @@ -1684,6 +1703,8 @@ static void __exit iucv_exit(void) | |
148 | spin_unlock_irq(&iucv_queue_lock); | |
149 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | |
150 | for_each_possible_cpu(cpu) { | |
151 | + kfree(iucv_param_irq[cpu]); | |
152 | + iucv_param_irq[cpu] = NULL; | |
153 | kfree(iucv_param[cpu]); | |
154 | iucv_param[cpu] = NULL; | |
155 | kfree(iucv_irq_data[cpu]); |