]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Patch-mainline: submitted 04aug2009 |
2 | References: bnc#498708 | |
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. | |
6 | ||
7 | The current practice of waiting for cache updates by queueing the | |
8 | whole request to be retried has (at least) two problems. | |
9 | ||
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 | |
12 | normal practice. | |
13 | ||
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. | |
16 | ||
17 | In many cases only a very sort wait is needed before the cache gets | |
18 | valid data. | |
19 | ||
20 | So, providing the underlying transport permits it by setting | |
21 | ->thread_wait, | |
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. | |
26 | ||
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. | |
29 | ||
30 | These values are probably much higher than needed, but will ensure | |
31 | some forward progress. | |
32 | ||
33 | Signed-off-by: NeilBrown <neilb@suse.de> | |
34 | ||
35 | --- | |
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(-) | |
40 | ||
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 { | |
44 | */ | |
45 | struct cache_req { | |
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. | |
49 | + */ | |
50 | }; | |
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; | |
58 | ||
59 | +struct thread_deferred_req { | |
60 | + struct cache_deferred_req handle; | |
61 | + wait_queue_head_t wait; | |
62 | +}; | |
63 | +static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many) | |
64 | +{ | |
65 | + struct thread_deferred_req *dr = | |
66 | + container_of(dreq, struct thread_deferred_req, handle); | |
67 | + wake_up(&dr->wait); | |
68 | +} | |
69 | + | |
70 | static int cache_defer_req(struct cache_req *req, struct cache_head *item) | |
71 | { | |
72 | struct cache_deferred_req *dreq, *discard; | |
73 | int hash = DFR_HASH(item); | |
74 | + struct thread_deferred_req sleeper; | |
75 | ||
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_ | |
79 | if (net_random()&1) | |
80 | return 0; | |
81 | } | |
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; | |
87 | + } else | |
88 | + dreq = req->defer(req); | |
89 | + | |
90 | + retry: | |
91 | if (dreq == NULL) | |
92 | return 0; | |
93 | ||
94 | @@ -606,6 +625,29 @@ static int cache_defer_req(struct cache_ | |
95 | cache_revisit_request(item); | |
96 | return 0; | |
97 | } | |
98 | + | |
99 | + if (dreq == &sleeper.handle) { | |
100 | + wait_event_interruptible_timeout( | |
101 | + sleeper.wait, | |
102 | + !test_bit(CACHE_PENDING, &item->flags) | |
103 | + || list_empty(&sleeper.handle.hash), | |
104 | + req->thread_wait); | |
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); | |
109 | + cache_defer_cnt--; | |
110 | + } | |
111 | + spin_unlock(&cache_defer_lock); | |
112 | + if (test_bit(CACHE_PENDING, &item->flags)) { | |
113 | + /* item is still pending, try request | |
114 | + * deferral | |
115 | + */ | |
116 | + dreq = req->defer(req); | |
117 | + goto retry; | |
118 | + } | |
119 | + return 0; | |
120 | + } | |
121 | return 1; | |
122 | } | |
123 | ||
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 | |
127 | return -EINTR; | |
128 | ||
129 | spin_lock_bh(&pool->sp_lock); | |
130 | + | |
131 | + /* Normally we will wait up to 5 seconds for any required | |
132 | + * cache information to be provided. | |
133 | + */ | |
134 | + rqstp->rq_chandle.thread_wait = 5*HZ; | |
135 | xprt = svc_xprt_dequeue(pool); | |
136 | if (xprt) { | |
137 | rqstp->rq_xprt = xprt; | |
138 | svc_xprt_get(xprt); | |
139 | rqstp->rq_reserved = serv->sv_max_mesg; | |
140 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); | |
141 | + | |
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. | |
145 | + */ | |
146 | + rqstp->rq_chandle.thread_wait = 1*HZ; | |
147 | } else { | |
148 | /* No data pending. Go to sleep */ | |
149 | svc_thread_enqueue(pool, rqstp); |