aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-11-11 22:18:03 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-12-06 10:46:25 -0500
commite6b3c4db6fbcd0d33720696f37790d6b8be12313 (patch)
tree24ad4a93b00ba7236b9a2d896fd6cb59a1dc2334
parentcc4dc59e5580d6c0de1685a25b74d32175f43434 (diff)
Fix a second potential rpc_wakeup race...
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4proc.c12
-rw-r--r--include/linux/sunrpc/sched.h8
-rw-r--r--net/sunrpc/clnt.c19
-rw-r--r--net/sunrpc/pmap_clnt.c2
-rw-r--r--net/sunrpc/sched.c80
-rw-r--r--net/sunrpc/sunrpc_syms.c1
6 files changed, 65 insertions, 57 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8118036cc449..93ac05889cbc 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -636,7 +636,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
636 smp_wmb(); 636 smp_wmb();
637 } else 637 } else
638 status = data->rpc_status; 638 status = data->rpc_status;
639 rpc_release_task(task); 639 rpc_put_task(task);
640 return status; 640 return status;
641} 641}
642 642
@@ -742,7 +742,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
742 smp_wmb(); 742 smp_wmb();
743 } else 743 } else
744 status = data->rpc_status; 744 status = data->rpc_status;
745 rpc_release_task(task); 745 rpc_put_task(task);
746 if (status != 0) 746 if (status != 0)
747 return status; 747 return status;
748 748
@@ -3067,7 +3067,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
3067 if (status == 0) 3067 if (status == 0)
3068 nfs_post_op_update_inode(inode, &data->fattr); 3068 nfs_post_op_update_inode(inode, &data->fattr);
3069 } 3069 }
3070 rpc_release_task(task); 3070 rpc_put_task(task);
3071 return status; 3071 return status;
3072} 3072}
3073 3073
@@ -3314,7 +3314,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
3314 if (IS_ERR(task)) 3314 if (IS_ERR(task))
3315 goto out; 3315 goto out;
3316 status = nfs4_wait_for_completion_rpc_task(task); 3316 status = nfs4_wait_for_completion_rpc_task(task);
3317 rpc_release_task(task); 3317 rpc_put_task(task);
3318out: 3318out:
3319 return status; 3319 return status;
3320} 3320}
@@ -3430,7 +3430,7 @@ static void nfs4_lock_release(void *calldata)
3430 task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, 3430 task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
3431 data->arg.lock_seqid); 3431 data->arg.lock_seqid);
3432 if (!IS_ERR(task)) 3432 if (!IS_ERR(task))
3433 rpc_release_task(task); 3433 rpc_put_task(task);
3434 dprintk("%s: cancelling lock!\n", __FUNCTION__); 3434 dprintk("%s: cancelling lock!\n", __FUNCTION__);
3435 } else 3435 } else
3436 nfs_free_seqid(data->arg.lock_seqid); 3436 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
3472 ret = -EAGAIN; 3472 ret = -EAGAIN;
3473 } else 3473 } else
3474 data->cancelled = 1; 3474 data->cancelled = 1;
3475 rpc_release_task(task); 3475 rpc_put_task(task);
3476 dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); 3476 dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret);
3477 return ret; 3477 return ret;
3478} 3478}
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index f399c138f79d..9fdb8c9d09f2 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -178,13 +178,6 @@ struct rpc_call_ops {
178 } while (0) 178 } while (0)
179 179
180#define RPC_IS_ACTIVATED(t) (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)) 180#define RPC_IS_ACTIVATED(t) (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
181#define rpc_set_active(t) (set_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
182#define rpc_clear_active(t) \
183 do { \
184 smp_mb__before_clear_bit(); \
185 clear_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate); \
186 smp_mb__after_clear_bit(); \
187 } while(0)
188 181
189/* 182/*
190 * Task priorities. 183 * Task priorities.
@@ -254,6 +247,7 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
254void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, 247void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
255 int flags, const struct rpc_call_ops *ops, 248 int flags, const struct rpc_call_ops *ops,
256 void *data); 249 void *data);
250void rpc_put_task(struct rpc_task *);
257void rpc_release_task(struct rpc_task *); 251void rpc_release_task(struct rpc_task *);
258void rpc_exit_task(struct rpc_task *); 252void rpc_exit_task(struct rpc_task *);
259void rpc_killall_tasks(struct rpc_clnt *); 253void rpc_killall_tasks(struct rpc_clnt *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index dfeea4fea95a..a323abc7ea85 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -466,10 +466,9 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
466 466
467 BUG_ON(flags & RPC_TASK_ASYNC); 467 BUG_ON(flags & RPC_TASK_ASYNC);
468 468
469 status = -ENOMEM;
470 task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL); 469 task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL);
471 if (task == NULL) 470 if (task == NULL)
472 goto out; 471 return -ENOMEM;
473 472
474 /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ 473 /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
475 rpc_task_sigmask(task, &oldset); 474 rpc_task_sigmask(task, &oldset);
@@ -478,15 +477,17 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
478 477
479 /* Set up the call info struct and execute the task */ 478 /* Set up the call info struct and execute the task */
480 status = task->tk_status; 479 status = task->tk_status;
481 if (status == 0) { 480 if (status != 0) {
482 atomic_inc(&task->tk_count); 481 rpc_release_task(task);
483 status = rpc_execute(task); 482 goto out;
484 if (status == 0)
485 status = task->tk_status;
486 } 483 }
487 rpc_restore_sigmask(&oldset); 484 atomic_inc(&task->tk_count);
488 rpc_release_task(task); 485 status = rpc_execute(task);
486 if (status == 0)
487 status = task->tk_status;
488 rpc_put_task(task);
489out: 489out:
490 rpc_restore_sigmask(&oldset);
490 return status; 491 return status;
491} 492}
492 493
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index e52afab413de..8d2e10fc3df9 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -134,7 +134,7 @@ void rpc_getport(struct rpc_task *task)
134 child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); 134 child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
135 if (IS_ERR(child)) 135 if (IS_ERR(child))
136 goto bailout; 136 goto bailout;
137 rpc_release_task(child); 137 rpc_put_task(child);
138 138
139 task->tk_xprt->stat.bind_count++; 139 task->tk_xprt->stat.bind_count++;
140 return; 140 return;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index b57d4062d429..66d01365f3a5 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -266,12 +266,28 @@ static int rpc_wait_bit_interruptible(void *word)
266 return 0; 266 return 0;
267} 267}
268 268
269static void rpc_set_active(struct rpc_task *task)
270{
271 if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0)
272 return;
273 spin_lock(&rpc_sched_lock);
274#ifdef RPC_DEBUG
275 task->tk_magic = RPC_TASK_MAGIC_ID;
276 task->tk_pid = rpc_task_id++;
277#endif
278 /* Add to global list of all tasks */
279 list_add_tail(&task->tk_task, &all_tasks);
280 spin_unlock(&rpc_sched_lock);
281}
282
269/* 283/*
270 * Mark an RPC call as having completed by clearing the 'active' bit 284 * Mark an RPC call as having completed by clearing the 'active' bit
271 */ 285 */
272static inline void rpc_mark_complete_task(struct rpc_task *task) 286static void rpc_mark_complete_task(struct rpc_task *task)
273{ 287{
274 rpc_clear_active(task); 288 smp_mb__before_clear_bit();
289 clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
290 smp_mb__after_clear_bit();
275 wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE); 291 wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
276} 292}
277 293
@@ -335,9 +351,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
335 return; 351 return;
336 } 352 }
337 353
338 /* Mark the task as being activated if so needed */
339 rpc_set_active(task);
340
341 __rpc_add_wait_queue(q, task); 354 __rpc_add_wait_queue(q, task);
342 355
343 BUG_ON(task->tk_callback != NULL); 356 BUG_ON(task->tk_callback != NULL);
@@ -348,6 +361,9 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
348void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, 361void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
349 rpc_action action, rpc_action timer) 362 rpc_action action, rpc_action timer)
350{ 363{
364 /* Mark the task as being activated if so needed */
365 rpc_set_active(task);
366
351 /* 367 /*
352 * Protect the queue operations. 368 * Protect the queue operations.
353 */ 369 */
@@ -673,8 +689,6 @@ static int __rpc_execute(struct rpc_task *task)
673 } 689 }
674 690
675 dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status); 691 dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status);
676 /* Wake up anyone who is waiting for task completion */
677 rpc_mark_complete_task(task);
678 /* Release all resources associated with the task */ 692 /* Release all resources associated with the task */
679 rpc_release_task(task); 693 rpc_release_task(task);
680 return status; 694 return status;
@@ -788,15 +802,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
788 task->tk_flags |= RPC_TASK_NOINTR; 802 task->tk_flags |= RPC_TASK_NOINTR;
789 } 803 }
790 804
791#ifdef RPC_DEBUG
792 task->tk_magic = RPC_TASK_MAGIC_ID;
793 task->tk_pid = rpc_task_id++;
794#endif
795 /* Add to global list of all tasks */
796 spin_lock(&rpc_sched_lock);
797 list_add_tail(&task->tk_task, &all_tasks);
798 spin_unlock(&rpc_sched_lock);
799
800 BUG_ON(task->tk_ops == NULL); 805 BUG_ON(task->tk_ops == NULL);
801 806
802 /* starting timestamp */ 807 /* starting timestamp */
@@ -849,16 +854,35 @@ cleanup:
849 goto out; 854 goto out;
850} 855}
851 856
852void rpc_release_task(struct rpc_task *task) 857
858void rpc_put_task(struct rpc_task *task)
853{ 859{
854 const struct rpc_call_ops *tk_ops = task->tk_ops; 860 const struct rpc_call_ops *tk_ops = task->tk_ops;
855 void *calldata = task->tk_calldata; 861 void *calldata = task->tk_calldata;
856 862
863 if (!atomic_dec_and_test(&task->tk_count))
864 return;
865 /* Release resources */
866 if (task->tk_rqstp)
867 xprt_release(task);
868 if (task->tk_msg.rpc_cred)
869 rpcauth_unbindcred(task);
870 if (task->tk_client) {
871 rpc_release_client(task->tk_client);
872 task->tk_client = NULL;
873 }
874 if (task->tk_flags & RPC_TASK_DYNAMIC)
875 rpc_free_task(task);
876 if (tk_ops->rpc_release)
877 tk_ops->rpc_release(calldata);
878}
879EXPORT_SYMBOL(rpc_put_task);
880
881void rpc_release_task(struct rpc_task *task)
882{
857#ifdef RPC_DEBUG 883#ifdef RPC_DEBUG
858 BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); 884 BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
859#endif 885#endif
860 if (!atomic_dec_and_test(&task->tk_count))
861 return;
862 dprintk("RPC: %4d release task\n", task->tk_pid); 886 dprintk("RPC: %4d release task\n", task->tk_pid);
863 887
864 /* Remove from global task list */ 888 /* Remove from global task list */
@@ -871,23 +895,13 @@ void rpc_release_task(struct rpc_task *task)
871 /* Synchronously delete any running timer */ 895 /* Synchronously delete any running timer */
872 rpc_delete_timer(task); 896 rpc_delete_timer(task);
873 897
874 /* Release resources */
875 if (task->tk_rqstp)
876 xprt_release(task);
877 if (task->tk_msg.rpc_cred)
878 rpcauth_unbindcred(task);
879 if (task->tk_client) {
880 rpc_release_client(task->tk_client);
881 task->tk_client = NULL;
882 }
883
884#ifdef RPC_DEBUG 898#ifdef RPC_DEBUG
885 task->tk_magic = 0; 899 task->tk_magic = 0;
886#endif 900#endif
887 if (task->tk_flags & RPC_TASK_DYNAMIC) 901 /* Wake up anyone who is waiting for task completion */
888 rpc_free_task(task); 902 rpc_mark_complete_task(task);
889 if (tk_ops->rpc_release) 903
890 tk_ops->rpc_release(calldata); 904 rpc_put_task(task);
891} 905}
892 906
893/** 907/**
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 192dff5dabcb..faaf81e97720 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -33,7 +33,6 @@ EXPORT_SYMBOL(rpciod_down);
33EXPORT_SYMBOL(rpciod_up); 33EXPORT_SYMBOL(rpciod_up);
34EXPORT_SYMBOL(rpc_new_task); 34EXPORT_SYMBOL(rpc_new_task);
35EXPORT_SYMBOL(rpc_wake_up_status); 35EXPORT_SYMBOL(rpc_wake_up_status);
36EXPORT_SYMBOL(rpc_release_task);
37 36
38/* RPC client functions */ 37/* RPC client functions */
39EXPORT_SYMBOL(rpc_clone_client); 38EXPORT_SYMBOL(rpc_clone_client);