summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2019-04-07 13:58:44 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2019-04-25 14:18:12 -0400
commitae67bd3821bb0a54d97e7883d211196637d487a9 (patch)
tree351a54fd10a71f6c76d5e8d8a8ce323c9252192e
parent085b7755808aa11f78ab9377257e1dad2e6fa4bb (diff)
SUNRPC: Fix up task signalling
The RPC_TASK_KILLED flag should really not be set from another context because it can clobber data in the struct task when task->tk_flags is changed non-atomically. Let's therefore swap out RPC_TASK_KILLED with an atomic flag, and add a function to set that flag and safely wake up the task. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/lockd/clntproc.c4
-rw-r--r--fs/nfsd/nfs4callback.c4
-rw-r--r--include/linux/sunrpc/sched.h6
-rw-r--r--include/trace/events/sunrpc.h6
-rw-r--r--net/sunrpc/clnt.c14
-rw-r--r--net/sunrpc/sched.c28
-rw-r--r--net/sunrpc/xprt.c4
7 files changed, 40 insertions, 26 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index e8a004097d18..d9c32d1a20c0 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -715,7 +715,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
715 struct nlm_rqst *req = data; 715 struct nlm_rqst *req = data;
716 u32 status = ntohl(req->a_res.status); 716 u32 status = ntohl(req->a_res.status);
717 717
718 if (RPC_ASSASSINATED(task)) 718 if (RPC_SIGNALLED(task))
719 goto die; 719 goto die;
720 720
721 if (task->tk_status < 0) { 721 if (task->tk_status < 0) {
@@ -783,7 +783,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
783 struct nlm_rqst *req = data; 783 struct nlm_rqst *req = data;
784 u32 status = ntohl(req->a_res.status); 784 u32 status = ntohl(req->a_res.status);
785 785
786 if (RPC_ASSASSINATED(task)) 786 if (RPC_SIGNALLED(task))
787 goto die; 787 goto die;
788 788
789 if (task->tk_status < 0) { 789 if (task->tk_status < 0) {
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index d219159b98af..f7494be8dbe2 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -1032,7 +1032,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
1032 * the submission code will error out, so we don't need to 1032 * the submission code will error out, so we don't need to
1033 * handle that case here. 1033 * handle that case here.
1034 */ 1034 */
1035 if (task->tk_flags & RPC_TASK_KILLED) 1035 if (RPC_SIGNALLED(task))
1036 goto need_restart; 1036 goto need_restart;
1037 1037
1038 return true; 1038 return true;
@@ -1081,7 +1081,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
1081 dprintk("%s: freed slot, new seqid=%d\n", __func__, 1081 dprintk("%s: freed slot, new seqid=%d\n", __func__,
1082 clp->cl_cb_session->se_cb_seq_nr); 1082 clp->cl_cb_session->se_cb_seq_nr);
1083 1083
1084 if (task->tk_flags & RPC_TASK_KILLED) 1084 if (RPC_SIGNALLED(task))
1085 goto need_restart; 1085 goto need_restart;
1086out: 1086out:
1087 return ret; 1087 return ret;
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 52d41d0c1ae1..90e06c67f455 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -125,7 +125,6 @@ struct rpc_task_setup {
125#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ 125#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
126#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ 126#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */
127#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ 127#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
128#define RPC_TASK_KILLED 0x0100 /* task was killed */
129#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ 128#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
130#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ 129#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
131#define RPC_TASK_SENT 0x0800 /* message was sent */ 130#define RPC_TASK_SENT 0x0800 /* message was sent */
@@ -135,7 +134,6 @@ struct rpc_task_setup {
135 134
136#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) 135#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
137#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) 136#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
138#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
139#define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT)) 137#define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT))
140#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) 138#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN)
141#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT) 139#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT)
@@ -146,6 +144,7 @@ struct rpc_task_setup {
146#define RPC_TASK_NEED_XMIT 3 144#define RPC_TASK_NEED_XMIT 3
147#define RPC_TASK_NEED_RECV 4 145#define RPC_TASK_NEED_RECV 4
148#define RPC_TASK_MSG_PIN_WAIT 5 146#define RPC_TASK_MSG_PIN_WAIT 5
147#define RPC_TASK_SIGNALLED 6
149 148
150#define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) 149#define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
151#define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) 150#define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
@@ -169,6 +168,8 @@ struct rpc_task_setup {
169 168
170#define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) 169#define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)
171 170
171#define RPC_SIGNALLED(t) test_bit(RPC_TASK_SIGNALLED, &(t)->tk_runstate)
172
172/* 173/*
173 * Task priorities. 174 * Task priorities.
174 * Note: if you change these, you must also change 175 * Note: if you change these, you must also change
@@ -217,6 +218,7 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *);
217struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req); 218struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req);
218void rpc_put_task(struct rpc_task *); 219void rpc_put_task(struct rpc_task *);
219void rpc_put_task_async(struct rpc_task *); 220void rpc_put_task_async(struct rpc_task *);
221void rpc_signal_task(struct rpc_task *);
220void rpc_exit_task(struct rpc_task *); 222void rpc_exit_task(struct rpc_task *);
221void rpc_exit(struct rpc_task *, int); 223void rpc_exit(struct rpc_task *, int);
222void rpc_release_calldata(const struct rpc_call_ops *, void *); 224void rpc_release_calldata(const struct rpc_call_ops *, void *);
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
index 7e899e635d33..5e3b77d9daa7 100644
--- a/include/trace/events/sunrpc.h
+++ b/include/trace/events/sunrpc.h
@@ -82,7 +82,6 @@ TRACE_DEFINE_ENUM(RPC_TASK_SWAPPER);
82TRACE_DEFINE_ENUM(RPC_CALL_MAJORSEEN); 82TRACE_DEFINE_ENUM(RPC_CALL_MAJORSEEN);
83TRACE_DEFINE_ENUM(RPC_TASK_ROOTCREDS); 83TRACE_DEFINE_ENUM(RPC_TASK_ROOTCREDS);
84TRACE_DEFINE_ENUM(RPC_TASK_DYNAMIC); 84TRACE_DEFINE_ENUM(RPC_TASK_DYNAMIC);
85TRACE_DEFINE_ENUM(RPC_TASK_KILLED);
86TRACE_DEFINE_ENUM(RPC_TASK_SOFT); 85TRACE_DEFINE_ENUM(RPC_TASK_SOFT);
87TRACE_DEFINE_ENUM(RPC_TASK_SOFTCONN); 86TRACE_DEFINE_ENUM(RPC_TASK_SOFTCONN);
88TRACE_DEFINE_ENUM(RPC_TASK_SENT); 87TRACE_DEFINE_ENUM(RPC_TASK_SENT);
@@ -97,7 +96,6 @@ TRACE_DEFINE_ENUM(RPC_TASK_NO_RETRANS_TIMEOUT);
97 { RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \ 96 { RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \
98 { RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \ 97 { RPC_TASK_ROOTCREDS, "ROOTCREDS" }, \
99 { RPC_TASK_DYNAMIC, "DYNAMIC" }, \ 98 { RPC_TASK_DYNAMIC, "DYNAMIC" }, \
100 { RPC_TASK_KILLED, "KILLED" }, \
101 { RPC_TASK_SOFT, "SOFT" }, \ 99 { RPC_TASK_SOFT, "SOFT" }, \
102 { RPC_TASK_SOFTCONN, "SOFTCONN" }, \ 100 { RPC_TASK_SOFTCONN, "SOFTCONN" }, \
103 { RPC_TASK_SENT, "SENT" }, \ 101 { RPC_TASK_SENT, "SENT" }, \
@@ -111,6 +109,7 @@ TRACE_DEFINE_ENUM(RPC_TASK_ACTIVE);
111TRACE_DEFINE_ENUM(RPC_TASK_NEED_XMIT); 109TRACE_DEFINE_ENUM(RPC_TASK_NEED_XMIT);
112TRACE_DEFINE_ENUM(RPC_TASK_NEED_RECV); 110TRACE_DEFINE_ENUM(RPC_TASK_NEED_RECV);
113TRACE_DEFINE_ENUM(RPC_TASK_MSG_PIN_WAIT); 111TRACE_DEFINE_ENUM(RPC_TASK_MSG_PIN_WAIT);
112TRACE_DEFINE_ENUM(RPC_TASK_SIGNALLED);
114 113
115#define rpc_show_runstate(flags) \ 114#define rpc_show_runstate(flags) \
116 __print_flags(flags, "|", \ 115 __print_flags(flags, "|", \
@@ -119,7 +118,8 @@ TRACE_DEFINE_ENUM(RPC_TASK_MSG_PIN_WAIT);
119 { (1UL << RPC_TASK_ACTIVE), "ACTIVE" }, \ 118 { (1UL << RPC_TASK_ACTIVE), "ACTIVE" }, \
120 { (1UL << RPC_TASK_NEED_XMIT), "NEED_XMIT" }, \ 119 { (1UL << RPC_TASK_NEED_XMIT), "NEED_XMIT" }, \
121 { (1UL << RPC_TASK_NEED_RECV), "NEED_RECV" }, \ 120 { (1UL << RPC_TASK_NEED_RECV), "NEED_RECV" }, \
122 { (1UL << RPC_TASK_MSG_PIN_WAIT), "MSG_PIN_WAIT" }) 121 { (1UL << RPC_TASK_MSG_PIN_WAIT), "MSG_PIN_WAIT" }, \
122 { (1UL << RPC_TASK_SIGNALLED), "SIGNALLED" })
123 123
124DECLARE_EVENT_CLASS(rpc_task_running, 124DECLARE_EVENT_CLASS(rpc_task_running,
125 125
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 8ff11dc98d7f..18f5392aa550 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -827,14 +827,8 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
827 * Spin lock all_tasks to prevent changes... 827 * Spin lock all_tasks to prevent changes...
828 */ 828 */
829 spin_lock(&clnt->cl_lock); 829 spin_lock(&clnt->cl_lock);
830 list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { 830 list_for_each_entry(rovr, &clnt->cl_tasks, tk_task)
831 if (!RPC_IS_ACTIVATED(rovr)) 831 rpc_signal_task(rovr);
832 continue;
833 if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
834 rovr->tk_flags |= RPC_TASK_KILLED;
835 rpc_exit(rovr, -EIO);
836 }
837 }
838 spin_unlock(&clnt->cl_lock); 832 spin_unlock(&clnt->cl_lock);
839} 833}
840EXPORT_SYMBOL_GPL(rpc_killall_tasks); 834EXPORT_SYMBOL_GPL(rpc_killall_tasks);
@@ -1477,8 +1471,6 @@ EXPORT_SYMBOL_GPL(rpc_force_rebind);
1477int 1471int
1478rpc_restart_call_prepare(struct rpc_task *task) 1472rpc_restart_call_prepare(struct rpc_task *task)
1479{ 1473{
1480 if (RPC_ASSASSINATED(task))
1481 return 0;
1482 task->tk_action = call_start; 1474 task->tk_action = call_start;
1483 task->tk_status = 0; 1475 task->tk_status = 0;
1484 if (task->tk_ops->rpc_call_prepare != NULL) 1476 if (task->tk_ops->rpc_call_prepare != NULL)
@@ -1494,8 +1486,6 @@ EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
1494int 1486int
1495rpc_restart_call(struct rpc_task *task) 1487rpc_restart_call(struct rpc_task *task)
1496{ 1488{
1497 if (RPC_ASSASSINATED(task))
1498 return 0;
1499 task->tk_action = call_start; 1489 task->tk_action = call_start;
1500 task->tk_status = 0; 1490 task->tk_status = 0;
1501 return 1; 1491 return 1;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 28956c70100a..3d6cb91ba598 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -759,8 +759,7 @@ static void
759rpc_reset_task_statistics(struct rpc_task *task) 759rpc_reset_task_statistics(struct rpc_task *task)
760{ 760{
761 task->tk_timeouts = 0; 761 task->tk_timeouts = 0;
762 task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_KILLED|RPC_TASK_SENT); 762 task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_SENT);
763
764 rpc_init_task_statistics(task); 763 rpc_init_task_statistics(task);
765} 764}
766 765
@@ -773,7 +772,6 @@ void rpc_exit_task(struct rpc_task *task)
773 if (task->tk_ops->rpc_call_done != NULL) { 772 if (task->tk_ops->rpc_call_done != NULL) {
774 task->tk_ops->rpc_call_done(task, task->tk_calldata); 773 task->tk_ops->rpc_call_done(task, task->tk_calldata);
775 if (task->tk_action != NULL) { 774 if (task->tk_action != NULL) {
776 WARN_ON(RPC_ASSASSINATED(task));
777 /* Always release the RPC slot and buffer memory */ 775 /* Always release the RPC slot and buffer memory */
778 xprt_release(task); 776 xprt_release(task);
779 rpc_reset_task_statistics(task); 777 rpc_reset_task_statistics(task);
@@ -781,6 +779,19 @@ void rpc_exit_task(struct rpc_task *task)
781 } 779 }
782} 780}
783 781
782void rpc_signal_task(struct rpc_task *task)
783{
784 struct rpc_wait_queue *queue;
785
786 if (!RPC_IS_ACTIVATED(task))
787 return;
788 set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate);
789 smp_mb__after_atomic();
790 queue = READ_ONCE(task->tk_waitqueue);
791 if (queue)
792 rpc_wake_up_queued_task_set_status(queue, task, -ERESTARTSYS);
793}
794
784void rpc_exit(struct rpc_task *task, int status) 795void rpc_exit(struct rpc_task *task, int status)
785{ 796{
786 task->tk_status = status; 797 task->tk_status = status;
@@ -836,6 +847,13 @@ static void __rpc_execute(struct rpc_task *task)
836 */ 847 */
837 if (!RPC_IS_QUEUED(task)) 848 if (!RPC_IS_QUEUED(task))
838 continue; 849 continue;
850
851 /*
852 * Signalled tasks should exit rather than sleep.
853 */
854 if (RPC_SIGNALLED(task))
855 rpc_exit(task, -ERESTARTSYS);
856
839 /* 857 /*
840 * The queue->lock protects against races with 858 * The queue->lock protects against races with
841 * rpc_make_runnable(). 859 * rpc_make_runnable().
@@ -861,7 +879,7 @@ static void __rpc_execute(struct rpc_task *task)
861 status = out_of_line_wait_on_bit(&task->tk_runstate, 879 status = out_of_line_wait_on_bit(&task->tk_runstate,
862 RPC_TASK_QUEUED, rpc_wait_bit_killable, 880 RPC_TASK_QUEUED, rpc_wait_bit_killable,
863 TASK_KILLABLE); 881 TASK_KILLABLE);
864 if (status == -ERESTARTSYS) { 882 if (status < 0) {
865 /* 883 /*
866 * When a sync task receives a signal, it exits with 884 * When a sync task receives a signal, it exits with
867 * -ERESTARTSYS. In order to catch any callbacks that 885 * -ERESTARTSYS. In order to catch any callbacks that
@@ -869,7 +887,7 @@ static void __rpc_execute(struct rpc_task *task)
869 * break the loop here, but go around once more. 887 * break the loop here, but go around once more.
870 */ 888 */
871 dprintk("RPC: %5u got signal\n", task->tk_pid); 889 dprintk("RPC: %5u got signal\n", task->tk_pid);
872 task->tk_flags |= RPC_TASK_KILLED; 890 set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate);
873 rpc_exit(task, -ERESTARTSYS); 891 rpc_exit(task, -ERESTARTSYS);
874 } 892 }
875 dprintk("RPC: %5u sync task resuming\n", task->tk_pid); 893 dprintk("RPC: %5u sync task resuming\n", task->tk_pid);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index d7117d241460..3a4156cb0134 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1337,6 +1337,10 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
1337 if (status < 0) 1337 if (status < 0)
1338 goto out_dequeue; 1338 goto out_dequeue;
1339 } 1339 }
1340 if (RPC_SIGNALLED(task)) {
1341 status = -ERESTARTSYS;
1342 goto out_dequeue;
1343 }
1340 } 1344 }
1341 1345
1342 /* 1346 /*