aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2012-05-15 03:20:06 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-05-16 08:42:46 -0400
commiteda0c6d6b04d3cf72f5e8d656e39bffe3568e6db (patch)
tree5f57e3581729dfad7a7999ee24fd044b47018b8e /arch/s390/kernel
parente5b8d7553f87d939295e9eb0ca699c0030dc5ff1 (diff)
s390: fix race on TIF_MCCK_PENDING
There is a small race window in the __switch_to code in regard to the transfer of the TIF_MCCK_PENDING bit from the previous to the next task. The bit is transferred before the task struct pointer and the thread-info pointer for the next task has been stored to lowcore. If a machine check sets the TIF_MCCK_PENDING bit between the transfer code and the store of current/thread_info the bit is still set for the previous task. And if the previous task has terminated it can get lost. The effect is that a pending CRW is not retrieved until the next machine checks sets TIF_MCCK_PENDING. To fix this reorder __switch_to to first store the task struct and thread-info pointer and then do the transfer of the bit. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/entry.S21
-rw-r--r--arch/s390/kernel/entry64.S21
2 files changed, 22 insertions, 20 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 74ee563fe62..1ae93b573d7 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -145,22 +145,23 @@ STACK_SIZE = 1 << STACK_SHIFT
145 * gpr2 = prev 145 * gpr2 = prev
146 */ 146 */
147ENTRY(__switch_to) 147ENTRY(__switch_to)
148 stm %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task
149 st %r15,__THREAD_ksp(%r2) # store kernel stack of prev
148 l %r4,__THREAD_info(%r2) # get thread_info of prev 150 l %r4,__THREAD_info(%r2) # get thread_info of prev
149 l %r5,__THREAD_info(%r3) # get thread_info of next 151 l %r5,__THREAD_info(%r3) # get thread_info of next
152 lr %r15,%r5
153 ahi %r15,STACK_SIZE # end of kernel stack of next
154 st %r3,__LC_CURRENT # store task struct of next
155 st %r5,__LC_THREAD_INFO # store thread info of next
156 st %r15,__LC_KERNEL_STACK # store end of kernel stack
157 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
158 mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
159 l %r15,__THREAD_ksp(%r3) # load kernel stack of next
150 tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? 160 tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
151 jz 0f 161 jz 0f
152 ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev 162 ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
153 oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next 163 oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next
1540: stm %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task 1640: lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
155 st %r15,__THREAD_ksp(%r2) # store kernel stack of prev
156 l %r15,__THREAD_ksp(%r3) # load kernel stack of next
157 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
158 lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
159 st %r3,__LC_CURRENT # store task struct of next
160 mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
161 st %r5,__LC_THREAD_INFO # store thread info of next
162 ahi %r5,STACK_SIZE # end of kernel stack of next
163 st %r5,__LC_KERNEL_STACK # store end of kernel stack
164 br %r14 165 br %r14
165 166
166__critical_start: 167__critical_start:
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 02bf601d84b..229fe1d0774 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -164,22 +164,23 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
164 * gpr2 = prev 164 * gpr2 = prev
165 */ 165 */
166ENTRY(__switch_to) 166ENTRY(__switch_to)
167 stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task
168 stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev
167 lg %r4,__THREAD_info(%r2) # get thread_info of prev 169 lg %r4,__THREAD_info(%r2) # get thread_info of prev
168 lg %r5,__THREAD_info(%r3) # get thread_info of next 170 lg %r5,__THREAD_info(%r3) # get thread_info of next
171 lgr %r15,%r5
172 aghi %r15,STACK_SIZE # end of kernel stack of next
173 stg %r3,__LC_CURRENT # store task struct of next
174 stg %r5,__LC_THREAD_INFO # store thread info of next
175 stg %r15,__LC_KERNEL_STACK # store end of kernel stack
176 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
177 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
178 lg %r15,__THREAD_ksp(%r3) # load kernel stack of next
169 tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? 179 tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
170 jz 0f 180 jz 0f
171 ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev 181 ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
172 oi __TI_flags+7(%r5),_TIF_MCCK_PENDING # set it in next 182 oi __TI_flags+7(%r5),_TIF_MCCK_PENDING # set it in next
1730: stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task 1830: lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
174 stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev
175 lg %r15,__THREAD_ksp(%r3) # load kernel stack of next
176 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
177 lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
178 stg %r3,__LC_CURRENT # store task struct of next
179 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
180 stg %r5,__LC_THREAD_INFO # store thread info of next
181 aghi %r5,STACK_SIZE # end of kernel stack of next
182 stg %r5,__LC_KERNEL_STACK # store end of kernel stack
183 br %r14 184 br %r14
184 185
185__critical_start: 186__critical_start: