diff options
Diffstat (limited to 'kernel/umh.c')
| -rw-r--r-- | kernel/umh.c | 20 | 
1 files changed, 13 insertions, 7 deletions
diff --git a/kernel/umh.c b/kernel/umh.c index 850631518665..fbf872c624cb 100644 --- a/kernel/umh.c +++ b/kernel/umh.c @@ -438,21 +438,27 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)  	if (wait == UMH_NO_WAIT)	/* task has freed sub_info */  		goto unlock; -	if (wait & UMH_KILLABLE) -		state |= TASK_KILLABLE; -  	if (wait & UMH_FREEZABLE)  		state |= TASK_FREEZABLE; -	retval = wait_for_completion_state(&done, state); -	if (!retval) -		goto wait_done; -  	if (wait & UMH_KILLABLE) { +		retval = wait_for_completion_state(&done, state | TASK_KILLABLE); +		if (!retval) +			goto wait_done; +  		/* umh_complete() will see NULL and free sub_info */  		if (xchg(&sub_info->complete, NULL))  			goto unlock; + +		/* +		 * fallthrough; in case of -ERESTARTSYS now do uninterruptible +		 * wait_for_completion_state(). Since umh_complete() shall call +		 * complete() in a moment if xchg() above returned NULL, this +		 * uninterruptible wait_for_completion_state() will not block +		 * SIGKILL'ed processes for long. +		 */  	} +	wait_for_completion_state(&done, state);  wait_done:  	retval = sub_info->retval;  |