1 Patch-mainline: submitted 04aug2009
3 From: NeilBrown <neilb@suse.de>
4 Date: Tue, 4 Aug 2009 15:06:38 +1000
5 Subject: [PATCH 07/12] sunrpc/cache: allow thread to block while waiting for cache update.
7 The current practice of waiting for cache updates by queueing the
8 whole request to be retried has (at least) two problems.
10 1/ We NFSv4, requests can be quite complex and re-trying a whole
11 request when a later part fails should only be a list-resort, not a
14 2/ Large requests, and in particular any 'write' request, will not be
15 queued by the current code and doing so would be undesirable.
17 In many cases only a very sort wait is needed before the cache gets
20 So, providing the underlying transport permits it by setting
22 arrange to wait briefly for an upcall to be completed (as reflected in
23 the clearing of CACHE_PENDING).
24 If the short wait was not long enough and CACHE_PENDING is still set,
25 fall back on the old approach.
27 The 'thread_wait' value is set to 5 seconds when there are spare
28 threads, and 1 second when there are no spare threads.
30 These values are probably much higher than needed, but will ensure
31 some forward progress.
33 Signed-off-by: NeilBrown <neilb@suse.de>
36 include/linux/sunrpc/cache.h | 3 ++
37 net/sunrpc/cache.c | 44 ++++++++++++++++++++++++++++++++++++++++++-
38 net/sunrpc/svc_xprt.c | 11 ++++++++++
39 3 files changed, 57 insertions(+), 1 deletion(-)
41 --- linux-2.6.27-SLE11_BRANCH.orig/include/linux/sunrpc/cache.h
42 +++ linux-2.6.27-SLE11_BRANCH/include/linux/sunrpc/cache.h
43 @@ -112,6 +112,9 @@ struct cache_detail {
46 struct cache_deferred_req *(*defer)(struct cache_req *req);
47 + int thread_wait; /* How long (jiffies) we can block the
48 + * current thread to wait for updates.
51 /* this must be embedded in a deferred_request that is being
52 * delayed awaiting cache-fill
53 --- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c
54 +++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c
55 @@ -560,10 +560,22 @@ static LIST_HEAD(cache_defer_list);
56 static struct list_head cache_defer_hash[DFR_HASHSIZE];
57 static int cache_defer_cnt;
59 +struct thread_deferred_req {
60 + struct cache_deferred_req handle;
61 + wait_queue_head_t wait;
63 +static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
65 + struct thread_deferred_req *dr =
66 + container_of(dreq, struct thread_deferred_req, handle);
70 static int cache_defer_req(struct cache_req *req, struct cache_head *item)
72 struct cache_deferred_req *dreq, *discard;
73 int hash = DFR_HASH(item);
74 + struct thread_deferred_req sleeper;
76 if (cache_defer_cnt >= DFR_MAX) {
77 /* too much in the cache, randomly drop this one,
78 @@ -572,7 +584,14 @@ static int cache_defer_req(struct cache_
82 - dreq = req->defer(req);
83 + if (req->thread_wait) {
84 + dreq = &sleeper.handle;
85 + init_waitqueue_head(&sleeper.wait);
86 + dreq->revisit = cache_restart_thread;
88 + dreq = req->defer(req);
94 @@ -606,6 +625,29 @@ static int cache_defer_req(struct cache_
95 cache_revisit_request(item);
99 + if (dreq == &sleeper.handle) {
100 + wait_event_interruptible_timeout(
102 + !test_bit(CACHE_PENDING, &item->flags)
103 + || list_empty(&sleeper.handle.hash),
105 + spin_lock(&cache_defer_lock);
106 + if (!list_empty(&sleeper.handle.hash)) {
107 + list_del_init(&sleeper.handle.recent);
108 + list_del_init(&sleeper.handle.hash);
111 + spin_unlock(&cache_defer_lock);
112 + if (test_bit(CACHE_PENDING, &item->flags)) {
113 + /* item is still pending, try request
116 + dreq = req->defer(req);
124 --- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/svc_xprt.c
125 +++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/svc_xprt.c
126 @@ -593,12 +593,23 @@ int svc_recv(struct svc_rqst *rqstp, lon
129 spin_lock_bh(&pool->sp_lock);
131 + /* Normally we will wait up to 5 seconds for any required
132 + * cache information to be provided.
134 + rqstp->rq_chandle.thread_wait = 5*HZ;
135 xprt = svc_xprt_dequeue(pool);
137 rqstp->rq_xprt = xprt;
139 rqstp->rq_reserved = serv->sv_max_mesg;
140 atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
142 + /* As there is a shortage of threads and this request
143 + * had to be queue, don't allow the thread to wait so
144 + * long for cache updates.
146 + rqstp->rq_chandle.thread_wait = 1*HZ;
148 /* No data pending. Go to sleep */
149 svc_thread_enqueue(pool, rqstp);