aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/host.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-12-14 10:05:52 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-12-16 12:37:26 -0500
commit8ea6ecc8b0759756a766c05dc7c98c51ec90de37 (patch)
tree225f6f30c7f9a16b585dd38ee1b7f6b0646f990d /fs/lockd/host.c
parent7db836d4a427c3c64406b00b6d8d745d6335d72a (diff)
lockd: Create client-side nlm_host cache
NFS clients don't need the garbage collection processing that is performed on nlm_host structures. The client picks up an nlm_host at mount time and holds a reference to it until the file system is unmounted. Servers, on the other hand, don't have a precise way to tell when an nlm_host is no longer being used, so zero refcount nlm_host entries are left to expire in the cache after a time. Basically there's nothing holding a reference to an nlm_host between individual server-side NLM requests, but we can't afford the expense of recreating them for every new NLM request from a client. The nlm_host cache adds some lifetime hysteresis to entries in the cache so the next time a particular nlm_host is needed, it's likely to be discovered by a lookup rather than created from whole cloth. With the new implementation, client nlm_host cache items are no longer garbage collected, and are destroyed directly by a new release function specialized for client entries, nlmclnt_release_host(). They are cached in their own data structure, and have their own lookup logic, simplified and specialized for client nlm_host entries. However, the client nlm_host cache still shares reboot recovery logic with the server nlm_host cache. The NSM "peer rebooted" downcall for clients and servers still come through the same RPC call. This is a legacy formal API that would be difficult to alter, and besides, the user space NSM implementation can't tell the difference between peers that are clients or servers. For this reason, the client cache continues to share the nlm_host_mutex (and reboot recovery logic) with the server cache. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/lockd/host.c')
-rw-r--r--fs/lockd/host.c81
1 files changed, 72 insertions, 9 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index e58e1426d161..c6942fb4bd0d 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -26,6 +26,7 @@
26#define NLM_HOST_COLLECT (120 * HZ) 26#define NLM_HOST_COLLECT (120 * HZ)
27 27
28static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; 28static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
29static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH];
29 30
30#define for_each_host(host, pos, chain, table) \ 31#define for_each_host(host, pos, chain, table) \
31 for ((chain) = (table); \ 32 for ((chain) = (table); \
@@ -288,12 +289,76 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
288 .hostname_len = strlen(hostname), 289 .hostname_len = strlen(hostname),
289 .noresvport = noresvport, 290 .noresvport = noresvport,
290 }; 291 };
292 struct hlist_head *chain;
293 struct hlist_node *pos;
294 struct nlm_host *host;
295 struct nsm_handle *nsm = NULL;
291 296
292 dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, 297 dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
293 (hostname ? hostname : "<none>"), version, 298 (hostname ? hostname : "<none>"), version,
294 (protocol == IPPROTO_UDP ? "udp" : "tcp")); 299 (protocol == IPPROTO_UDP ? "udp" : "tcp"));
295 300
296 return nlm_lookup_host(&ni); 301 mutex_lock(&nlm_host_mutex);
302
303 chain = &nlm_client_hosts[nlm_hash_address(sap)];
304 hlist_for_each_entry(host, pos, chain, h_hash) {
305 if (!rpc_cmp_addr(nlm_addr(host), sap))
306 continue;
307
308 /* Same address. Share an NSM handle if we already have one */
309 if (nsm == NULL)
310 nsm = host->h_nsmhandle;
311
312 if (host->h_proto != protocol)
313 continue;
314 if (host->h_version != version)
315 continue;
316
317 nlm_get_host(host);
318 dprintk("lockd: %s found host %s (%s)\n", __func__,
319 host->h_name, host->h_addrbuf);
320 goto out;
321 }
322
323 host = nlm_alloc_host(&ni, nsm);
324 if (unlikely(host == NULL))
325 goto out;
326
327 hlist_add_head(&host->h_hash, chain);
328 nrhosts++;
329
330 dprintk("lockd: %s created host %s (%s)\n", __func__,
331 host->h_name, host->h_addrbuf);
332
333out:
334 mutex_unlock(&nlm_host_mutex);
335 return host;
336}
337
338/**
339 * nlmclnt_release_host - release client nlm_host
340 * @host: nlm_host to release
341 *
342 */
343void nlmclnt_release_host(struct nlm_host *host)
344{
345 if (host == NULL)
346 return;
347
348 dprintk("lockd: release client host %s\n", host->h_name);
349
350 BUG_ON(atomic_read(&host->h_count) < 0);
351 BUG_ON(host->h_server);
352
353 if (atomic_dec_and_test(&host->h_count)) {
354 BUG_ON(!list_empty(&host->h_lockowners));
355 BUG_ON(!list_empty(&host->h_granted));
356 BUG_ON(!list_empty(&host->h_reclaim));
357
358 mutex_lock(&nlm_host_mutex);
359 nlm_destroy_host_locked(host);
360 mutex_unlock(&nlm_host_mutex);
361 }
297} 362}
298 363
299/** 364/**
@@ -515,16 +580,14 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
515 * To avoid processing a host several times, we match the nsmstate. 580 * To avoid processing a host several times, we match the nsmstate.
516 */ 581 */
517 while ((host = next_host_state(nlm_hosts, nsm, info)) != NULL) { 582 while ((host = next_host_state(nlm_hosts, nsm, info)) != NULL) {
518 if (host->h_server) { 583 nlmsvc_free_host_resources(host);
519 /* We're server for this guy, just ditch
520 * all the locks he held. */
521 nlmsvc_free_host_resources(host);
522 } else {
523 /* He's the server, initiate lock recovery. */
524 nlmclnt_recovery(host);
525 }
526 nlm_release_host(host); 584 nlm_release_host(host);
527 } 585 }
586 while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
587 nlmclnt_recovery(host);
588 nlmclnt_release_host(host);
589 }
590
528 nsm_release(nsm); 591 nsm_release(nsm);
529} 592}
530 593