diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-05-15 03:20:06 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-05-16 08:42:46 -0400 |
commit | eda0c6d6b04d3cf72f5e8d656e39bffe3568e6db (patch) | |
tree | 5f57e3581729dfad7a7999ee24fd044b47018b8e /arch/s390 | |
parent | e5b8d7553f87d939295e9eb0ca699c0030dc5ff1 (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')
-rw-r--r-- | arch/s390/kernel/entry.S | 21 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 21 |
2 files changed, 22 insertions, 20 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 74ee563fe62b..1ae93b573d7d 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 | */ |
147 | ENTRY(__switch_to) | 147 | ENTRY(__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 |
154 | 0: stm %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task | 164 | 0: 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 02bf601d84bf..229fe1d07749 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 | */ |
166 | ENTRY(__switch_to) | 166 | ENTRY(__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 |
173 | 0: stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task | 183 | 0: 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: |