diff options
-rw-r--r-- | fs/lockd/clntlock.c | 3 | ||||
-rw-r--r-- | fs/lockd/host.c | 121 | ||||
-rw-r--r-- | fs/lockd/mon.c | 14 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 17 |
4 files changed, 136 insertions, 19 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 87e1d03e8267..54e63ddef043 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -150,7 +150,8 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) | |||
150 | static void nlmclnt_prepare_reclaim(struct nlm_host *host) | 150 | static void nlmclnt_prepare_reclaim(struct nlm_host *host) |
151 | { | 151 | { |
152 | down_write(&host->h_rwsem); | 152 | down_write(&host->h_rwsem); |
153 | host->h_monitored = 0; | 153 | if (host->h_nsmhandle) |
154 | host->h_nsmhandle->sm_monitored = 0; | ||
154 | host->h_state++; | 155 | host->h_state++; |
155 | host->h_nextrebind = 0; | 156 | host->h_nextrebind = 0; |
156 | nlm_rebind_host(host); | 157 | nlm_rebind_host(host); |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 481ce7ee1002..0bf4afb71d25 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -34,6 +34,8 @@ static DEFINE_MUTEX(nlm_host_mutex); | |||
34 | 34 | ||
35 | 35 | ||
36 | static void nlm_gc_hosts(void); | 36 | static void nlm_gc_hosts(void); |
37 | static struct nsm_handle * __nsm_find(const struct sockaddr_in *, | ||
38 | const char *, int, int); | ||
37 | 39 | ||
38 | /* | 40 | /* |
39 | * Find an NLM server handle in the cache. If there is none, create it. | 41 | * Find an NLM server handle in the cache. If there is none, create it. |
@@ -68,7 +70,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
68 | int hostname_len) | 70 | int hostname_len) |
69 | { | 71 | { |
70 | struct nlm_host *host, **hp; | 72 | struct nlm_host *host, **hp; |
71 | u32 addr; | 73 | struct nsm_handle *nsm = NULL; |
72 | int hash; | 74 | int hash; |
73 | 75 | ||
74 | dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", | 76 | dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", |
@@ -86,7 +88,21 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
86 | if (time_after_eq(jiffies, next_gc)) | 88 | if (time_after_eq(jiffies, next_gc)) |
87 | nlm_gc_hosts(); | 89 | nlm_gc_hosts(); |
88 | 90 | ||
91 | /* We may keep several nlm_host objects for a peer, because each | ||
92 | * nlm_host is identified by | ||
93 | * (address, protocol, version, server/client) | ||
94 | * We could probably simplify this a little by putting all those | ||
95 | * different NLM rpc_clients into one single nlm_host object. | ||
96 | * This would allow us to have one nlm_host per address. | ||
97 | */ | ||
89 | for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) { | 98 | for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) { |
99 | if (!nlm_cmp_addr(&host->h_addr, sin)) | ||
100 | continue; | ||
101 | |||
102 | /* See if we have an NSM handle for this client */ | ||
103 | if (!nsm && (nsm = host->h_nsmhandle) != 0) | ||
104 | atomic_inc(&nsm->sm_count); | ||
105 | |||
90 | if (host->h_proto != proto) | 106 | if (host->h_proto != proto) |
91 | continue; | 107 | continue; |
92 | if (host->h_version != version) | 108 | if (host->h_version != version) |
@@ -94,7 +110,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
94 | if (host->h_server != server) | 110 | if (host->h_server != server) |
95 | continue; | 111 | continue; |
96 | 112 | ||
97 | if (nlm_cmp_addr(&host->h_addr, sin)) { | 113 | { |
98 | if (hp != nlm_hosts + hash) { | 114 | if (hp != nlm_hosts + hash) { |
99 | *hp = host->h_next; | 115 | *hp = host->h_next; |
100 | host->h_next = nlm_hosts[hash]; | 116 | host->h_next = nlm_hosts[hash]; |
@@ -106,16 +122,18 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
106 | } | 122 | } |
107 | } | 123 | } |
108 | 124 | ||
109 | /* Ooops, no host found, create it */ | 125 | /* Sadly, the host isn't in our hash table yet. See if |
110 | dprintk("lockd: creating host entry\n"); | 126 | * we have an NSM handle for it. If not, create one. |
127 | */ | ||
128 | if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len))) | ||
129 | goto out; | ||
111 | 130 | ||
112 | host = kzalloc(sizeof(*host), GFP_KERNEL); | 131 | host = kzalloc(sizeof(*host), GFP_KERNEL); |
113 | if (!host) | 132 | if (!host) { |
114 | goto nohost; | 133 | nsm_release(nsm); |
115 | 134 | goto out; | |
116 | addr = sin->sin_addr.s_addr; | 135 | } |
117 | sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr)); | 136 | host->h_name = nsm->sm_name; |
118 | |||
119 | host->h_addr = *sin; | 137 | host->h_addr = *sin; |
120 | host->h_addr.sin_port = 0; /* ouch! */ | 138 | host->h_addr.sin_port = 0; /* ouch! */ |
121 | host->h_version = version; | 139 | host->h_version = version; |
@@ -129,6 +147,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
129 | init_rwsem(&host->h_rwsem); | 147 | init_rwsem(&host->h_rwsem); |
130 | host->h_state = 0; /* pseudo NSM state */ | 148 | host->h_state = 0; /* pseudo NSM state */ |
131 | host->h_nsmstate = 0; /* real NSM state */ | 149 | host->h_nsmstate = 0; /* real NSM state */ |
150 | host->h_nsmhandle = nsm; | ||
132 | host->h_server = server; | 151 | host->h_server = server; |
133 | host->h_next = nlm_hosts[hash]; | 152 | host->h_next = nlm_hosts[hash]; |
134 | nlm_hosts[hash] = host; | 153 | nlm_hosts[hash] = host; |
@@ -140,7 +159,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
140 | if (++nrhosts > NLM_HOST_MAX) | 159 | if (++nrhosts > NLM_HOST_MAX) |
141 | next_gc = 0; | 160 | next_gc = 0; |
142 | 161 | ||
143 | nohost: | 162 | out: |
144 | mutex_unlock(&nlm_host_mutex); | 163 | mutex_unlock(&nlm_host_mutex); |
145 | return host; | 164 | return host; |
146 | } | 165 | } |
@@ -393,3 +412,83 @@ nlm_gc_hosts(void) | |||
393 | next_gc = jiffies + NLM_HOST_COLLECT; | 412 | next_gc = jiffies + NLM_HOST_COLLECT; |
394 | } | 413 | } |
395 | 414 | ||
415 | |||
416 | /* | ||
417 | * Manage NSM handles | ||
418 | */ | ||
419 | static LIST_HEAD(nsm_handles); | ||
420 | static DECLARE_MUTEX(nsm_sema); | ||
421 | |||
422 | static struct nsm_handle * | ||
423 | __nsm_find(const struct sockaddr_in *sin, | ||
424 | const char *hostname, int hostname_len, | ||
425 | int create) | ||
426 | { | ||
427 | struct nsm_handle *nsm = NULL; | ||
428 | struct list_head *pos; | ||
429 | |||
430 | if (!sin) | ||
431 | return NULL; | ||
432 | |||
433 | if (hostname && memchr(hostname, '/', hostname_len) != NULL) { | ||
434 | if (printk_ratelimit()) { | ||
435 | printk(KERN_WARNING "Invalid hostname \"%.*s\" " | ||
436 | "in NFS lock request\n", | ||
437 | hostname_len, hostname); | ||
438 | } | ||
439 | return NULL; | ||
440 | } | ||
441 | |||
442 | down(&nsm_sema); | ||
443 | list_for_each(pos, &nsm_handles) { | ||
444 | nsm = list_entry(pos, struct nsm_handle, sm_link); | ||
445 | |||
446 | if (!nlm_cmp_addr(&nsm->sm_addr, sin)) | ||
447 | continue; | ||
448 | atomic_inc(&nsm->sm_count); | ||
449 | goto out; | ||
450 | } | ||
451 | |||
452 | if (!create) { | ||
453 | nsm = NULL; | ||
454 | goto out; | ||
455 | } | ||
456 | |||
457 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | ||
458 | if (nsm != NULL) { | ||
459 | nsm->sm_addr = *sin; | ||
460 | nsm->sm_name = (char *) (nsm + 1); | ||
461 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
462 | nsm->sm_name[hostname_len] = '\0'; | ||
463 | atomic_set(&nsm->sm_count, 1); | ||
464 | |||
465 | list_add(&nsm->sm_link, &nsm_handles); | ||
466 | } | ||
467 | |||
468 | out: up(&nsm_sema); | ||
469 | return nsm; | ||
470 | } | ||
471 | |||
472 | struct nsm_handle * | ||
473 | nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len) | ||
474 | { | ||
475 | return __nsm_find(sin, hostname, hostname_len, 1); | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * Release an NSM handle | ||
480 | */ | ||
481 | void | ||
482 | nsm_release(struct nsm_handle *nsm) | ||
483 | { | ||
484 | if (!nsm) | ||
485 | return; | ||
486 | if (atomic_dec_and_test(&nsm->sm_count)) { | ||
487 | down(&nsm_sema); | ||
488 | if (atomic_read(&nsm->sm_count) == 0) { | ||
489 | list_del(&nsm->sm_link); | ||
490 | kfree(nsm); | ||
491 | } | ||
492 | up(&nsm_sema); | ||
493 | } | ||
494 | } | ||
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e02a1a4dfced..e27981403fbe 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -70,11 +70,14 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) | |||
70 | int | 70 | int |
71 | nsm_monitor(struct nlm_host *host) | 71 | nsm_monitor(struct nlm_host *host) |
72 | { | 72 | { |
73 | struct nsm_handle *nsm = host->h_nsmhandle; | ||
73 | struct nsm_res res; | 74 | struct nsm_res res; |
74 | int status; | 75 | int status; |
75 | 76 | ||
76 | dprintk("lockd: nsm_monitor(%s)\n", host->h_name); | 77 | dprintk("lockd: nsm_monitor(%s)\n", host->h_name); |
77 | if (host->h_monitored) | 78 | BUG_ON(nsm == NULL); |
79 | |||
80 | if (nsm->sm_monitored) | ||
78 | return 0; | 81 | return 0; |
79 | 82 | ||
80 | status = nsm_mon_unmon(host, SM_MON, &res); | 83 | status = nsm_mon_unmon(host, SM_MON, &res); |
@@ -82,7 +85,7 @@ nsm_monitor(struct nlm_host *host) | |||
82 | if (status < 0 || res.status != 0) | 85 | if (status < 0 || res.status != 0) |
83 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); | 86 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); |
84 | else | 87 | else |
85 | host->h_monitored = 1; | 88 | nsm->sm_monitored = 1; |
86 | return status; | 89 | return status; |
87 | } | 90 | } |
88 | 91 | ||
@@ -92,19 +95,22 @@ nsm_monitor(struct nlm_host *host) | |||
92 | int | 95 | int |
93 | nsm_unmonitor(struct nlm_host *host) | 96 | nsm_unmonitor(struct nlm_host *host) |
94 | { | 97 | { |
98 | struct nsm_handle *nsm = host->h_nsmhandle; | ||
95 | struct nsm_res res; | 99 | struct nsm_res res; |
96 | int status = 0; | 100 | int status = 0; |
97 | 101 | ||
98 | dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); | 102 | dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); |
99 | if (!host->h_monitored) | 103 | if (nsm == NULL) |
100 | return 0; | 104 | return 0; |
101 | host->h_monitored = 0; | 105 | host->h_nsmhandle = NULL; |
102 | 106 | ||
103 | if (!host->h_killed) { | 107 | if (!host->h_killed) { |
104 | status = nsm_mon_unmon(host, SM_UNMON, &res); | 108 | status = nsm_mon_unmon(host, SM_UNMON, &res); |
105 | if (status < 0) | 109 | if (status < 0) |
106 | printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name); | 110 | printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name); |
111 | nsm->sm_monitored = 0; | ||
107 | } | 112 | } |
113 | nsm_release(nsm); | ||
108 | return status; | 114 | return status; |
109 | } | 115 | } |
110 | 116 | ||
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0f9b236bca7f..ab2ffc8a0b44 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -40,14 +40,13 @@ struct nlm_host { | |||
40 | struct nlm_host * h_next; /* linked list (hash table) */ | 40 | struct nlm_host * h_next; /* linked list (hash table) */ |
41 | struct sockaddr_in h_addr; /* peer address */ | 41 | struct sockaddr_in h_addr; /* peer address */ |
42 | struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ | 42 | struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ |
43 | char h_name[20]; /* remote hostname */ | 43 | char * h_name; /* remote hostname */ |
44 | u32 h_version; /* interface version */ | 44 | u32 h_version; /* interface version */ |
45 | unsigned short h_proto; /* transport proto */ | 45 | unsigned short h_proto; /* transport proto */ |
46 | unsigned short h_reclaiming : 1, | 46 | unsigned short h_reclaiming : 1, |
47 | h_server : 1, /* server side, not client side */ | 47 | h_server : 1, /* server side, not client side */ |
48 | h_inuse : 1, | 48 | h_inuse : 1, |
49 | h_killed : 1, | 49 | h_killed : 1; |
50 | h_monitored : 1; | ||
51 | wait_queue_head_t h_gracewait; /* wait while reclaiming */ | 50 | wait_queue_head_t h_gracewait; /* wait while reclaiming */ |
52 | struct rw_semaphore h_rwsem; /* Reboot recovery lock */ | 51 | struct rw_semaphore h_rwsem; /* Reboot recovery lock */ |
53 | u32 h_state; /* pseudo-state counter */ | 52 | u32 h_state; /* pseudo-state counter */ |
@@ -61,6 +60,16 @@ struct nlm_host { | |||
61 | spinlock_t h_lock; | 60 | spinlock_t h_lock; |
62 | struct list_head h_granted; /* Locks in GRANTED state */ | 61 | struct list_head h_granted; /* Locks in GRANTED state */ |
63 | struct list_head h_reclaim; /* Locks in RECLAIM state */ | 62 | struct list_head h_reclaim; /* Locks in RECLAIM state */ |
63 | struct nsm_handle * h_nsmhandle; /* NSM status handle */ | ||
64 | }; | ||
65 | |||
66 | struct nsm_handle { | ||
67 | struct list_head sm_link; | ||
68 | atomic_t sm_count; | ||
69 | char * sm_name; | ||
70 | struct sockaddr_in sm_addr; | ||
71 | unsigned int sm_monitored : 1, | ||
72 | sm_sticky : 1; /* don't unmonitor */ | ||
64 | }; | 73 | }; |
65 | 74 | ||
66 | /* | 75 | /* |
@@ -171,6 +180,8 @@ void nlm_release_host(struct nlm_host *); | |||
171 | void nlm_shutdown_hosts(void); | 180 | void nlm_shutdown_hosts(void); |
172 | extern struct nlm_host *nlm_find_client(void); | 181 | extern struct nlm_host *nlm_find_client(void); |
173 | extern void nlm_host_rebooted(const struct sockaddr_in *, const struct nlm_reboot *); | 182 | extern void nlm_host_rebooted(const struct sockaddr_in *, const struct nlm_reboot *); |
183 | struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int); | ||
184 | void nsm_release(struct nsm_handle *); | ||
174 | 185 | ||
175 | 186 | ||
176 | /* | 187 | /* |