Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 217203
b: refs/heads/master
c: f16b6e8
h: refs/heads/master
i:
  217201: 9586f94
  217199: ca8a83a
v: v3
  • Loading branch information
NeilBrown authored and J. Bruce Fields committed Sep 7, 2010
1 parent 56b9f79 commit 11715e2
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c5b29f885afe890f953f7f23424045cdad31d3e4
refs/heads/master: f16b6e8d838b2e2bb4561201311c66ac02ad67df
3 changes: 3 additions & 0 deletions trunk/include/linux/sunrpc/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ struct cache_detail {
*/
struct cache_req {
struct cache_deferred_req *(*defer)(struct cache_req *req);
int thread_wait; /* How long (jiffies) we can block the
* current thread to wait for updates.
*/
};
/* this must be embedded in a deferred_request that is being
* delayed awaiting cache-fill
Expand Down
59 changes: 58 additions & 1 deletion trunk/net/sunrpc/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,10 +509,22 @@ static LIST_HEAD(cache_defer_list);
static struct list_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;

struct thread_deferred_req {
struct cache_deferred_req handle;
struct completion completion;
};
static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
{
struct thread_deferred_req *dr =
container_of(dreq, struct thread_deferred_req, handle);
complete(&dr->completion);
}

static int cache_defer_req(struct cache_req *req, struct cache_head *item)
{
struct cache_deferred_req *dreq, *discard;
int hash = DFR_HASH(item);
struct thread_deferred_req sleeper;

if (cache_defer_cnt >= DFR_MAX) {
/* too much in the cache, randomly drop this one,
Expand All @@ -521,7 +533,15 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
if (net_random()&1)
return -ENOMEM;
}
dreq = req->defer(req);
if (req->thread_wait) {
dreq = &sleeper.handle;
sleeper.completion =
COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
dreq->revisit = cache_restart_thread;
} else
dreq = req->defer(req);

retry:
if (dreq == NULL)
return -ENOMEM;

Expand Down Expand Up @@ -555,6 +575,43 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
cache_revisit_request(item);
return -EAGAIN;
}

if (dreq == &sleeper.handle) {
if (wait_for_completion_interruptible_timeout(
&sleeper.completion, req->thread_wait) <= 0) {
/* The completion wasn't completed, so we need
* to clean up
*/
spin_lock(&cache_defer_lock);
if (!list_empty(&sleeper.handle.hash)) {
list_del_init(&sleeper.handle.recent);
list_del_init(&sleeper.handle.hash);
cache_defer_cnt--;
spin_unlock(&cache_defer_lock);
} else {
/* cache_revisit_request already removed
* this from the hash table, but hasn't
* called ->revisit yet. It will very soon
* and we need to wait for it.
*/
spin_unlock(&cache_defer_lock);
wait_for_completion(&sleeper.completion);
}
}
if (test_bit(CACHE_PENDING, &item->flags)) {
/* item is still pending, try request
* deferral
*/
dreq = req->defer(req);
goto retry;
}
/* only return success if we actually deferred the
* request. In this case we waited until it was
* answered so no deferral has happened - rather
* an answer already exists.
*/
return -EEXIST;
}
return 0;
}

Expand Down
11 changes: 11 additions & 0 deletions trunk/net/sunrpc/svc_xprt.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,13 +651,24 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
if (signalled() || kthread_should_stop())
return -EINTR;

/* Normally we will wait up to 5 seconds for any required
* cache information to be provided.
*/
rqstp->rq_chandle.thread_wait = 5*HZ;

spin_lock_bh(&pool->sp_lock);
xprt = svc_xprt_dequeue(pool);
if (xprt) {
rqstp->rq_xprt = xprt;
svc_xprt_get(xprt);
rqstp->rq_reserved = serv->sv_max_mesg;
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);

/* As there is a shortage of threads and this request
* had to be queue, don't allow the thread to wait so
* long for cache updates.
*/
rqstp->rq_chandle.thread_wait = 1*HZ;
} else {
/* No data pending. Go to sleep */
svc_thread_enqueue(pool, rqstp);
Expand Down

0 comments on commit 11715e2

Please sign in to comment.