aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/host.c128
-rw-r--r--fs/lockd/mon.c133
-rw-r--r--include/linux/lockd/lockd.h6
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;
32static DEFINE_MUTEX(nlm_host_mutex); 32static DEFINE_MUTEX(nlm_host_mutex);
33 33
34static void nlm_gc_hosts(void); 34static 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);
40static void nsm_release(struct nsm_handle *nsm);
41 35
42struct nlm_lookup_host_info { 36struct 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
109static 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
116static 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
130static 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 */
643static LIST_HEAD(nsm_handles);
644static DEFINE_SPINLOCK(nsm_lock);
645
646static 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
667retry:
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
705found:
706 spin_unlock(&nsm_lock);
707 return nsm;
708}
709
710/*
711 * Release an NSM handle
712 */
713static 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 {
47static struct rpc_clnt * nsm_create(void); 47static struct rpc_clnt * nsm_create(void);
48 48
49static struct rpc_program nsm_program; 49static struct rpc_program nsm_program;
50static LIST_HEAD(nsm_handles);
51static DEFINE_SPINLOCK(nsm_lock);
50 52
51/* 53/*
52 * Local NSM state 54 * Local NSM state
53 */ 55 */
54int nsm_local_state; 56int nsm_local_state;
55 57
58static 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
65static 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
79static 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 */
220struct 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
239retry:
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
277found:
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 */
287void 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 *,
247int nsm_monitor(const struct nlm_host *host); 247int nsm_monitor(const struct nlm_host *host);
248void nsm_unmonitor(const struct nlm_host *host); 248void nsm_unmonitor(const struct nlm_host *host);
249 249
250struct 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);
254void 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