diff options
-rw-r--r-- | fs/lockd/host.c | 128 | ||||
-rw-r--r-- | fs/lockd/mon.c | 133 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 6 |
3 files changed, 139 insertions, 128 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 1d523c1a7b62..dbdeaa88d2fa 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -32,12 +32,6 @@ static int nrhosts; | |||
32 | static DEFINE_MUTEX(nlm_host_mutex); | 32 | static DEFINE_MUTEX(nlm_host_mutex); |
33 | 33 | ||
34 | static void nlm_gc_hosts(void); | 34 | static void nlm_gc_hosts(void); |
35 | static 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 | static void nsm_release(struct nsm_handle *nsm); | ||
41 | 35 | ||
42 | struct nlm_lookup_host_info { | 36 | struct nlm_lookup_host_info { |
43 | const int server; /* search for server|client */ | 37 | const int server; /* search for server|client */ |
@@ -106,43 +100,6 @@ static void nlm_clear_port(struct sockaddr *sap) | |||
106 | } | 100 | } |
107 | } | 101 | } |
108 | 102 | ||
109 | static void nlm_display_ipv4_address(const struct sockaddr *sap, char *buf, | ||
110 | const size_t len) | ||
111 | { | ||
112 | const struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
113 | snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr); | ||
114 | } | ||
115 | |||
116 | static void nlm_display_ipv6_address(const struct sockaddr *sap, char *buf, | ||
117 | const size_t len) | ||
118 | { | ||
119 | const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
120 | |||
121 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) | ||
122 | snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]); | ||
123 | else if (sin6->sin6_scope_id != 0) | ||
124 | snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr, | ||
125 | sin6->sin6_scope_id); | ||
126 | else | ||
127 | snprintf(buf, len, "%pI6", &sin6->sin6_addr); | ||
128 | } | ||
129 | |||
130 | static void nlm_display_address(const struct sockaddr *sap, | ||
131 | char *buf, const size_t len) | ||
132 | { | ||
133 | switch (sap->sa_family) { | ||
134 | case AF_INET: | ||
135 | nlm_display_ipv4_address(sap, buf, len); | ||
136 | break; | ||
137 | case AF_INET6: | ||
138 | nlm_display_ipv6_address(sap, buf, len); | ||
139 | break; | ||
140 | default: | ||
141 | snprintf(buf, len, "unsupported address family"); | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | /* | 103 | /* |
147 | * Common host lookup routine for server & client | 104 | * Common host lookup routine for server & client |
148 | */ | 105 | */ |
@@ -635,88 +592,3 @@ nlm_gc_hosts(void) | |||
635 | 592 | ||
636 | next_gc = jiffies + NLM_HOST_COLLECT; | 593 | next_gc = jiffies + NLM_HOST_COLLECT; |
637 | } | 594 | } |
638 | |||
639 | |||
640 | /* | ||
641 | * Manage NSM handles | ||
642 | */ | ||
643 | static LIST_HEAD(nsm_handles); | ||
644 | static DEFINE_SPINLOCK(nsm_lock); | ||
645 | |||
646 | static struct nsm_handle *nsm_find(const struct sockaddr *sap, | ||
647 | const size_t salen, | ||
648 | const char *hostname, | ||
649 | const size_t hostname_len, | ||
650 | const int create) | ||
651 | { | ||
652 | struct nsm_handle *nsm = NULL; | ||
653 | struct nsm_handle *pos; | ||
654 | |||
655 | if (!sap) | ||
656 | return NULL; | ||
657 | |||
658 | if (hostname && memchr(hostname, '/', hostname_len) != NULL) { | ||
659 | if (printk_ratelimit()) { | ||
660 | printk(KERN_WARNING "Invalid hostname \"%.*s\" " | ||
661 | "in NFS lock request\n", | ||
662 | (int)hostname_len, hostname); | ||
663 | } | ||
664 | return NULL; | ||
665 | } | ||
666 | |||
667 | retry: | ||
668 | spin_lock(&nsm_lock); | ||
669 | list_for_each_entry(pos, &nsm_handles, sm_link) { | ||
670 | |||
671 | if (hostname && nsm_use_hostnames) { | ||
672 | if (strlen(pos->sm_name) != hostname_len | ||
673 | || memcmp(pos->sm_name, hostname, hostname_len)) | ||
674 | continue; | ||
675 | } else if (!nlm_cmp_addr(nsm_addr(pos), sap)) | ||
676 | continue; | ||
677 | atomic_inc(&pos->sm_count); | ||
678 | kfree(nsm); | ||
679 | nsm = pos; | ||
680 | goto found; | ||
681 | } | ||
682 | if (nsm) { | ||
683 | list_add(&nsm->sm_link, &nsm_handles); | ||
684 | goto found; | ||
685 | } | ||
686 | spin_unlock(&nsm_lock); | ||
687 | |||
688 | if (!create) | ||
689 | return NULL; | ||
690 | |||
691 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | ||
692 | if (nsm == NULL) | ||
693 | return NULL; | ||
694 | |||
695 | memcpy(nsm_addr(nsm), sap, salen); | ||
696 | nsm->sm_addrlen = salen; | ||
697 | nsm->sm_name = (char *) (nsm + 1); | ||
698 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
699 | nsm->sm_name[hostname_len] = '\0'; | ||
700 | nlm_display_address((struct sockaddr *)&nsm->sm_addr, | ||
701 | nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf)); | ||
702 | atomic_set(&nsm->sm_count, 1); | ||
703 | goto retry; | ||
704 | |||
705 | found: | ||
706 | spin_unlock(&nsm_lock); | ||
707 | return nsm; | ||
708 | } | ||
709 | |||
710 | /* | ||
711 | * Release an NSM handle | ||
712 | */ | ||
713 | static void nsm_release(struct nsm_handle *nsm) | ||
714 | { | ||
715 | if (!nsm) | ||
716 | return; | ||
717 | if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) { | ||
718 | list_del(&nsm->sm_link); | ||
719 | spin_unlock(&nsm_lock); | ||
720 | kfree(nsm); | ||
721 | } | ||
722 | } | ||
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 81e1cc14246f..8e68e799293c 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -47,12 +47,51 @@ struct nsm_res { | |||
47 | static struct rpc_clnt * nsm_create(void); | 47 | static struct rpc_clnt * nsm_create(void); |
48 | 48 | ||
49 | static struct rpc_program nsm_program; | 49 | static struct rpc_program nsm_program; |
50 | static LIST_HEAD(nsm_handles); | ||
51 | static DEFINE_SPINLOCK(nsm_lock); | ||
50 | 52 | ||
51 | /* | 53 | /* |
52 | * Local NSM state | 54 | * Local NSM state |
53 | */ | 55 | */ |
54 | int nsm_local_state; | 56 | int nsm_local_state; |
55 | 57 | ||
58 | static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf, | ||
59 | const size_t len) | ||
60 | { | ||
61 | const struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
62 | snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr); | ||
63 | } | ||
64 | |||
65 | static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf, | ||
66 | const size_t len) | ||
67 | { | ||
68 | const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
69 | |||
70 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) | ||
71 | snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]); | ||
72 | else if (sin6->sin6_scope_id != 0) | ||
73 | snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr, | ||
74 | sin6->sin6_scope_id); | ||
75 | else | ||
76 | snprintf(buf, len, "%pI6", &sin6->sin6_addr); | ||
77 | } | ||
78 | |||
79 | static void nsm_display_address(const struct sockaddr *sap, | ||
80 | char *buf, const size_t len) | ||
81 | { | ||
82 | switch (sap->sa_family) { | ||
83 | case AF_INET: | ||
84 | nsm_display_ipv4_address(sap, buf, len); | ||
85 | break; | ||
86 | case AF_INET6: | ||
87 | nsm_display_ipv6_address(sap, buf, len); | ||
88 | break; | ||
89 | default: | ||
90 | snprintf(buf, len, "unsupported address family"); | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | |||
56 | /* | 95 | /* |
57 | * Common procedure for NSMPROC_MON/NSMPROC_UNMON calls | 96 | * Common procedure for NSMPROC_MON/NSMPROC_UNMON calls |
58 | */ | 97 | */ |
@@ -162,6 +201,100 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
162 | } | 201 | } |
163 | } | 202 | } |
164 | 203 | ||
204 | /** | ||
205 | * nsm_find - Find or create a cached nsm_handle | ||
206 | * @sap: pointer to socket address of handle to find | ||
207 | * @salen: length of socket address | ||
208 | * @hostname: pointer to C string containing hostname to find | ||
209 | * @hostname_len: length of C string | ||
210 | * @create: one means create new handle if not found in cache | ||
211 | * | ||
212 | * Behavior is modulated by the global nsm_use_hostnames variable | ||
213 | * and by the @create argument. | ||
214 | * | ||
215 | * Returns a cached nsm_handle after bumping its ref count, or if | ||
216 | * @create is set, returns a fresh nsm_handle if a handle that | ||
217 | * matches @sap and/or @hostname cannot be found in the handle cache. | ||
218 | * Returns NULL if an error occurs. | ||
219 | */ | ||
220 | struct nsm_handle *nsm_find(const struct sockaddr *sap, const size_t salen, | ||
221 | const char *hostname, const size_t hostname_len, | ||
222 | const int create) | ||
223 | { | ||
224 | struct nsm_handle *nsm = NULL; | ||
225 | struct nsm_handle *pos; | ||
226 | |||
227 | if (!sap) | ||
228 | return NULL; | ||
229 | |||
230 | if (hostname && memchr(hostname, '/', hostname_len) != NULL) { | ||
231 | if (printk_ratelimit()) { | ||
232 | printk(KERN_WARNING "Invalid hostname \"%.*s\" " | ||
233 | "in NFS lock request\n", | ||
234 | (int)hostname_len, hostname); | ||
235 | } | ||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | retry: | ||
240 | spin_lock(&nsm_lock); | ||
241 | list_for_each_entry(pos, &nsm_handles, sm_link) { | ||
242 | |||
243 | if (hostname && nsm_use_hostnames) { | ||
244 | if (strlen(pos->sm_name) != hostname_len | ||
245 | || memcmp(pos->sm_name, hostname, hostname_len)) | ||
246 | continue; | ||
247 | } else if (!nlm_cmp_addr(nsm_addr(pos), sap)) | ||
248 | continue; | ||
249 | atomic_inc(&pos->sm_count); | ||
250 | kfree(nsm); | ||
251 | nsm = pos; | ||
252 | goto found; | ||
253 | } | ||
254 | if (nsm) { | ||
255 | list_add(&nsm->sm_link, &nsm_handles); | ||
256 | goto found; | ||
257 | } | ||
258 | spin_unlock(&nsm_lock); | ||
259 | |||
260 | if (!create) | ||
261 | return NULL; | ||
262 | |||
263 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | ||
264 | if (nsm == NULL) | ||
265 | return NULL; | ||
266 | |||
267 | memcpy(nsm_addr(nsm), sap, salen); | ||
268 | nsm->sm_addrlen = salen; | ||
269 | nsm->sm_name = (char *) (nsm + 1); | ||
270 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
271 | nsm->sm_name[hostname_len] = '\0'; | ||
272 | nsm_display_address((struct sockaddr *)&nsm->sm_addr, | ||
273 | nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf)); | ||
274 | atomic_set(&nsm->sm_count, 1); | ||
275 | goto retry; | ||
276 | |||
277 | found: | ||
278 | spin_unlock(&nsm_lock); | ||
279 | return nsm; | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * nsm_release - Release an NSM handle | ||
284 | * @nsm: pointer to handle to be released | ||
285 | * | ||
286 | */ | ||
287 | void nsm_release(struct nsm_handle *nsm) | ||
288 | { | ||
289 | if (!nsm) | ||
290 | return; | ||
291 | if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) { | ||
292 | list_del(&nsm->sm_link); | ||
293 | spin_unlock(&nsm_lock); | ||
294 | kfree(nsm); | ||
295 | } | ||
296 | } | ||
297 | |||
165 | /* | 298 | /* |
166 | * Create NSM client for the local host | 299 | * Create NSM client for the local host |
167 | */ | 300 | */ |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 38344bfb814a..8d715363c6ac 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -247,6 +247,12 @@ extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, | |||
247 | int nsm_monitor(const struct nlm_host *host); | 247 | int nsm_monitor(const struct nlm_host *host); |
248 | void nsm_unmonitor(const struct nlm_host *host); | 248 | void nsm_unmonitor(const struct nlm_host *host); |
249 | 249 | ||
250 | struct nsm_handle *nsm_find(const struct sockaddr *sap, const size_t salen, | ||
251 | const char *hostname, | ||
252 | const size_t hostname_len, | ||
253 | const int create); | ||
254 | void nsm_release(struct nsm_handle *nsm); | ||
255 | |||
250 | /* | 256 | /* |
251 | * This is used in garbage collection and resource reclaim | 257 | * This is used in garbage collection and resource reclaim |
252 | * A return value != 0 means destroy the lock/block/share | 258 | * A return value != 0 means destroy the lock/block/share |