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>
This commit is contained in:
		
					parent
					
						
							
								e5b8d7553f
							
						
					
				
			
			
				commit
				
					
						eda0c6d6b0
					
				
			
		
					 2 changed files with 22 additions and 20 deletions
				
			
		| 
						 | 
					@ -145,22 +145,23 @@ STACK_SIZE  = 1 << STACK_SHIFT
 | 
				
			||||||
 *  gpr2 = prev
 | 
					 *  gpr2 = prev
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(__switch_to)
 | 
					ENTRY(__switch_to)
 | 
				
			||||||
 | 
						stm	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
 | 
				
			||||||
 | 
						st	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
 | 
				
			||||||
	l	%r4,__THREAD_info(%r2)		# get thread_info of prev
 | 
						l	%r4,__THREAD_info(%r2)		# get thread_info of prev
 | 
				
			||||||
	l	%r5,__THREAD_info(%r3)		# get thread_info of next
 | 
						l	%r5,__THREAD_info(%r3)		# get thread_info of next
 | 
				
			||||||
 | 
						lr	%r15,%r5
 | 
				
			||||||
 | 
						ahi	%r15,STACK_SIZE			# end of kernel stack of next
 | 
				
			||||||
 | 
						st	%r3,__LC_CURRENT		# store task struct of next
 | 
				
			||||||
 | 
						st	%r5,__LC_THREAD_INFO		# store thread info of next
 | 
				
			||||||
 | 
						st	%r15,__LC_KERNEL_STACK		# store end of kernel stack
 | 
				
			||||||
 | 
						lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 | 
				
			||||||
 | 
						mvc	__LC_CURRENT_PID(4,%r0),__TASK_pid(%r3)	# store pid of next
 | 
				
			||||||
 | 
						l	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 | 
				
			||||||
	tm	__TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
 | 
						tm	__TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
 | 
				
			||||||
	jz	0f
 | 
						jz	0f
 | 
				
			||||||
	ni	__TI_flags+3(%r4),255-_TIF_MCCK_PENDING	# clear flag in prev
 | 
						ni	__TI_flags+3(%r4),255-_TIF_MCCK_PENDING	# clear flag in prev
 | 
				
			||||||
	oi	__TI_flags+3(%r5),_TIF_MCCK_PENDING	# set it in next
 | 
						oi	__TI_flags+3(%r5),_TIF_MCCK_PENDING	# set it in next
 | 
				
			||||||
0:	stm	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
 | 
					0:	lm	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 | 
				
			||||||
	st	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
 | 
					 | 
				
			||||||
	l	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 | 
					 | 
				
			||||||
	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 | 
					 | 
				
			||||||
	lm	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 | 
					 | 
				
			||||||
	st	%r3,__LC_CURRENT		# store task struct of next
 | 
					 | 
				
			||||||
	mvc	__LC_CURRENT_PID(4,%r0),__TASK_pid(%r3)	# store pid of next
 | 
					 | 
				
			||||||
	st	%r5,__LC_THREAD_INFO		# store thread info of next
 | 
					 | 
				
			||||||
	ahi	%r5,STACK_SIZE			# end of kernel stack of next
 | 
					 | 
				
			||||||
	st	%r5,__LC_KERNEL_STACK		# store end of kernel stack
 | 
					 | 
				
			||||||
	br	%r14
 | 
						br	%r14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__critical_start:
 | 
					__critical_start:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,22 +164,23 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
 | 
				
			||||||
 *  gpr2 = prev
 | 
					 *  gpr2 = prev
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(__switch_to)
 | 
					ENTRY(__switch_to)
 | 
				
			||||||
 | 
						stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
 | 
				
			||||||
 | 
						stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
 | 
				
			||||||
	lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
 | 
						lg	%r4,__THREAD_info(%r2)		# get thread_info of prev
 | 
				
			||||||
	lg	%r5,__THREAD_info(%r3)		# get thread_info of next
 | 
						lg	%r5,__THREAD_info(%r3)		# get thread_info of next
 | 
				
			||||||
 | 
						lgr	%r15,%r5
 | 
				
			||||||
 | 
						aghi	%r15,STACK_SIZE			# end of kernel stack of next
 | 
				
			||||||
 | 
						stg	%r3,__LC_CURRENT		# store task struct of next
 | 
				
			||||||
 | 
						stg	%r5,__LC_THREAD_INFO		# store thread info of next
 | 
				
			||||||
 | 
						stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
 | 
				
			||||||
 | 
						lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 | 
				
			||||||
 | 
						mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
 | 
				
			||||||
 | 
						lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 | 
				
			||||||
	tm	__TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
 | 
						tm	__TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
 | 
				
			||||||
	jz	0f
 | 
						jz	0f
 | 
				
			||||||
	ni	__TI_flags+7(%r4),255-_TIF_MCCK_PENDING	# clear flag in prev
 | 
						ni	__TI_flags+7(%r4),255-_TIF_MCCK_PENDING	# clear flag in prev
 | 
				
			||||||
	oi	__TI_flags+7(%r5),_TIF_MCCK_PENDING	# set it in next
 | 
						oi	__TI_flags+7(%r5),_TIF_MCCK_PENDING	# set it in next
 | 
				
			||||||
0:	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
 | 
					0:	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 | 
				
			||||||
	stg	%r15,__THREAD_ksp(%r2)		# store kernel stack of prev
 | 
					 | 
				
			||||||
	lg	%r15,__THREAD_ksp(%r3)		# load kernel stack of next
 | 
					 | 
				
			||||||
	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
 | 
					 | 
				
			||||||
	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
 | 
					 | 
				
			||||||
	stg	%r3,__LC_CURRENT		# store task struct of next
 | 
					 | 
				
			||||||
	mvc	__LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
 | 
					 | 
				
			||||||
	stg	%r5,__LC_THREAD_INFO		# store thread info of next
 | 
					 | 
				
			||||||
	aghi	%r5,STACK_SIZE			# end of kernel stack of next
 | 
					 | 
				
			||||||
	stg	%r5,__LC_KERNEL_STACK		# store end of kernel stack
 | 
					 | 
				
			||||||
	br	%r14
 | 
						br	%r14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__critical_start:
 | 
					__critical_start:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue