aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/cache.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-09-21 22:55:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-10-01 18:09:54 -0400
commit277f68dbba397997c7f3dc843d14afa1654bb80e (patch)
tree7c9856840c40a3f08bef3a965a9f3c39937c9e99 /net/sunrpc/cache.c
parent14ec63c3336af7ea5445e0d8f4d26ba3041e40b3 (diff)
sunrpc: fix race in new cache_wait code.
If we set up to wait for a cache item to be filled in, and then find that it is no longer pending, it could be that some other thread is in 'cache_revisit_request' and has moved our request to its 'pending' list. So when our setup_deferral calls cache_revisit_request it will find nothing to put on the pending list, and do nothing. We then return from cache_wait_req, thus leaving the 'sleeper' on-stack structure open to being corrupted by subsequent stack usage. However that 'sleeper' could still be on the 'pending' list that the other thread is looking at and so any corruption could cause it to behave badly. To avoid this race we simply take the same path as if the 'wait_for_completion_interruptible_timeout' was interrupted and if the sleeper is no longer on the list (which it won't be) we wait on the completion - which will ensure that any other cache_revisit_request will have let go of the sleeper. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc/cache.c')
-rw-r--r--net/sunrpc/cache.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index e20968aac68a..1e72cc955931 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -578,10 +578,9 @@ static int cache_wait_req(struct cache_req *req, struct cache_head *item)
578 dreq->revisit = cache_restart_thread; 578 dreq->revisit = cache_restart_thread;
579 579
580 ret = setup_deferral(dreq, item); 580 ret = setup_deferral(dreq, item);
581 if (ret)
582 return ret;
583 581
584 if (wait_for_completion_interruptible_timeout( 582 if (ret ||
583 wait_for_completion_interruptible_timeout(
585 &sleeper.completion, req->thread_wait) <= 0) { 584 &sleeper.completion, req->thread_wait) <= 0) {
586 /* The completion wasn't completed, so we need 585 /* The completion wasn't completed, so we need
587 * to clean up 586 * to clean up