diff options
Diffstat (limited to 'fs/lockd/host.c')
-rw-r--r-- | fs/lockd/host.c | 410 |
1 files changed, 246 insertions, 164 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index ed0c59fe23ce..b7c99bfb3da6 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -25,9 +25,22 @@ | |||
25 | #define NLM_HOST_EXPIRE (300 * HZ) | 25 | #define NLM_HOST_EXPIRE (300 * HZ) |
26 | #define NLM_HOST_COLLECT (120 * HZ) | 26 | #define NLM_HOST_COLLECT (120 * HZ) |
27 | 27 | ||
28 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; | 28 | static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; |
29 | static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; | ||
30 | |||
31 | #define for_each_host(host, pos, chain, table) \ | ||
32 | for ((chain) = (table); \ | ||
33 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | ||
34 | hlist_for_each_entry((host), (pos), (chain), h_hash) | ||
35 | |||
36 | #define for_each_host_safe(host, pos, next, chain, table) \ | ||
37 | for ((chain) = (table); \ | ||
38 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | ||
39 | hlist_for_each_entry_safe((host), (pos), (next), \ | ||
40 | (chain), h_hash) | ||
41 | |||
29 | static unsigned long next_gc; | 42 | static unsigned long next_gc; |
30 | static int nrhosts; | 43 | static unsigned long nrhosts; |
31 | static DEFINE_MUTEX(nlm_host_mutex); | 44 | static DEFINE_MUTEX(nlm_host_mutex); |
32 | 45 | ||
33 | static void nlm_gc_hosts(void); | 46 | static void nlm_gc_hosts(void); |
@@ -40,8 +53,6 @@ struct nlm_lookup_host_info { | |||
40 | const u32 version; /* NLM version to search for */ | 53 | const u32 version; /* NLM version to search for */ |
41 | const char *hostname; /* remote's hostname */ | 54 | const char *hostname; /* remote's hostname */ |
42 | const size_t hostname_len; /* it's length */ | 55 | const size_t hostname_len; /* it's length */ |
43 | const struct sockaddr *src_sap; /* our address (optional) */ | ||
44 | const size_t src_len; /* it's length */ | ||
45 | const int noresvport; /* use non-priv port */ | 56 | const int noresvport; /* use non-priv port */ |
46 | }; | 57 | }; |
47 | 58 | ||
@@ -88,127 +99,83 @@ static unsigned int nlm_hash_address(const struct sockaddr *sap) | |||
88 | } | 99 | } |
89 | 100 | ||
90 | /* | 101 | /* |
91 | * Common host lookup routine for server & client | 102 | * Allocate and initialize an nlm_host. Common to both client and server. |
92 | */ | 103 | */ |
93 | static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | 104 | static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, |
105 | struct nsm_handle *nsm) | ||
94 | { | 106 | { |
95 | struct hlist_head *chain; | 107 | struct nlm_host *host = NULL; |
96 | struct hlist_node *pos; | 108 | unsigned long now = jiffies; |
97 | struct nlm_host *host; | ||
98 | struct nsm_handle *nsm = NULL; | ||
99 | |||
100 | mutex_lock(&nlm_host_mutex); | ||
101 | |||
102 | if (time_after_eq(jiffies, next_gc)) | ||
103 | nlm_gc_hosts(); | ||
104 | |||
105 | /* We may keep several nlm_host objects for a peer, because each | ||
106 | * nlm_host is identified by | ||
107 | * (address, protocol, version, server/client) | ||
108 | * We could probably simplify this a little by putting all those | ||
109 | * different NLM rpc_clients into one single nlm_host object. | ||
110 | * This would allow us to have one nlm_host per address. | ||
111 | */ | ||
112 | chain = &nlm_hosts[nlm_hash_address(ni->sap)]; | ||
113 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
114 | if (!rpc_cmp_addr(nlm_addr(host), ni->sap)) | ||
115 | continue; | ||
116 | |||
117 | /* See if we have an NSM handle for this client */ | ||
118 | if (!nsm) | ||
119 | nsm = host->h_nsmhandle; | ||
120 | |||
121 | if (host->h_proto != ni->protocol) | ||
122 | continue; | ||
123 | if (host->h_version != ni->version) | ||
124 | continue; | ||
125 | if (host->h_server != ni->server) | ||
126 | continue; | ||
127 | if (ni->server && ni->src_len != 0 && | ||
128 | !rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap)) | ||
129 | continue; | ||
130 | |||
131 | /* Move to head of hash chain. */ | ||
132 | hlist_del(&host->h_hash); | ||
133 | hlist_add_head(&host->h_hash, chain); | ||
134 | |||
135 | nlm_get_host(host); | ||
136 | dprintk("lockd: nlm_lookup_host found host %s (%s)\n", | ||
137 | host->h_name, host->h_addrbuf); | ||
138 | goto out; | ||
139 | } | ||
140 | 109 | ||
141 | /* | 110 | if (nsm != NULL) |
142 | * The host wasn't in our hash table. If we don't | ||
143 | * have an NSM handle for it yet, create one. | ||
144 | */ | ||
145 | if (nsm) | ||
146 | atomic_inc(&nsm->sm_count); | 111 | atomic_inc(&nsm->sm_count); |
147 | else { | 112 | else { |
148 | host = NULL; | 113 | host = NULL; |
149 | nsm = nsm_get_handle(ni->sap, ni->salen, | 114 | nsm = nsm_get_handle(ni->sap, ni->salen, |
150 | ni->hostname, ni->hostname_len); | 115 | ni->hostname, ni->hostname_len); |
151 | if (!nsm) { | 116 | if (unlikely(nsm == NULL)) { |
152 | dprintk("lockd: nlm_lookup_host failed; " | 117 | dprintk("lockd: %s failed; no nsm handle\n", |
153 | "no nsm handle\n"); | 118 | __func__); |
154 | goto out; | 119 | goto out; |
155 | } | 120 | } |
156 | } | 121 | } |
157 | 122 | ||
158 | host = kzalloc(sizeof(*host), GFP_KERNEL); | 123 | host = kmalloc(sizeof(*host), GFP_KERNEL); |
159 | if (!host) { | 124 | if (unlikely(host == NULL)) { |
125 | dprintk("lockd: %s failed; no memory\n", __func__); | ||
160 | nsm_release(nsm); | 126 | nsm_release(nsm); |
161 | dprintk("lockd: nlm_lookup_host failed; no memory\n"); | ||
162 | goto out; | 127 | goto out; |
163 | } | 128 | } |
164 | host->h_name = nsm->sm_name; | 129 | |
165 | host->h_addrbuf = nsm->sm_addrbuf; | ||
166 | memcpy(nlm_addr(host), ni->sap, ni->salen); | 130 | memcpy(nlm_addr(host), ni->sap, ni->salen); |
167 | host->h_addrlen = ni->salen; | 131 | host->h_addrlen = ni->salen; |
168 | rpc_set_port(nlm_addr(host), 0); | 132 | rpc_set_port(nlm_addr(host), 0); |
169 | memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len); | 133 | host->h_srcaddrlen = 0; |
170 | host->h_srcaddrlen = ni->src_len; | 134 | |
135 | host->h_rpcclnt = NULL; | ||
136 | host->h_name = nsm->sm_name; | ||
171 | host->h_version = ni->version; | 137 | host->h_version = ni->version; |
172 | host->h_proto = ni->protocol; | 138 | host->h_proto = ni->protocol; |
173 | host->h_rpcclnt = NULL; | 139 | host->h_reclaiming = 0; |
174 | mutex_init(&host->h_mutex); | 140 | host->h_server = ni->server; |
175 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 141 | host->h_noresvport = ni->noresvport; |
176 | host->h_expires = jiffies + NLM_HOST_EXPIRE; | 142 | host->h_inuse = 0; |
177 | atomic_set(&host->h_count, 1); | ||
178 | init_waitqueue_head(&host->h_gracewait); | 143 | init_waitqueue_head(&host->h_gracewait); |
179 | init_rwsem(&host->h_rwsem); | 144 | init_rwsem(&host->h_rwsem); |
180 | host->h_state = 0; /* pseudo NSM state */ | 145 | host->h_state = 0; |
181 | host->h_nsmstate = 0; /* real NSM state */ | 146 | host->h_nsmstate = 0; |
182 | host->h_nsmhandle = nsm; | 147 | host->h_pidcount = 0; |
183 | host->h_server = ni->server; | 148 | atomic_set(&host->h_count, 1); |
184 | host->h_noresvport = ni->noresvport; | 149 | mutex_init(&host->h_mutex); |
185 | hlist_add_head(&host->h_hash, chain); | 150 | host->h_nextrebind = now + NLM_HOST_REBIND; |
151 | host->h_expires = now + NLM_HOST_EXPIRE; | ||
186 | INIT_LIST_HEAD(&host->h_lockowners); | 152 | INIT_LIST_HEAD(&host->h_lockowners); |
187 | spin_lock_init(&host->h_lock); | 153 | spin_lock_init(&host->h_lock); |
188 | INIT_LIST_HEAD(&host->h_granted); | 154 | INIT_LIST_HEAD(&host->h_granted); |
189 | INIT_LIST_HEAD(&host->h_reclaim); | 155 | INIT_LIST_HEAD(&host->h_reclaim); |
190 | 156 | host->h_nsmhandle = nsm; | |
191 | nrhosts++; | 157 | host->h_addrbuf = nsm->sm_addrbuf; |
192 | |||
193 | dprintk("lockd: nlm_lookup_host created host %s\n", | ||
194 | host->h_name); | ||
195 | 158 | ||
196 | out: | 159 | out: |
197 | mutex_unlock(&nlm_host_mutex); | ||
198 | return host; | 160 | return host; |
199 | } | 161 | } |
200 | 162 | ||
201 | /* | 163 | /* |
202 | * Destroy a host | 164 | * Destroy an nlm_host and free associated resources |
165 | * | ||
166 | * Caller must hold nlm_host_mutex. | ||
203 | */ | 167 | */ |
204 | static void | 168 | static void nlm_destroy_host_locked(struct nlm_host *host) |
205 | nlm_destroy_host(struct nlm_host *host) | ||
206 | { | 169 | { |
207 | struct rpc_clnt *clnt; | 170 | struct rpc_clnt *clnt; |
208 | 171 | ||
172 | dprintk("lockd: destroy host %s\n", host->h_name); | ||
173 | |||
209 | BUG_ON(!list_empty(&host->h_lockowners)); | 174 | BUG_ON(!list_empty(&host->h_lockowners)); |
210 | BUG_ON(atomic_read(&host->h_count)); | 175 | BUG_ON(atomic_read(&host->h_count)); |
211 | 176 | ||
177 | hlist_del_init(&host->h_hash); | ||
178 | |||
212 | nsm_unmonitor(host); | 179 | nsm_unmonitor(host); |
213 | nsm_release(host->h_nsmhandle); | 180 | nsm_release(host->h_nsmhandle); |
214 | 181 | ||
@@ -216,6 +183,8 @@ nlm_destroy_host(struct nlm_host *host) | |||
216 | if (clnt != NULL) | 183 | if (clnt != NULL) |
217 | rpc_shutdown_client(clnt); | 184 | rpc_shutdown_client(clnt); |
218 | kfree(host); | 185 | kfree(host); |
186 | |||
187 | nrhosts--; | ||
219 | } | 188 | } |
220 | 189 | ||
221 | /** | 190 | /** |
@@ -249,12 +218,76 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
249 | .hostname_len = strlen(hostname), | 218 | .hostname_len = strlen(hostname), |
250 | .noresvport = noresvport, | 219 | .noresvport = noresvport, |
251 | }; | 220 | }; |
221 | struct hlist_head *chain; | ||
222 | struct hlist_node *pos; | ||
223 | struct nlm_host *host; | ||
224 | struct nsm_handle *nsm = NULL; | ||
252 | 225 | ||
253 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, | 226 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, |
254 | (hostname ? hostname : "<none>"), version, | 227 | (hostname ? hostname : "<none>"), version, |
255 | (protocol == IPPROTO_UDP ? "udp" : "tcp")); | 228 | (protocol == IPPROTO_UDP ? "udp" : "tcp")); |
256 | 229 | ||
257 | return nlm_lookup_host(&ni); | 230 | mutex_lock(&nlm_host_mutex); |
231 | |||
232 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; | ||
233 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
234 | if (!rpc_cmp_addr(nlm_addr(host), sap)) | ||
235 | continue; | ||
236 | |||
237 | /* Same address. Share an NSM handle if we already have one */ | ||
238 | if (nsm == NULL) | ||
239 | nsm = host->h_nsmhandle; | ||
240 | |||
241 | if (host->h_proto != protocol) | ||
242 | continue; | ||
243 | if (host->h_version != version) | ||
244 | continue; | ||
245 | |||
246 | nlm_get_host(host); | ||
247 | dprintk("lockd: %s found host %s (%s)\n", __func__, | ||
248 | host->h_name, host->h_addrbuf); | ||
249 | goto out; | ||
250 | } | ||
251 | |||
252 | host = nlm_alloc_host(&ni, nsm); | ||
253 | if (unlikely(host == NULL)) | ||
254 | goto out; | ||
255 | |||
256 | hlist_add_head(&host->h_hash, chain); | ||
257 | nrhosts++; | ||
258 | |||
259 | dprintk("lockd: %s created host %s (%s)\n", __func__, | ||
260 | host->h_name, host->h_addrbuf); | ||
261 | |||
262 | out: | ||
263 | mutex_unlock(&nlm_host_mutex); | ||
264 | return host; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * nlmclnt_release_host - release client nlm_host | ||
269 | * @host: nlm_host to release | ||
270 | * | ||
271 | */ | ||
272 | void nlmclnt_release_host(struct nlm_host *host) | ||
273 | { | ||
274 | if (host == NULL) | ||
275 | return; | ||
276 | |||
277 | dprintk("lockd: release client host %s\n", host->h_name); | ||
278 | |||
279 | BUG_ON(atomic_read(&host->h_count) < 0); | ||
280 | BUG_ON(host->h_server); | ||
281 | |||
282 | if (atomic_dec_and_test(&host->h_count)) { | ||
283 | BUG_ON(!list_empty(&host->h_lockowners)); | ||
284 | BUG_ON(!list_empty(&host->h_granted)); | ||
285 | BUG_ON(!list_empty(&host->h_reclaim)); | ||
286 | |||
287 | mutex_lock(&nlm_host_mutex); | ||
288 | nlm_destroy_host_locked(host); | ||
289 | mutex_unlock(&nlm_host_mutex); | ||
290 | } | ||
258 | } | 291 | } |
259 | 292 | ||
260 | /** | 293 | /** |
@@ -279,12 +312,18 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
279 | const char *hostname, | 312 | const char *hostname, |
280 | const size_t hostname_len) | 313 | const size_t hostname_len) |
281 | { | 314 | { |
315 | struct hlist_head *chain; | ||
316 | struct hlist_node *pos; | ||
317 | struct nlm_host *host = NULL; | ||
318 | struct nsm_handle *nsm = NULL; | ||
282 | struct sockaddr_in sin = { | 319 | struct sockaddr_in sin = { |
283 | .sin_family = AF_INET, | 320 | .sin_family = AF_INET, |
284 | }; | 321 | }; |
285 | struct sockaddr_in6 sin6 = { | 322 | struct sockaddr_in6 sin6 = { |
286 | .sin6_family = AF_INET6, | 323 | .sin6_family = AF_INET6, |
287 | }; | 324 | }; |
325 | struct sockaddr *src_sap; | ||
326 | size_t src_len = rqstp->rq_addrlen; | ||
288 | struct nlm_lookup_host_info ni = { | 327 | struct nlm_lookup_host_info ni = { |
289 | .server = 1, | 328 | .server = 1, |
290 | .sap = svc_addr(rqstp), | 329 | .sap = svc_addr(rqstp), |
@@ -293,27 +332,91 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
293 | .version = rqstp->rq_vers, | 332 | .version = rqstp->rq_vers, |
294 | .hostname = hostname, | 333 | .hostname = hostname, |
295 | .hostname_len = hostname_len, | 334 | .hostname_len = hostname_len, |
296 | .src_len = rqstp->rq_addrlen, | ||
297 | }; | 335 | }; |
298 | 336 | ||
299 | dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, | 337 | dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, |
300 | (int)hostname_len, hostname, rqstp->rq_vers, | 338 | (int)hostname_len, hostname, rqstp->rq_vers, |
301 | (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp")); | 339 | (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp")); |
302 | 340 | ||
341 | mutex_lock(&nlm_host_mutex); | ||
342 | |||
303 | switch (ni.sap->sa_family) { | 343 | switch (ni.sap->sa_family) { |
304 | case AF_INET: | 344 | case AF_INET: |
305 | sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; | 345 | sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; |
306 | ni.src_sap = (struct sockaddr *)&sin; | 346 | src_sap = (struct sockaddr *)&sin; |
307 | break; | 347 | break; |
308 | case AF_INET6: | 348 | case AF_INET6: |
309 | ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); | 349 | ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); |
310 | ni.src_sap = (struct sockaddr *)&sin6; | 350 | src_sap = (struct sockaddr *)&sin6; |
311 | break; | 351 | break; |
312 | default: | 352 | default: |
313 | return NULL; | 353 | dprintk("lockd: %s failed; unrecognized address family\n", |
354 | __func__); | ||
355 | goto out; | ||
314 | } | 356 | } |
315 | 357 | ||
316 | return nlm_lookup_host(&ni); | 358 | if (time_after_eq(jiffies, next_gc)) |
359 | nlm_gc_hosts(); | ||
360 | |||
361 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; | ||
362 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
363 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) | ||
364 | continue; | ||
365 | |||
366 | /* Same address. Share an NSM handle if we already have one */ | ||
367 | if (nsm == NULL) | ||
368 | nsm = host->h_nsmhandle; | ||
369 | |||
370 | if (host->h_proto != ni.protocol) | ||
371 | continue; | ||
372 | if (host->h_version != ni.version) | ||
373 | continue; | ||
374 | if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap)) | ||
375 | continue; | ||
376 | |||
377 | /* Move to head of hash chain. */ | ||
378 | hlist_del(&host->h_hash); | ||
379 | hlist_add_head(&host->h_hash, chain); | ||
380 | |||
381 | nlm_get_host(host); | ||
382 | dprintk("lockd: %s found host %s (%s)\n", | ||
383 | __func__, host->h_name, host->h_addrbuf); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | host = nlm_alloc_host(&ni, nsm); | ||
388 | if (unlikely(host == NULL)) | ||
389 | goto out; | ||
390 | |||
391 | memcpy(nlm_srcaddr(host), src_sap, src_len); | ||
392 | host->h_srcaddrlen = src_len; | ||
393 | hlist_add_head(&host->h_hash, chain); | ||
394 | nrhosts++; | ||
395 | |||
396 | dprintk("lockd: %s created host %s (%s)\n", | ||
397 | __func__, host->h_name, host->h_addrbuf); | ||
398 | |||
399 | out: | ||
400 | mutex_unlock(&nlm_host_mutex); | ||
401 | return host; | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * nlmsvc_release_host - release server nlm_host | ||
406 | * @host: nlm_host to release | ||
407 | * | ||
408 | * Host is destroyed later in nlm_gc_host(). | ||
409 | */ | ||
410 | void nlmsvc_release_host(struct nlm_host *host) | ||
411 | { | ||
412 | if (host == NULL) | ||
413 | return; | ||
414 | |||
415 | dprintk("lockd: release server host %s\n", host->h_name); | ||
416 | |||
417 | BUG_ON(atomic_read(&host->h_count) < 0); | ||
418 | BUG_ON(!host->h_server); | ||
419 | atomic_dec(&host->h_count); | ||
317 | } | 420 | } |
318 | 421 | ||
319 | /* | 422 | /* |
@@ -413,20 +516,29 @@ struct nlm_host * nlm_get_host(struct nlm_host *host) | |||
413 | return host; | 516 | return host; |
414 | } | 517 | } |
415 | 518 | ||
416 | /* | 519 | static struct nlm_host *next_host_state(struct hlist_head *cache, |
417 | * Release NLM host after use | 520 | struct nsm_handle *nsm, |
418 | */ | 521 | const struct nlm_reboot *info) |
419 | void nlm_release_host(struct nlm_host *host) | ||
420 | { | 522 | { |
421 | if (host != NULL) { | 523 | struct nlm_host *host; |
422 | dprintk("lockd: release host %s\n", host->h_name); | 524 | struct hlist_head *chain; |
423 | BUG_ON(atomic_read(&host->h_count) < 0); | 525 | struct hlist_node *pos; |
424 | if (atomic_dec_and_test(&host->h_count)) { | 526 | |
425 | BUG_ON(!list_empty(&host->h_lockowners)); | 527 | mutex_lock(&nlm_host_mutex); |
426 | BUG_ON(!list_empty(&host->h_granted)); | 528 | for_each_host(host, pos, chain, cache) { |
427 | BUG_ON(!list_empty(&host->h_reclaim)); | 529 | if (host->h_nsmhandle == nsm |
530 | && host->h_nsmstate != info->state) { | ||
531 | host->h_nsmstate = info->state; | ||
532 | host->h_state++; | ||
533 | |||
534 | nlm_get_host(host); | ||
535 | mutex_unlock(&nlm_host_mutex); | ||
536 | return host; | ||
428 | } | 537 | } |
429 | } | 538 | } |
539 | |||
540 | mutex_unlock(&nlm_host_mutex); | ||
541 | return NULL; | ||
430 | } | 542 | } |
431 | 543 | ||
432 | /** | 544 | /** |
@@ -438,8 +550,6 @@ void nlm_release_host(struct nlm_host *host) | |||
438 | */ | 550 | */ |
439 | void nlm_host_rebooted(const struct nlm_reboot *info) | 551 | void nlm_host_rebooted(const struct nlm_reboot *info) |
440 | { | 552 | { |
441 | struct hlist_head *chain; | ||
442 | struct hlist_node *pos; | ||
443 | struct nsm_handle *nsm; | 553 | struct nsm_handle *nsm; |
444 | struct nlm_host *host; | 554 | struct nlm_host *host; |
445 | 555 | ||
@@ -452,32 +562,15 @@ void nlm_host_rebooted(const struct nlm_reboot *info) | |||
452 | * lock for this. | 562 | * lock for this. |
453 | * To avoid processing a host several times, we match the nsmstate. | 563 | * To avoid processing a host several times, we match the nsmstate. |
454 | */ | 564 | */ |
455 | again: mutex_lock(&nlm_host_mutex); | 565 | while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) { |
456 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 566 | nlmsvc_free_host_resources(host); |
457 | hlist_for_each_entry(host, pos, chain, h_hash) { | 567 | nlmsvc_release_host(host); |
458 | if (host->h_nsmhandle == nsm | ||
459 | && host->h_nsmstate != info->state) { | ||
460 | host->h_nsmstate = info->state; | ||
461 | host->h_state++; | ||
462 | |||
463 | nlm_get_host(host); | ||
464 | mutex_unlock(&nlm_host_mutex); | ||
465 | |||
466 | if (host->h_server) { | ||
467 | /* We're server for this guy, just ditch | ||
468 | * all the locks he held. */ | ||
469 | nlmsvc_free_host_resources(host); | ||
470 | } else { | ||
471 | /* He's the server, initiate lock recovery. */ | ||
472 | nlmclnt_recovery(host); | ||
473 | } | ||
474 | |||
475 | nlm_release_host(host); | ||
476 | goto again; | ||
477 | } | ||
478 | } | ||
479 | } | 568 | } |
480 | mutex_unlock(&nlm_host_mutex); | 569 | while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) { |
570 | nlmclnt_recovery(host); | ||
571 | nlmclnt_release_host(host); | ||
572 | } | ||
573 | |||
481 | nsm_release(nsm); | 574 | nsm_release(nsm); |
482 | } | 575 | } |
483 | 576 | ||
@@ -497,13 +590,11 @@ nlm_shutdown_hosts(void) | |||
497 | 590 | ||
498 | /* First, make all hosts eligible for gc */ | 591 | /* First, make all hosts eligible for gc */ |
499 | dprintk("lockd: nuking all hosts...\n"); | 592 | dprintk("lockd: nuking all hosts...\n"); |
500 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 593 | for_each_host(host, pos, chain, nlm_server_hosts) { |
501 | hlist_for_each_entry(host, pos, chain, h_hash) { | 594 | host->h_expires = jiffies - 1; |
502 | host->h_expires = jiffies - 1; | 595 | if (host->h_rpcclnt) { |
503 | if (host->h_rpcclnt) { | 596 | rpc_shutdown_client(host->h_rpcclnt); |
504 | rpc_shutdown_client(host->h_rpcclnt); | 597 | host->h_rpcclnt = NULL; |
505 | host->h_rpcclnt = NULL; | ||
506 | } | ||
507 | } | 598 | } |
508 | } | 599 | } |
509 | 600 | ||
@@ -512,15 +603,13 @@ nlm_shutdown_hosts(void) | |||
512 | mutex_unlock(&nlm_host_mutex); | 603 | mutex_unlock(&nlm_host_mutex); |
513 | 604 | ||
514 | /* complain if any hosts are left */ | 605 | /* complain if any hosts are left */ |
515 | if (nrhosts) { | 606 | if (nrhosts != 0) { |
516 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); | 607 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); |
517 | dprintk("lockd: %d hosts left:\n", nrhosts); | 608 | dprintk("lockd: %lu hosts left:\n", nrhosts); |
518 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 609 | for_each_host(host, pos, chain, nlm_server_hosts) { |
519 | hlist_for_each_entry(host, pos, chain, h_hash) { | 610 | dprintk(" %s (cnt %d use %d exp %ld)\n", |
520 | dprintk(" %s (cnt %d use %d exp %ld)\n", | 611 | host->h_name, atomic_read(&host->h_count), |
521 | host->h_name, atomic_read(&host->h_count), | 612 | host->h_inuse, host->h_expires); |
522 | host->h_inuse, host->h_expires); | ||
523 | } | ||
524 | } | 613 | } |
525 | } | 614 | } |
526 | } | 615 | } |
@@ -538,29 +627,22 @@ nlm_gc_hosts(void) | |||
538 | struct nlm_host *host; | 627 | struct nlm_host *host; |
539 | 628 | ||
540 | dprintk("lockd: host garbage collection\n"); | 629 | dprintk("lockd: host garbage collection\n"); |
541 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 630 | for_each_host(host, pos, chain, nlm_server_hosts) |
542 | hlist_for_each_entry(host, pos, chain, h_hash) | 631 | host->h_inuse = 0; |
543 | host->h_inuse = 0; | ||
544 | } | ||
545 | 632 | ||
546 | /* Mark all hosts that hold locks, blocks or shares */ | 633 | /* Mark all hosts that hold locks, blocks or shares */ |
547 | nlmsvc_mark_resources(); | 634 | nlmsvc_mark_resources(); |
548 | 635 | ||
549 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 636 | for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { |
550 | hlist_for_each_entry_safe(host, pos, next, chain, h_hash) { | 637 | if (atomic_read(&host->h_count) || host->h_inuse |
551 | if (atomic_read(&host->h_count) || host->h_inuse | 638 | || time_before(jiffies, host->h_expires)) { |
552 | || time_before(jiffies, host->h_expires)) { | 639 | dprintk("nlm_gc_hosts skipping %s " |
553 | dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", | 640 | "(cnt %d use %d exp %ld)\n", |
554 | host->h_name, atomic_read(&host->h_count), | 641 | host->h_name, atomic_read(&host->h_count), |
555 | host->h_inuse, host->h_expires); | 642 | host->h_inuse, host->h_expires); |
556 | continue; | 643 | continue; |
557 | } | ||
558 | dprintk("lockd: delete host %s\n", host->h_name); | ||
559 | hlist_del_init(&host->h_hash); | ||
560 | |||
561 | nlm_destroy_host(host); | ||
562 | nrhosts--; | ||
563 | } | 644 | } |
645 | nlm_destroy_host_locked(host); | ||
564 | } | 646 | } |
565 | 647 | ||
566 | next_gc = jiffies + NLM_HOST_COLLECT; | 648 | next_gc = jiffies + NLM_HOST_COLLECT; |