diff options
author | Jeff Layton <jlayton@redhat.com> | 2008-02-12 19:47:24 +0300 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-04-24 00:13:38 +0400 |
commit | 7b54fe61ffd5bfa4e50d371a2415225aa0cbb38e (patch) | |
tree | 6da4eb10c73ca75ff7cc94c11cfb11cd102447c4 /net | |
parent | 6aaa67b5f3b9fe24f0c76d0415cc72e5a1137bea (diff) | |
download | linux-7b54fe61ffd5bfa4e50d371a2415225aa0cbb38e.tar.xz |
SUNRPC: allow svc_recv to break out of 500ms sleep when alloc_page fails
svc_recv() calls alloc_page(), and if it fails it does a 500ms
uninterruptible sleep and then reattempts. There doesn't seem to be any
real reason for this to be uninterruptible, so change it to an
interruptible sleep. Also check for kthread_stop() and signalled() after
setting the task state to avoid races that might lead to sleeping after
kthread_stop() wakes up the task.
I've done some very basic smoke testing with this, but obviously it's
hard to test the actual changes since this all depends on an
alloc_page() call failing.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 2e5d43c39142..d8e8d79a8451 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -587,10 +587,12 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) while (rqstp->rq_pages[i] == NULL) { struct page *p = alloc_page(GFP_KERNEL); if (!p) { - int j = msecs_to_jiffies(500); - if (kthread_should_stop()) + set_current_state(TASK_INTERRUPTIBLE); + if (signalled() || kthread_should_stop()) { + set_current_state(TASK_RUNNING); return -EINTR; - schedule_timeout_uninterruptible(j); + } + schedule_timeout(msecs_to_jiffies(500)); } rqstp->rq_pages[i] = p; } |