Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14b218a8 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

[PATCH] RPC: Ensure rpc calls respects the RPC_NOINTR flag



 For internal purposes, the rpc_clnt_sigmask() call is replaced by
 a call to rpc_task_sigmask(), which ensures that the current task
 sigmask respects both the client cl_intr flag and the per-task NOINTR flag.

 Problem noted by Jiaying Zhang.

 Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 455a3967
Loading
Loading
Loading
Loading
+37 −34
Original line number Original line Diff line number Diff line
@@ -378,38 +378,41 @@ rpc_default_callback(struct rpc_task *task)
}
}


/*
/*
 *	Export the signal mask handling for aysnchronous code that
 *	Export the signal mask handling for synchronous code that
 *	sleeps on RPC calls
 *	sleeps on RPC calls
 */
 */
#define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL))
 
 
void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
static void rpc_save_sigmask(sigset_t *oldset, int intr)
{
{
	unsigned long	sigallow = sigmask(SIGKILL);
	unsigned long	sigallow = 0;
	unsigned long	irqflags;
	sigset_t sigmask;


	/* Turn off various signals */
	/* Block all signals except those listed in sigallow */
	if (clnt->cl_intr) {
	if (intr)
		struct k_sigaction *action = current->sighand->action;
		sigallow |= RPC_INTR_SIGNALS;
		if (action[SIGINT-1].sa.sa_handler == SIG_DFL)
	siginitsetinv(&sigmask, sigallow);
			sigallow |= sigmask(SIGINT);
	sigprocmask(SIG_BLOCK, &sigmask, oldset);
		if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL)
			sigallow |= sigmask(SIGQUIT);
}
}
	spin_lock_irqsave(&current->sighand->siglock, irqflags);

	*oldset = current->blocked;
static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset)
	siginitsetinv(&current->blocked, sigallow & ~oldset->sig[0]);
{
	recalc_sigpending();
	rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task));
	spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
}
}


void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
static inline void rpc_restore_sigmask(sigset_t *oldset)
{
{
	unsigned long	irqflags;
	sigprocmask(SIG_SETMASK, oldset, NULL);
}

void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
{
	rpc_save_sigmask(oldset, clnt->cl_intr);
}


	spin_lock_irqsave(&current->sighand->siglock, irqflags);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
	current->blocked = *oldset;
{
	recalc_sigpending();
	rpc_restore_sigmask(oldset);
	spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
}
}


/*
/*
@@ -427,26 +430,26 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)


	BUG_ON(flags & RPC_TASK_ASYNC);
	BUG_ON(flags & RPC_TASK_ASYNC);


	rpc_clnt_sigmask(clnt, &oldset);		

	status = -ENOMEM;
	status = -ENOMEM;
	task = rpc_new_task(clnt, NULL, flags);
	task = rpc_new_task(clnt, NULL, flags);
	if (task == NULL)
	if (task == NULL)
		goto out;
		goto out;


	/* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
	rpc_task_sigmask(task, &oldset);

	rpc_call_setup(task, msg, 0);
	rpc_call_setup(task, msg, 0);


	/* Set up the call info struct and execute the task */
	/* Set up the call info struct and execute the task */
	if (task->tk_status == 0)
	if (task->tk_status == 0) {
		status = rpc_execute(task);
		status = rpc_execute(task);
	else {
	} else {
		status = task->tk_status;
		status = task->tk_status;
		rpc_release_task(task);
		rpc_release_task(task);
	}
	}


	rpc_restore_sigmask(&oldset);
out:
out:
	rpc_clnt_sigunmask(clnt, &oldset);		

	return status;
	return status;
}
}


@@ -467,8 +470,6 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,


	flags |= RPC_TASK_ASYNC;
	flags |= RPC_TASK_ASYNC;


	rpc_clnt_sigmask(clnt, &oldset);		

	/* Create/initialize a new RPC task */
	/* Create/initialize a new RPC task */
	if (!callback)
	if (!callback)
		callback = rpc_default_callback;
		callback = rpc_default_callback;
@@ -477,6 +478,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
		goto out;
		goto out;
	task->tk_calldata = data;
	task->tk_calldata = data;


	/* Mask signals on GSS_AUTH upcalls */
	rpc_task_sigmask(task, &oldset);		

	rpc_call_setup(task, msg, 0);
	rpc_call_setup(task, msg, 0);


	/* Set up the call info struct and execute the task */
	/* Set up the call info struct and execute the task */
@@ -486,9 +490,8 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
	else
	else
		rpc_release_task(task);
		rpc_release_task(task);


	rpc_restore_sigmask(&oldset);		
out:
out:
	rpc_clnt_sigunmask(clnt, &oldset);		

	return status;
	return status;
}
}


@@ -666,7 +669,7 @@ call_allocate(struct rpc_task *task)
		return;
		return;
	printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 
	printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 


	if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) {
	if (RPC_IS_ASYNC(task) || !signalled()) {
		xprt_release(task);
		xprt_release(task);
		task->tk_action = call_reserve;
		task->tk_action = call_reserve;
		rpc_delay(task, HZ>>4);
		rpc_delay(task, HZ>>4);