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

Fix a second potential rpc_wakeup race...

parent cc4dc59e
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -636,7 +636,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
		smp_wmb();
	} else
		status = data->rpc_status;
	rpc_release_task(task);
	rpc_put_task(task);
	return status;
}

@@ -742,7 +742,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
		smp_wmb();
	} else
		status = data->rpc_status;
	rpc_release_task(task);
	rpc_put_task(task);
	if (status != 0)
		return status;

@@ -3067,7 +3067,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
		if (status == 0)
			nfs_post_op_update_inode(inode, &data->fattr);
	}
	rpc_release_task(task);
	rpc_put_task(task);
	return status;
}

@@ -3314,7 +3314,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
	if (IS_ERR(task))
		goto out;
	status = nfs4_wait_for_completion_rpc_task(task);
	rpc_release_task(task);
	rpc_put_task(task);
out:
	return status;
}
@@ -3430,7 +3430,7 @@ static void nfs4_lock_release(void *calldata)
		task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
				data->arg.lock_seqid);
		if (!IS_ERR(task))
			rpc_release_task(task);
			rpc_put_task(task);
		dprintk("%s: cancelling lock!\n", __FUNCTION__);
	} else
		nfs_free_seqid(data->arg.lock_seqid);
@@ -3472,7 +3472,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
			ret = -EAGAIN;
	} else
		data->cancelled = 1;
	rpc_release_task(task);
	rpc_put_task(task);
	dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret);
	return ret;
}
+1 −7
Original line number Diff line number Diff line
@@ -178,13 +178,6 @@ struct rpc_call_ops {
	} while (0)

#define RPC_IS_ACTIVATED(t)	(test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
#define rpc_set_active(t)	(set_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
#define rpc_clear_active(t)	\
	do { \
		smp_mb__before_clear_bit(); \
		clear_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate); \
		smp_mb__after_clear_bit(); \
	} while(0)

/*
 * Task priorities.
@@ -254,6 +247,7 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
void		rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
				int flags, const struct rpc_call_ops *ops,
				void *data);
void		rpc_put_task(struct rpc_task *);
void		rpc_release_task(struct rpc_task *);
void		rpc_exit_task(struct rpc_task *);
void		rpc_killall_tasks(struct rpc_clnt *);
+10 −9
Original line number Diff line number Diff line
@@ -466,10 +466,9 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)

	BUG_ON(flags & RPC_TASK_ASYNC);

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

	/* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
	rpc_task_sigmask(task, &oldset);
@@ -478,15 +477,17 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)

	/* Set up the call info struct and execute the task */
	status = task->tk_status;
	if (status == 0) {
	if (status != 0) {
		rpc_release_task(task);
		goto out;
	}
	atomic_inc(&task->tk_count);
	status = rpc_execute(task);
	if (status == 0)
		status = task->tk_status;
	}
	rpc_restore_sigmask(&oldset);
	rpc_release_task(task);
	rpc_put_task(task);
out:
	rpc_restore_sigmask(&oldset);
	return status;
}

+1 −1
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ void rpc_getport(struct rpc_task *task)
	child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
	if (IS_ERR(child))
		goto bailout;
	rpc_release_task(child);
	rpc_put_task(child);

	task->tk_xprt->stat.bind_count++;
	return;
+47 −33
Original line number Diff line number Diff line
@@ -266,12 +266,28 @@ static int rpc_wait_bit_interruptible(void *word)
	return 0;
}

static void rpc_set_active(struct rpc_task *task)
{
	if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0)
		return;
	spin_lock(&rpc_sched_lock);
#ifdef RPC_DEBUG
	task->tk_magic = RPC_TASK_MAGIC_ID;
	task->tk_pid = rpc_task_id++;
#endif
	/* Add to global list of all tasks */
	list_add_tail(&task->tk_task, &all_tasks);
	spin_unlock(&rpc_sched_lock);
}

/*
 * Mark an RPC call as having completed by clearing the 'active' bit
 */
static inline void rpc_mark_complete_task(struct rpc_task *task)
static void rpc_mark_complete_task(struct rpc_task *task)
{
	rpc_clear_active(task);
	smp_mb__before_clear_bit();
	clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
	smp_mb__after_clear_bit();
	wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
}

@@ -335,9 +351,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
		return;
	}

	/* Mark the task as being activated if so needed */
	rpc_set_active(task);

	__rpc_add_wait_queue(q, task);

	BUG_ON(task->tk_callback != NULL);
@@ -348,6 +361,9 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
				rpc_action action, rpc_action timer)
{
	/* Mark the task as being activated if so needed */
	rpc_set_active(task);

	/*
	 * Protect the queue operations.
	 */
@@ -673,8 +689,6 @@ static int __rpc_execute(struct rpc_task *task)
	}

	dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status);
	/* Wake up anyone who is waiting for task completion */
	rpc_mark_complete_task(task);
	/* Release all resources associated with the task */
	rpc_release_task(task);
	return status;
@@ -788,15 +802,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
			task->tk_flags |= RPC_TASK_NOINTR;
	}

#ifdef RPC_DEBUG
	task->tk_magic = RPC_TASK_MAGIC_ID;
	task->tk_pid = rpc_task_id++;
#endif
	/* Add to global list of all tasks */
	spin_lock(&rpc_sched_lock);
	list_add_tail(&task->tk_task, &all_tasks);
	spin_unlock(&rpc_sched_lock);

	BUG_ON(task->tk_ops == NULL);

	/* starting timestamp */
@@ -849,16 +854,35 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc
	goto out;
}

void rpc_release_task(struct rpc_task *task)

void rpc_put_task(struct rpc_task *task)
{
	const struct rpc_call_ops *tk_ops = task->tk_ops;
	void *calldata = task->tk_calldata;

	if (!atomic_dec_and_test(&task->tk_count))
		return;
	/* Release resources */
	if (task->tk_rqstp)
		xprt_release(task);
	if (task->tk_msg.rpc_cred)
		rpcauth_unbindcred(task);
	if (task->tk_client) {
		rpc_release_client(task->tk_client);
		task->tk_client = NULL;
	}
	if (task->tk_flags & RPC_TASK_DYNAMIC)
		rpc_free_task(task);
	if (tk_ops->rpc_release)
		tk_ops->rpc_release(calldata);
}
EXPORT_SYMBOL(rpc_put_task);

void rpc_release_task(struct rpc_task *task)
{
#ifdef RPC_DEBUG
	BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
#endif
	if (!atomic_dec_and_test(&task->tk_count))
		return;
	dprintk("RPC: %4d release task\n", task->tk_pid);

	/* Remove from global task list */
@@ -871,23 +895,13 @@ void rpc_release_task(struct rpc_task *task)
	/* Synchronously delete any running timer */
	rpc_delete_timer(task);

	/* Release resources */
	if (task->tk_rqstp)
		xprt_release(task);
	if (task->tk_msg.rpc_cred)
		rpcauth_unbindcred(task);
	if (task->tk_client) {
		rpc_release_client(task->tk_client);
		task->tk_client = NULL;
	}

#ifdef RPC_DEBUG
	task->tk_magic = 0;
#endif
	if (task->tk_flags & RPC_TASK_DYNAMIC)
		rpc_free_task(task);
	if (tk_ops->rpc_release)
		tk_ops->rpc_release(calldata);
	/* Wake up anyone who is waiting for task completion */
	rpc_mark_complete_task(task);

	rpc_put_task(task);
}

/**
Loading