aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/lockd/clntlock.c4
-rw-r--r--fs/lockd/clntproc.c6
-rw-r--r--fs/lockd/host.c81
-rw-r--r--include/linux/lockd/lockd.h1
4 files changed, 78 insertions, 14 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 25509eb28fd7..8d4ea8351e3d 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(nlmclnt_init);
79 */ 79 */
80void nlmclnt_done(struct nlm_host *host) 80void nlmclnt_done(struct nlm_host *host)
81{ 81{
82 nlm_release_host(host); 82 nlmclnt_release_host(host);
83 lockd_down(); 83 lockd_down();
84} 84}
85EXPORT_SYMBOL_GPL(nlmclnt_done); 85EXPORT_SYMBOL_GPL(nlmclnt_done);
@@ -273,7 +273,7 @@ restart:
273 spin_unlock(&nlm_blocked_lock); 273 spin_unlock(&nlm_blocked_lock);
274 274
275 /* Release host handle after use */ 275 /* Release host handle after use */
276 nlm_release_host(host); 276 nlmclnt_release_host(host);
277 lockd_down(); 277 lockd_down();
278 return 0; 278 return 0;
279} 279}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index fbc6617f76c4..adb45ec9038c 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -58,7 +58,7 @@ static void nlm_put_lockowner(struct nlm_lockowner *lockowner)
58 return; 58 return;
59 list_del(&lockowner->list); 59 list_del(&lockowner->list);
60 spin_unlock(&lockowner->host->h_lock); 60 spin_unlock(&lockowner->host->h_lock);
61 nlm_release_host(lockowner->host); 61 nlmclnt_release_host(lockowner->host);
62 kfree(lockowner); 62 kfree(lockowner);
63} 63}
64 64
@@ -207,7 +207,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
207 printk("nlm_alloc_call: failed, waiting for memory\n"); 207 printk("nlm_alloc_call: failed, waiting for memory\n");
208 schedule_timeout_interruptible(5*HZ); 208 schedule_timeout_interruptible(5*HZ);
209 } 209 }
210 nlm_release_host(host); 210 nlmclnt_release_host(host);
211 return NULL; 211 return NULL;
212} 212}
213 213
@@ -215,7 +215,7 @@ void nlmclnt_release_call(struct nlm_rqst *call)
215{ 215{
216 if (!atomic_dec_and_test(&call->a_count)) 216 if (!atomic_dec_and_test(&call->a_count))
217 return; 217 return;
218 nlm_release_host(call->a_host); 218 nlmclnt_release_host(call->a_host);
219 nlmclnt_release_lockargs(call); 219 nlmclnt_release_lockargs(call);
220 kfree(call); 220 kfree(call);
221} 221}
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
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index a32ba62455af..6c2a0e2f298e 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -223,6 +223,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
223 const u32 version, 223 const u32 version,
224 const char *hostname, 224 const char *hostname,
225 int noresvport); 225 int noresvport);
226void nlmclnt_release_host(struct nlm_host *);
226struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, 227struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
227 const char *hostname, 228 const char *hostname,
228 const size_t hostname_len); 229 const size_t hostname_len);