summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2008-02-07 16:34:54 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2008-04-23 16:13:36 -0400
commit7086721f9c8b59331e164e534f588e075cfd9d3f (patch)
tree593ddc28b30dba189069579b82ed81996d965df2
parent23d42ee278de1552d67daef5774ba59ff30925db (diff)
SUNRPC: have svc_recv() check kthread_should_stop()
When using kthreads that call into svc_recv, we want to make sure that they do not block there for a long time when we're trying to take down the kthread. This patch changes svc_recv() to check kthread_should_stop() at the same places that it checks to see if it's signalled(). Also check just before svc_recv() tries to schedule(). By making sure that we check it just after setting the task state we can avoid having to use any locking or signalling to ensure it doesn't block for a long time. There's still a chance of a 500ms sleep if alloc_page() fails, but that should be a rare occurrence and isn't a terribly long time in the context of a kthread being taken down. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r--net/sunrpc/svc_xprt.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 332eb47539e..2e5d43c3914 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -18,6 +18,7 @@
#include <linux/skbuff.h>
#include <linux/file.h>
#include <linux/freezer.h>
+#include <linux/kthread.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <net/ip.h>
@@ -587,6 +588,8 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
struct page *p = alloc_page(GFP_KERNEL);
if (!p) {
int j = msecs_to_jiffies(500);
+ if (kthread_should_stop())
+ return -EINTR;
schedule_timeout_uninterruptible(j);
}
rqstp->rq_pages[i] = p;
@@ -607,7 +610,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
try_to_freeze();
cond_resched();
- if (signalled())
+ if (signalled() || kthread_should_stop())
return -EINTR;
spin_lock_bh(&pool->sp_lock);
@@ -626,6 +629,20 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
* to bring down the daemons ...
*/
set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * checking kthread_should_stop() here allows us to avoid
+ * locking and signalling when stopping kthreads that call
+ * svc_recv. If the thread has already been woken up, then
+ * we can exit here without sleeping. If not, then it
+ * it'll be woken up quickly during the schedule_timeout
+ */
+ if (kthread_should_stop()) {
+ set_current_state(TASK_RUNNING);
+ spin_unlock_bh(&pool->sp_lock);
+ return -EINTR;
+ }
+
add_wait_queue(&rqstp->rq_wait, &wait);
spin_unlock_bh(&pool->sp_lock);
@@ -641,7 +658,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
svc_thread_dequeue(pool, rqstp);
spin_unlock_bh(&pool->sp_lock);
dprintk("svc: server %p, no data yet\n", rqstp);
- return signalled()? -EINTR : -EAGAIN;
+ if (signalled() || kthread_should_stop())
+ return -EINTR;
+ else
+ return -EAGAIN;
}
}
spin_unlock_bh(&pool->sp_lock);