aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd/host.c')
-rw-r--r--fs/lockd/host.c180
1 files changed, 26 insertions, 154 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index e05d04416037..99d737bd4325 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -15,7 +15,6 @@
15#include <linux/sunrpc/clnt.h> 15#include <linux/sunrpc/clnt.h>
16#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
17#include <linux/lockd/lockd.h> 17#include <linux/lockd/lockd.h>
18#include <linux/lockd/sm_inter.h>
19#include <linux/mutex.h> 18#include <linux/mutex.h>
20 19
21#include <net/ipv6.h> 20#include <net/ipv6.h>
@@ -32,11 +31,6 @@ static int nrhosts;
32static DEFINE_MUTEX(nlm_host_mutex); 31static DEFINE_MUTEX(nlm_host_mutex);
33 32
34static void nlm_gc_hosts(void); 33static void nlm_gc_hosts(void);
35static struct nsm_handle *nsm_find(const struct sockaddr *sap,
36 const size_t salen,
37 const char *hostname,
38 const size_t hostname_len,
39 const int create);
40 34
41struct nlm_lookup_host_info { 35struct nlm_lookup_host_info {
42 const int server; /* search for server|client */ 36 const int server; /* search for server|client */
@@ -48,6 +42,7 @@ struct nlm_lookup_host_info {
48 const size_t hostname_len; /* it's length */ 42 const size_t hostname_len; /* it's length */
49 const struct sockaddr *src_sap; /* our address (optional) */ 43 const struct sockaddr *src_sap; /* our address (optional) */
50 const size_t src_len; /* it's length */ 44 const size_t src_len; /* it's length */
45 const int noresvport; /* use non-priv port */
51}; 46};
52 47
53/* 48/*
@@ -104,32 +99,6 @@ static void nlm_clear_port(struct sockaddr *sap)
104 } 99 }
105} 100}
106 101
107static void nlm_display_address(const struct sockaddr *sap,
108 char *buf, const size_t len)
109{
110 const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
111 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
112
113 switch (sap->sa_family) {
114 case AF_UNSPEC:
115 snprintf(buf, len, "unspecified");
116 break;
117 case AF_INET:
118 snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
119 break;
120 case AF_INET6:
121 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
122 snprintf(buf, len, "%pI4",
123 &sin6->sin6_addr.s6_addr32[3]);
124 else
125 snprintf(buf, len, "%pI6", &sin6->sin6_addr);
126 break;
127 default:
128 snprintf(buf, len, "unsupported address family");
129 break;
130 }
131}
132
133/* 102/*
134 * Common host lookup routine for server & client 103 * Common host lookup routine for server & client
135 */ 104 */
@@ -189,8 +158,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
189 atomic_inc(&nsm->sm_count); 158 atomic_inc(&nsm->sm_count);
190 else { 159 else {
191 host = NULL; 160 host = NULL;
192 nsm = nsm_find(ni->sap, ni->salen, 161 nsm = nsm_get_handle(ni->sap, ni->salen,
193 ni->hostname, ni->hostname_len, 1); 162 ni->hostname, ni->hostname_len);
194 if (!nsm) { 163 if (!nsm) {
195 dprintk("lockd: nlm_lookup_host failed; " 164 dprintk("lockd: nlm_lookup_host failed; "
196 "no nsm handle\n"); 165 "no nsm handle\n");
@@ -205,6 +174,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
205 goto out; 174 goto out;
206 } 175 }
207 host->h_name = nsm->sm_name; 176 host->h_name = nsm->sm_name;
177 host->h_addrbuf = nsm->sm_addrbuf;
208 memcpy(nlm_addr(host), ni->sap, ni->salen); 178 memcpy(nlm_addr(host), ni->sap, ni->salen);
209 host->h_addrlen = ni->salen; 179 host->h_addrlen = ni->salen;
210 nlm_clear_port(nlm_addr(host)); 180 nlm_clear_port(nlm_addr(host));
@@ -222,6 +192,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
222 host->h_nsmstate = 0; /* real NSM state */ 192 host->h_nsmstate = 0; /* real NSM state */
223 host->h_nsmhandle = nsm; 193 host->h_nsmhandle = nsm;
224 host->h_server = ni->server; 194 host->h_server = ni->server;
195 host->h_noresvport = ni->noresvport;
225 hlist_add_head(&host->h_hash, chain); 196 hlist_add_head(&host->h_hash, chain);
226 INIT_LIST_HEAD(&host->h_lockowners); 197 INIT_LIST_HEAD(&host->h_lockowners);
227 spin_lock_init(&host->h_lock); 198 spin_lock_init(&host->h_lock);
@@ -230,11 +201,6 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
230 201
231 nrhosts++; 202 nrhosts++;
232 203
233 nlm_display_address((struct sockaddr *)&host->h_addr,
234 host->h_addrbuf, sizeof(host->h_addrbuf));
235 nlm_display_address((struct sockaddr *)&host->h_srcaddr,
236 host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
237
238 dprintk("lockd: nlm_lookup_host created host %s\n", 204 dprintk("lockd: nlm_lookup_host created host %s\n",
239 host->h_name); 205 host->h_name);
240 206
@@ -254,10 +220,8 @@ nlm_destroy_host(struct nlm_host *host)
254 BUG_ON(!list_empty(&host->h_lockowners)); 220 BUG_ON(!list_empty(&host->h_lockowners));
255 BUG_ON(atomic_read(&host->h_count)); 221 BUG_ON(atomic_read(&host->h_count));
256 222
257 /*
258 * Release NSM handle and unmonitor host.
259 */
260 nsm_unmonitor(host); 223 nsm_unmonitor(host);
224 nsm_release(host->h_nsmhandle);
261 225
262 clnt = host->h_rpcclnt; 226 clnt = host->h_rpcclnt;
263 if (clnt != NULL) 227 if (clnt != NULL)
@@ -272,6 +236,7 @@ nlm_destroy_host(struct nlm_host *host)
272 * @protocol: transport protocol to use 236 * @protocol: transport protocol to use
273 * @version: NLM protocol version 237 * @version: NLM protocol version
274 * @hostname: '\0'-terminated hostname of server 238 * @hostname: '\0'-terminated hostname of server
239 * @noresvport: 1 if non-privileged port should be used
275 * 240 *
276 * Returns an nlm_host structure that matches the passed-in 241 * Returns an nlm_host structure that matches the passed-in
277 * [server address, transport protocol, NLM version, server hostname]. 242 * [server address, transport protocol, NLM version, server hostname].
@@ -281,7 +246,9 @@ nlm_destroy_host(struct nlm_host *host)
281struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, 246struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
282 const size_t salen, 247 const size_t salen,
283 const unsigned short protocol, 248 const unsigned short protocol,
284 const u32 version, const char *hostname) 249 const u32 version,
250 const char *hostname,
251 int noresvport)
285{ 252{
286 const struct sockaddr source = { 253 const struct sockaddr source = {
287 .sa_family = AF_UNSPEC, 254 .sa_family = AF_UNSPEC,
@@ -296,6 +263,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
296 .hostname_len = strlen(hostname), 263 .hostname_len = strlen(hostname),
297 .src_sap = &source, 264 .src_sap = &source,
298 .src_len = sizeof(source), 265 .src_len = sizeof(source),
266 .noresvport = noresvport,
299 }; 267 };
300 268
301 dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, 269 dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
@@ -372,8 +340,8 @@ nlm_bind_host(struct nlm_host *host)
372{ 340{
373 struct rpc_clnt *clnt; 341 struct rpc_clnt *clnt;
374 342
375 dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n", 343 dprintk("lockd: nlm_bind_host %s (%s)\n",
376 host->h_name, host->h_addrbuf, host->h_srcaddrbuf); 344 host->h_name, host->h_addrbuf);
377 345
378 /* Lock host handle */ 346 /* Lock host handle */
379 mutex_lock(&host->h_mutex); 347 mutex_lock(&host->h_mutex);
@@ -417,6 +385,8 @@ nlm_bind_host(struct nlm_host *host)
417 */ 385 */
418 if (!host->h_server) 386 if (!host->h_server)
419 args.flags |= RPC_CLNT_CREATE_HARDRTRY; 387 args.flags |= RPC_CLNT_CREATE_HARDRTRY;
388 if (host->h_noresvport)
389 args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
420 390
421 clnt = rpc_create(&args); 391 clnt = rpc_create(&args);
422 if (!IS_ERR(clnt)) 392 if (!IS_ERR(clnt))
@@ -473,35 +443,23 @@ void nlm_release_host(struct nlm_host *host)
473 } 443 }
474} 444}
475 445
476/* 446/**
477 * We were notified that the host indicated by address &sin 447 * nlm_host_rebooted - Release all resources held by rebooted host
478 * has rebooted. 448 * @info: pointer to decoded results of NLM_SM_NOTIFY call
479 * Release all resources held by that peer. 449 *
450 * We were notified that the specified host has rebooted. Release
451 * all resources held by that peer.
480 */ 452 */
481void nlm_host_rebooted(const struct sockaddr_in *sin, 453void nlm_host_rebooted(const struct nlm_reboot *info)
482 const char *hostname,
483 unsigned int hostname_len,
484 u32 new_state)
485{ 454{
486 struct hlist_head *chain; 455 struct hlist_head *chain;
487 struct hlist_node *pos; 456 struct hlist_node *pos;
488 struct nsm_handle *nsm; 457 struct nsm_handle *nsm;
489 struct nlm_host *host; 458 struct nlm_host *host;
490 459
491 nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin), 460 nsm = nsm_reboot_lookup(info);
492 hostname, hostname_len, 0); 461 if (unlikely(nsm == NULL))
493 if (nsm == NULL) {
494 dprintk("lockd: never saw rebooted peer '%.*s' before\n",
495 hostname_len, hostname);
496 return; 462 return;
497 }
498
499 dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
500 hostname_len, hostname, nsm->sm_addrbuf);
501
502 /* When reclaiming locks on this peer, make sure that
503 * we set up a new notification */
504 nsm->sm_monitored = 0;
505 463
506 /* Mark all hosts tied to this NSM state as having rebooted. 464 /* Mark all hosts tied to this NSM state as having rebooted.
507 * We run the loop repeatedly, because we drop the host table 465 * We run the loop repeatedly, because we drop the host table
@@ -512,8 +470,8 @@ again: mutex_lock(&nlm_host_mutex);
512 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { 470 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
513 hlist_for_each_entry(host, pos, chain, h_hash) { 471 hlist_for_each_entry(host, pos, chain, h_hash) {
514 if (host->h_nsmhandle == nsm 472 if (host->h_nsmhandle == nsm
515 && host->h_nsmstate != new_state) { 473 && host->h_nsmstate != info->state) {
516 host->h_nsmstate = new_state; 474 host->h_nsmstate = info->state;
517 host->h_state++; 475 host->h_state++;
518 476
519 nlm_get_host(host); 477 nlm_get_host(host);
@@ -621,89 +579,3 @@ nlm_gc_hosts(void)
621 579
622 next_gc = jiffies + NLM_HOST_COLLECT; 580 next_gc = jiffies + NLM_HOST_COLLECT;
623} 581}
624
625
626/*
627 * Manage NSM handles
628 */
629static LIST_HEAD(nsm_handles);
630static DEFINE_SPINLOCK(nsm_lock);
631
632static struct nsm_handle *nsm_find(const struct sockaddr *sap,
633 const size_t salen,
634 const char *hostname,
635 const size_t hostname_len,
636 const int create)
637{
638 struct nsm_handle *nsm = NULL;
639 struct nsm_handle *pos;
640
641 if (!sap)
642 return NULL;
643
644 if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
645 if (printk_ratelimit()) {
646 printk(KERN_WARNING "Invalid hostname \"%.*s\" "
647 "in NFS lock request\n",
648 (int)hostname_len, hostname);
649 }
650 return NULL;
651 }
652
653retry:
654 spin_lock(&nsm_lock);
655 list_for_each_entry(pos, &nsm_handles, sm_link) {
656
657 if (hostname && nsm_use_hostnames) {
658 if (strlen(pos->sm_name) != hostname_len
659 || memcmp(pos->sm_name, hostname, hostname_len))
660 continue;
661 } else if (!nlm_cmp_addr(nsm_addr(pos), sap))
662 continue;
663 atomic_inc(&pos->sm_count);
664 kfree(nsm);
665 nsm = pos;
666 goto found;
667 }
668 if (nsm) {
669 list_add(&nsm->sm_link, &nsm_handles);
670 goto found;
671 }
672 spin_unlock(&nsm_lock);
673
674 if (!create)
675 return NULL;
676
677 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
678 if (nsm == NULL)
679 return NULL;
680
681 memcpy(nsm_addr(nsm), sap, salen);
682 nsm->sm_addrlen = salen;
683 nsm->sm_name = (char *) (nsm + 1);
684 memcpy(nsm->sm_name, hostname, hostname_len);
685 nsm->sm_name[hostname_len] = '\0';
686 nlm_display_address((struct sockaddr *)&nsm->sm_addr,
687 nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
688 atomic_set(&nsm->sm_count, 1);
689 goto retry;
690
691found:
692 spin_unlock(&nsm_lock);
693 return nsm;
694}
695
696/*
697 * Release an NSM handle
698 */
699void
700nsm_release(struct nsm_handle *nsm)
701{
702 if (!nsm)
703 return;
704 if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
705 list_del(&nsm->sm_link);
706 spin_unlock(&nsm_lock);
707 kfree(nsm);
708 }
709}