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

Commit b55c5989 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

SUNRPC: Fix a race between work-queue and rpc_killall_tasks



Since rpc_killall_tasks may modify the rpc_task's tk_action field
without any locking, we need to be careful when dereferencing it.

Reported-by: default avatarBen Greear <greearb@candelatech.com>
Tested-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org
parent 2bea038c
Loading
Loading
Loading
Loading
+11 −16
Original line number Diff line number Diff line
@@ -616,30 +616,25 @@ static void __rpc_execute(struct rpc_task *task)
	BUG_ON(RPC_IS_QUEUED(task));

	for (;;) {
		void (*do_action)(struct rpc_task *);

		/*
		 * Execute any pending callback.
		 * Execute any pending callback first.
		 */
		if (task->tk_callback) {
			void (*save_callback)(struct rpc_task *);

			/*
			 * We set tk_callback to NULL before calling it,
			 * in case it sets the tk_callback field itself:
			 */
			save_callback = task->tk_callback;
		do_action = task->tk_callback;
		task->tk_callback = NULL;
			save_callback(task);
		} else {
		if (do_action == NULL) {
			/*
			 * Perform the next FSM step.
			 * tk_action may be NULL when the task has been killed
			 * by someone else.
			 * tk_action may be NULL if the task has been killed.
			 * In particular, note that rpc_killall_tasks may
			 * do this at any time, so beware when dereferencing.
			 */
			if (task->tk_action == NULL)
			do_action = task->tk_action;
			if (do_action == NULL)
				break;
			task->tk_action(task);
		}
		do_action(task);

		/*
		 * Lockless check for whether task is sleeping or not.