static int call_usermodehelper_exec_async(void *data)
{
	struct subprocess_info *sub_info = data;
	struct cred *new;
	int retval;

	spin_lock_irq(&current->sighand->siglock);
	flush_signal_handlers(current, 1);
	spin_unlock_irq(&current->sighand->siglock);

	/*
	 * Initial kernel threads share ther FS with init, in order to
	 * get the init root directory. But we've now created a new
	 * thread that is going to execve a user process and has its own
	 * 'struct fs_struct'. Reset umask to the default.
	 */
	current->fs->umask = 0022;

	/*
	 * Our parent (unbound workqueue) runs with elevated scheduling
	 * priority. Avoid propagating that into the userspace child.
	 */
	set_user_nice(current, 0);

	retval = -ENOMEM;
	new = prepare_kernel_cred(current);
	if (!new)
		goto out;

	spin_lock(&umh_sysctl_lock);
	new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
	new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
					     new->cap_inheritable);
	spin_unlock(&umh_sysctl_lock);

	if (sub_info->init) {
		retval = sub_info->init(sub_info, new);
		if (retval) {
			abort_creds(new);
			goto out;
		}
	}

	commit_creds(new);

	retval = kernel_execve(sub_info->path,
			       (const char *const *)sub_info->argv,
			       (const char *const *)sub_info->envp);
out:
	sub_info->retval = retval;
	/*
	 * call_usermodehelper_exec_sync() will call umh_complete
	 * if UHM_WAIT_PROC.
	 */
	if (!(sub_info->wait & UMH_WAIT_PROC))
		umh_complete(sub_info);
	if (!retval)
		return 0;
	do_exit(0);
}
