aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/mon.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2008-12-05 19:02:45 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-01-06 11:53:53 -0500
commit67c6d107a689243979a2b5f15244b5261634a924 (patch)
tree36e2093df96a449c284640c9cc329fc251e98bd0 /fs/lockd/mon.c
parent03eb1dcbb799304b58730f4dba65812f49fb305e (diff)
NSM: Move nsm_find() to fs/lockd/mon.c
The nsm_find() function sets up fresh nsm_handle entries. This is where we will store the "priv" cookie used to lookup nsm_handles during reboot recovery. The cookie will be constructed when nsm_find() creates a new nsm_handle. As much as possible, I would like to keep everything that handles a "priv" cookie in fs/lockd/mon.c so that all the smarts are in one source file. That organization should make it pretty simple to see how all this works. To me, it makes more sense than the current arrangement to keep nsm_find() with nsm_monitor() and nsm_unmonitor(). So, start reorganizing by moving nsm_find() into fs/lockd/mon.c. The nsm_release() function comes along too, since it shares the nsm_lock global variable. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/lockd/mon.c')
-rw-r--r--fs/lockd/mon.c133
1 files changed, 133 insertions, 0 deletions
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 */