diff options
author | James Morris <jmorris@namei.org> | 2011-03-07 18:55:06 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-03-07 18:55:06 -0500 |
commit | 1cc26bada9f6807814806db2f0d78792eecdac71 (patch) | |
tree | 5509b5139db04af6c13db0a580c84116a4a54039 /fs/lockd | |
parent | eae61f3c829439f8f9121b5cd48a14be04df451f (diff) | |
parent | 214d93b02c4fe93638ad268613c9702a81ed9192 (diff) |
Merge branch 'master'; commit 'v2.6.38-rc7' into next
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/Makefile | 6 | ||||
-rw-r--r-- | fs/lockd/clnt4xdr.c | 605 | ||||
-rw-r--r-- | fs/lockd/clntlock.c | 4 | ||||
-rw-r--r-- | fs/lockd/clntproc.c | 18 | ||||
-rw-r--r-- | fs/lockd/clntxdr.c | 627 | ||||
-rw-r--r-- | fs/lockd/host.c | 410 | ||||
-rw-r--r-- | fs/lockd/mon.c | 110 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 20 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 34 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 28 | ||||
-rw-r--r-- | fs/lockd/xdr.c | 287 | ||||
-rw-r--r-- | fs/lockd/xdr4.c | 255 |
12 files changed, 1594 insertions, 810 deletions
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile index 97f6073ab339..ca58d64374ca 100644 --- a/fs/lockd/Makefile +++ b/fs/lockd/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_LOCKD) += lockd.o | 5 | obj-$(CONFIG_LOCKD) += lockd.o |
6 | 6 | ||
7 | lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \ | 7 | lockd-objs-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \ |
8 | svcproc.o svcsubs.o mon.o xdr.o grace.o | 8 | svcshare.o svcproc.o svcsubs.o mon.o xdr.o grace.o |
9 | lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o | 9 | lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o |
10 | lockd-objs := $(lockd-objs-y) | 10 | lockd-objs := $(lockd-objs-y) |
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c new file mode 100644 index 000000000000..f848b52c67b1 --- /dev/null +++ b/fs/lockd/clnt4xdr.c | |||
@@ -0,0 +1,605 @@ | |||
1 | /* | ||
2 | * linux/fs/lockd/clnt4xdr.c | ||
3 | * | ||
4 | * XDR functions to encode/decode NLM version 4 RPC arguments and results. | ||
5 | * | ||
6 | * NLM client-side only. | ||
7 | * | ||
8 | * Copyright (C) 2010, Oracle. All rights reserved. | ||
9 | */ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/sunrpc/xdr.h> | ||
13 | #include <linux/sunrpc/clnt.h> | ||
14 | #include <linux/sunrpc/stats.h> | ||
15 | #include <linux/lockd/lockd.h> | ||
16 | |||
17 | #define NLMDBG_FACILITY NLMDBG_XDR | ||
18 | |||
19 | #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) | ||
20 | # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" | ||
21 | #endif | ||
22 | |||
23 | #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) | ||
24 | # error "NLM host name cannot be larger than NLM's maximum string length!" | ||
25 | #endif | ||
26 | |||
27 | /* | ||
28 | * Declare the space requirements for NLM arguments and replies as | ||
29 | * number of 32bit-words | ||
30 | */ | ||
31 | #define NLM4_void_sz (0) | ||
32 | #define NLM4_cookie_sz (1+(NLM_MAXCOOKIELEN>>2)) | ||
33 | #define NLM4_caller_sz (1+(NLMCLNT_OHSIZE>>2)) | ||
34 | #define NLM4_owner_sz (1+(NLMCLNT_OHSIZE>>2)) | ||
35 | #define NLM4_fhandle_sz (1+(NFS3_FHSIZE>>2)) | ||
36 | #define NLM4_lock_sz (5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz) | ||
37 | #define NLM4_holder_sz (6+NLM4_owner_sz) | ||
38 | |||
39 | #define NLM4_testargs_sz (NLM4_cookie_sz+1+NLM4_lock_sz) | ||
40 | #define NLM4_lockargs_sz (NLM4_cookie_sz+4+NLM4_lock_sz) | ||
41 | #define NLM4_cancargs_sz (NLM4_cookie_sz+2+NLM4_lock_sz) | ||
42 | #define NLM4_unlockargs_sz (NLM4_cookie_sz+NLM4_lock_sz) | ||
43 | |||
44 | #define NLM4_testres_sz (NLM4_cookie_sz+1+NLM4_holder_sz) | ||
45 | #define NLM4_res_sz (NLM4_cookie_sz+1) | ||
46 | #define NLM4_norep_sz (0) | ||
47 | |||
48 | |||
49 | static s64 loff_t_to_s64(loff_t offset) | ||
50 | { | ||
51 | s64 res; | ||
52 | |||
53 | if (offset >= NLM4_OFFSET_MAX) | ||
54 | res = NLM4_OFFSET_MAX; | ||
55 | else if (offset <= -NLM4_OFFSET_MAX) | ||
56 | res = -NLM4_OFFSET_MAX; | ||
57 | else | ||
58 | res = offset; | ||
59 | return res; | ||
60 | } | ||
61 | |||
62 | static void nlm4_compute_offsets(const struct nlm_lock *lock, | ||
63 | u64 *l_offset, u64 *l_len) | ||
64 | { | ||
65 | const struct file_lock *fl = &lock->fl; | ||
66 | |||
67 | BUG_ON(fl->fl_start > NLM4_OFFSET_MAX); | ||
68 | BUG_ON(fl->fl_end > NLM4_OFFSET_MAX && | ||
69 | fl->fl_end != OFFSET_MAX); | ||
70 | |||
71 | *l_offset = loff_t_to_s64(fl->fl_start); | ||
72 | if (fl->fl_end == OFFSET_MAX) | ||
73 | *l_len = 0; | ||
74 | else | ||
75 | *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Handle decode buffer overflows out-of-line. | ||
80 | */ | ||
81 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | ||
82 | { | ||
83 | dprintk("lockd: %s prematurely hit the end of our receive buffer. " | ||
84 | "Remaining buffer length is %tu words.\n", | ||
85 | func, xdr->end - xdr->p); | ||
86 | } | ||
87 | |||
88 | |||
89 | /* | ||
90 | * Encode/decode NLMv4 basic data types | ||
91 | * | ||
92 | * Basic NLMv4 data types are defined in Appendix II, section 6.1.4 | ||
93 | * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter | ||
94 | * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W". | ||
95 | * | ||
96 | * Not all basic data types have their own encoding and decoding | ||
97 | * functions. For run-time efficiency, some data types are encoded | ||
98 | * or decoded inline. | ||
99 | */ | ||
100 | |||
101 | static void encode_bool(struct xdr_stream *xdr, const int value) | ||
102 | { | ||
103 | __be32 *p; | ||
104 | |||
105 | p = xdr_reserve_space(xdr, 4); | ||
106 | *p = value ? xdr_one : xdr_zero; | ||
107 | } | ||
108 | |||
109 | static void encode_int32(struct xdr_stream *xdr, const s32 value) | ||
110 | { | ||
111 | __be32 *p; | ||
112 | |||
113 | p = xdr_reserve_space(xdr, 4); | ||
114 | *p = cpu_to_be32(value); | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * typedef opaque netobj<MAXNETOBJ_SZ> | ||
119 | */ | ||
120 | static void encode_netobj(struct xdr_stream *xdr, | ||
121 | const u8 *data, const unsigned int length) | ||
122 | { | ||
123 | __be32 *p; | ||
124 | |||
125 | BUG_ON(length > XDR_MAX_NETOBJ); | ||
126 | p = xdr_reserve_space(xdr, 4 + length); | ||
127 | xdr_encode_opaque(p, data, length); | ||
128 | } | ||
129 | |||
130 | static int decode_netobj(struct xdr_stream *xdr, | ||
131 | struct xdr_netobj *obj) | ||
132 | { | ||
133 | u32 length; | ||
134 | __be32 *p; | ||
135 | |||
136 | p = xdr_inline_decode(xdr, 4); | ||
137 | if (unlikely(p == NULL)) | ||
138 | goto out_overflow; | ||
139 | length = be32_to_cpup(p++); | ||
140 | if (unlikely(length > XDR_MAX_NETOBJ)) | ||
141 | goto out_size; | ||
142 | obj->len = length; | ||
143 | obj->data = (u8 *)p; | ||
144 | return 0; | ||
145 | out_size: | ||
146 | dprintk("NFS: returned netobj was too long: %u\n", length); | ||
147 | return -EIO; | ||
148 | out_overflow: | ||
149 | print_overflow_msg(__func__, xdr); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * netobj cookie; | ||
155 | */ | ||
156 | static void encode_cookie(struct xdr_stream *xdr, | ||
157 | const struct nlm_cookie *cookie) | ||
158 | { | ||
159 | BUG_ON(cookie->len > NLM_MAXCOOKIELEN); | ||
160 | encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); | ||
161 | } | ||
162 | |||
163 | static int decode_cookie(struct xdr_stream *xdr, | ||
164 | struct nlm_cookie *cookie) | ||
165 | { | ||
166 | u32 length; | ||
167 | __be32 *p; | ||
168 | |||
169 | p = xdr_inline_decode(xdr, 4); | ||
170 | if (unlikely(p == NULL)) | ||
171 | goto out_overflow; | ||
172 | length = be32_to_cpup(p++); | ||
173 | /* apparently HPUX can return empty cookies */ | ||
174 | if (length == 0) | ||
175 | goto out_hpux; | ||
176 | if (length > NLM_MAXCOOKIELEN) | ||
177 | goto out_size; | ||
178 | p = xdr_inline_decode(xdr, length); | ||
179 | if (unlikely(p == NULL)) | ||
180 | goto out_overflow; | ||
181 | cookie->len = length; | ||
182 | memcpy(cookie->data, p, length); | ||
183 | return 0; | ||
184 | out_hpux: | ||
185 | cookie->len = 4; | ||
186 | memset(cookie->data, 0, 4); | ||
187 | return 0; | ||
188 | out_size: | ||
189 | dprintk("NFS: returned cookie was too long: %u\n", length); | ||
190 | return -EIO; | ||
191 | out_overflow: | ||
192 | print_overflow_msg(__func__, xdr); | ||
193 | return -EIO; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * netobj fh; | ||
198 | */ | ||
199 | static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) | ||
200 | { | ||
201 | BUG_ON(fh->size > NFS3_FHSIZE); | ||
202 | encode_netobj(xdr, (u8 *)&fh->data, fh->size); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * enum nlm4_stats { | ||
207 | * NLM4_GRANTED = 0, | ||
208 | * NLM4_DENIED = 1, | ||
209 | * NLM4_DENIED_NOLOCKS = 2, | ||
210 | * NLM4_BLOCKED = 3, | ||
211 | * NLM4_DENIED_GRACE_PERIOD = 4, | ||
212 | * NLM4_DEADLCK = 5, | ||
213 | * NLM4_ROFS = 6, | ||
214 | * NLM4_STALE_FH = 7, | ||
215 | * NLM4_FBIG = 8, | ||
216 | * NLM4_FAILED = 9 | ||
217 | * }; | ||
218 | * | ||
219 | * struct nlm4_stat { | ||
220 | * nlm4_stats stat; | ||
221 | * }; | ||
222 | * | ||
223 | * NB: we don't swap bytes for the NLM status values. The upper | ||
224 | * layers deal directly with the status value in network byte | ||
225 | * order. | ||
226 | */ | ||
227 | static void encode_nlm4_stat(struct xdr_stream *xdr, | ||
228 | const __be32 stat) | ||
229 | { | ||
230 | __be32 *p; | ||
231 | |||
232 | BUG_ON(be32_to_cpu(stat) > NLM_FAILED); | ||
233 | p = xdr_reserve_space(xdr, 4); | ||
234 | *p = stat; | ||
235 | } | ||
236 | |||
237 | static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) | ||
238 | { | ||
239 | __be32 *p; | ||
240 | |||
241 | p = xdr_inline_decode(xdr, 4); | ||
242 | if (unlikely(p == NULL)) | ||
243 | goto out_overflow; | ||
244 | if (unlikely(*p > nlm4_failed)) | ||
245 | goto out_bad_xdr; | ||
246 | *stat = *p; | ||
247 | return 0; | ||
248 | out_bad_xdr: | ||
249 | dprintk("%s: server returned invalid nlm4_stats value: %u\n", | ||
250 | __func__, be32_to_cpup(p)); | ||
251 | return -EIO; | ||
252 | out_overflow: | ||
253 | print_overflow_msg(__func__, xdr); | ||
254 | return -EIO; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * struct nlm4_holder { | ||
259 | * bool exclusive; | ||
260 | * int32 svid; | ||
261 | * netobj oh; | ||
262 | * uint64 l_offset; | ||
263 | * uint64 l_len; | ||
264 | * }; | ||
265 | */ | ||
266 | static void encode_nlm4_holder(struct xdr_stream *xdr, | ||
267 | const struct nlm_res *result) | ||
268 | { | ||
269 | const struct nlm_lock *lock = &result->lock; | ||
270 | u64 l_offset, l_len; | ||
271 | __be32 *p; | ||
272 | |||
273 | encode_bool(xdr, lock->fl.fl_type == F_RDLCK); | ||
274 | encode_int32(xdr, lock->svid); | ||
275 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | ||
276 | |||
277 | p = xdr_reserve_space(xdr, 4 + 4); | ||
278 | nlm4_compute_offsets(lock, &l_offset, &l_len); | ||
279 | p = xdr_encode_hyper(p, l_offset); | ||
280 | xdr_encode_hyper(p, l_len); | ||
281 | } | ||
282 | |||
283 | static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) | ||
284 | { | ||
285 | struct nlm_lock *lock = &result->lock; | ||
286 | struct file_lock *fl = &lock->fl; | ||
287 | u64 l_offset, l_len; | ||
288 | u32 exclusive; | ||
289 | int error; | ||
290 | __be32 *p; | ||
291 | s32 end; | ||
292 | |||
293 | memset(lock, 0, sizeof(*lock)); | ||
294 | locks_init_lock(fl); | ||
295 | |||
296 | p = xdr_inline_decode(xdr, 4 + 4); | ||
297 | if (unlikely(p == NULL)) | ||
298 | goto out_overflow; | ||
299 | exclusive = be32_to_cpup(p++); | ||
300 | lock->svid = be32_to_cpup(p); | ||
301 | fl->fl_pid = (pid_t)lock->svid; | ||
302 | |||
303 | error = decode_netobj(xdr, &lock->oh); | ||
304 | if (unlikely(error)) | ||
305 | goto out; | ||
306 | |||
307 | p = xdr_inline_decode(xdr, 8 + 8); | ||
308 | if (unlikely(p == NULL)) | ||
309 | goto out_overflow; | ||
310 | |||
311 | fl->fl_flags = FL_POSIX; | ||
312 | fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; | ||
313 | p = xdr_decode_hyper(p, &l_offset); | ||
314 | xdr_decode_hyper(p, &l_len); | ||
315 | end = l_offset + l_len - 1; | ||
316 | |||
317 | fl->fl_start = (loff_t)l_offset; | ||
318 | if (l_len == 0 || end < 0) | ||
319 | fl->fl_end = OFFSET_MAX; | ||
320 | else | ||
321 | fl->fl_end = (loff_t)end; | ||
322 | error = 0; | ||
323 | out: | ||
324 | return error; | ||
325 | out_overflow: | ||
326 | print_overflow_msg(__func__, xdr); | ||
327 | return -EIO; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * string caller_name<LM_MAXSTRLEN>; | ||
332 | */ | ||
333 | static void encode_caller_name(struct xdr_stream *xdr, const char *name) | ||
334 | { | ||
335 | /* NB: client-side does not set lock->len */ | ||
336 | u32 length = strlen(name); | ||
337 | __be32 *p; | ||
338 | |||
339 | BUG_ON(length > NLM_MAXSTRLEN); | ||
340 | p = xdr_reserve_space(xdr, 4 + length); | ||
341 | xdr_encode_opaque(p, name, length); | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * struct nlm4_lock { | ||
346 | * string caller_name<LM_MAXSTRLEN>; | ||
347 | * netobj fh; | ||
348 | * netobj oh; | ||
349 | * int32 svid; | ||
350 | * uint64 l_offset; | ||
351 | * uint64 l_len; | ||
352 | * }; | ||
353 | */ | ||
354 | static void encode_nlm4_lock(struct xdr_stream *xdr, | ||
355 | const struct nlm_lock *lock) | ||
356 | { | ||
357 | u64 l_offset, l_len; | ||
358 | __be32 *p; | ||
359 | |||
360 | encode_caller_name(xdr, lock->caller); | ||
361 | encode_fh(xdr, &lock->fh); | ||
362 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | ||
363 | |||
364 | p = xdr_reserve_space(xdr, 4 + 8 + 8); | ||
365 | *p++ = cpu_to_be32(lock->svid); | ||
366 | |||
367 | nlm4_compute_offsets(lock, &l_offset, &l_len); | ||
368 | p = xdr_encode_hyper(p, l_offset); | ||
369 | xdr_encode_hyper(p, l_len); | ||
370 | } | ||
371 | |||
372 | |||
373 | /* | ||
374 | * NLMv4 XDR encode functions | ||
375 | * | ||
376 | * NLMv4 argument types are defined in Appendix II of RFC 1813: | ||
377 | * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's | ||
378 | * "Protocols for Interworking: XNFS, Version 3W". | ||
379 | */ | ||
380 | |||
381 | /* | ||
382 | * struct nlm4_testargs { | ||
383 | * netobj cookie; | ||
384 | * bool exclusive; | ||
385 | * struct nlm4_lock alock; | ||
386 | * }; | ||
387 | */ | ||
388 | static void nlm4_xdr_enc_testargs(struct rpc_rqst *req, | ||
389 | struct xdr_stream *xdr, | ||
390 | const struct nlm_args *args) | ||
391 | { | ||
392 | const struct nlm_lock *lock = &args->lock; | ||
393 | |||
394 | encode_cookie(xdr, &args->cookie); | ||
395 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
396 | encode_nlm4_lock(xdr, lock); | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * struct nlm4_lockargs { | ||
401 | * netobj cookie; | ||
402 | * bool block; | ||
403 | * bool exclusive; | ||
404 | * struct nlm4_lock alock; | ||
405 | * bool reclaim; | ||
406 | * int state; | ||
407 | * }; | ||
408 | */ | ||
409 | static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req, | ||
410 | struct xdr_stream *xdr, | ||
411 | const struct nlm_args *args) | ||
412 | { | ||
413 | const struct nlm_lock *lock = &args->lock; | ||
414 | |||
415 | encode_cookie(xdr, &args->cookie); | ||
416 | encode_bool(xdr, args->block); | ||
417 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
418 | encode_nlm4_lock(xdr, lock); | ||
419 | encode_bool(xdr, args->reclaim); | ||
420 | encode_int32(xdr, args->state); | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * struct nlm4_cancargs { | ||
425 | * netobj cookie; | ||
426 | * bool block; | ||
427 | * bool exclusive; | ||
428 | * struct nlm4_lock alock; | ||
429 | * }; | ||
430 | */ | ||
431 | static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req, | ||
432 | struct xdr_stream *xdr, | ||
433 | const struct nlm_args *args) | ||
434 | { | ||
435 | const struct nlm_lock *lock = &args->lock; | ||
436 | |||
437 | encode_cookie(xdr, &args->cookie); | ||
438 | encode_bool(xdr, args->block); | ||
439 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
440 | encode_nlm4_lock(xdr, lock); | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * struct nlm4_unlockargs { | ||
445 | * netobj cookie; | ||
446 | * struct nlm4_lock alock; | ||
447 | * }; | ||
448 | */ | ||
449 | static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, | ||
450 | struct xdr_stream *xdr, | ||
451 | const struct nlm_args *args) | ||
452 | { | ||
453 | const struct nlm_lock *lock = &args->lock; | ||
454 | |||
455 | encode_cookie(xdr, &args->cookie); | ||
456 | encode_nlm4_lock(xdr, lock); | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * struct nlm4_res { | ||
461 | * netobj cookie; | ||
462 | * nlm4_stat stat; | ||
463 | * }; | ||
464 | */ | ||
465 | static void nlm4_xdr_enc_res(struct rpc_rqst *req, | ||
466 | struct xdr_stream *xdr, | ||
467 | const struct nlm_res *result) | ||
468 | { | ||
469 | encode_cookie(xdr, &result->cookie); | ||
470 | encode_nlm4_stat(xdr, result->status); | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | * union nlm4_testrply switch (nlm4_stats stat) { | ||
475 | * case NLM4_DENIED: | ||
476 | * struct nlm4_holder holder; | ||
477 | * default: | ||
478 | * void; | ||
479 | * }; | ||
480 | * | ||
481 | * struct nlm4_testres { | ||
482 | * netobj cookie; | ||
483 | * nlm4_testrply test_stat; | ||
484 | * }; | ||
485 | */ | ||
486 | static void nlm4_xdr_enc_testres(struct rpc_rqst *req, | ||
487 | struct xdr_stream *xdr, | ||
488 | const struct nlm_res *result) | ||
489 | { | ||
490 | encode_cookie(xdr, &result->cookie); | ||
491 | encode_nlm4_stat(xdr, result->status); | ||
492 | if (result->status == nlm_lck_denied) | ||
493 | encode_nlm4_holder(xdr, result); | ||
494 | } | ||
495 | |||
496 | |||
497 | /* | ||
498 | * NLMv4 XDR decode functions | ||
499 | * | ||
500 | * NLMv4 argument types are defined in Appendix II of RFC 1813: | ||
501 | * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's | ||
502 | * "Protocols for Interworking: XNFS, Version 3W". | ||
503 | */ | ||
504 | |||
505 | /* | ||
506 | * union nlm4_testrply switch (nlm4_stats stat) { | ||
507 | * case NLM4_DENIED: | ||
508 | * struct nlm4_holder holder; | ||
509 | * default: | ||
510 | * void; | ||
511 | * }; | ||
512 | * | ||
513 | * struct nlm4_testres { | ||
514 | * netobj cookie; | ||
515 | * nlm4_testrply test_stat; | ||
516 | * }; | ||
517 | */ | ||
518 | static int decode_nlm4_testrply(struct xdr_stream *xdr, | ||
519 | struct nlm_res *result) | ||
520 | { | ||
521 | int error; | ||
522 | |||
523 | error = decode_nlm4_stat(xdr, &result->status); | ||
524 | if (unlikely(error)) | ||
525 | goto out; | ||
526 | if (result->status == nlm_lck_denied) | ||
527 | error = decode_nlm4_holder(xdr, result); | ||
528 | out: | ||
529 | return error; | ||
530 | } | ||
531 | |||
532 | static int nlm4_xdr_dec_testres(struct rpc_rqst *req, | ||
533 | struct xdr_stream *xdr, | ||
534 | struct nlm_res *result) | ||
535 | { | ||
536 | int error; | ||
537 | |||
538 | error = decode_cookie(xdr, &result->cookie); | ||
539 | if (unlikely(error)) | ||
540 | goto out; | ||
541 | error = decode_nlm4_testrply(xdr, result); | ||
542 | out: | ||
543 | return error; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * struct nlm4_res { | ||
548 | * netobj cookie; | ||
549 | * nlm4_stat stat; | ||
550 | * }; | ||
551 | */ | ||
552 | static int nlm4_xdr_dec_res(struct rpc_rqst *req, | ||
553 | struct xdr_stream *xdr, | ||
554 | struct nlm_res *result) | ||
555 | { | ||
556 | int error; | ||
557 | |||
558 | error = decode_cookie(xdr, &result->cookie); | ||
559 | if (unlikely(error)) | ||
560 | goto out; | ||
561 | error = decode_nlm4_stat(xdr, &result->status); | ||
562 | out: | ||
563 | return error; | ||
564 | } | ||
565 | |||
566 | |||
567 | /* | ||
568 | * For NLM, a void procedure really returns nothing | ||
569 | */ | ||
570 | #define nlm4_xdr_dec_norep NULL | ||
571 | |||
572 | #define PROC(proc, argtype, restype) \ | ||
573 | [NLMPROC_##proc] = { \ | ||
574 | .p_proc = NLMPROC_##proc, \ | ||
575 | .p_encode = (kxdreproc_t)nlm4_xdr_enc_##argtype, \ | ||
576 | .p_decode = (kxdrdproc_t)nlm4_xdr_dec_##restype, \ | ||
577 | .p_arglen = NLM4_##argtype##_sz, \ | ||
578 | .p_replen = NLM4_##restype##_sz, \ | ||
579 | .p_statidx = NLMPROC_##proc, \ | ||
580 | .p_name = #proc, \ | ||
581 | } | ||
582 | |||
583 | static struct rpc_procinfo nlm4_procedures[] = { | ||
584 | PROC(TEST, testargs, testres), | ||
585 | PROC(LOCK, lockargs, res), | ||
586 | PROC(CANCEL, cancargs, res), | ||
587 | PROC(UNLOCK, unlockargs, res), | ||
588 | PROC(GRANTED, testargs, res), | ||
589 | PROC(TEST_MSG, testargs, norep), | ||
590 | PROC(LOCK_MSG, lockargs, norep), | ||
591 | PROC(CANCEL_MSG, cancargs, norep), | ||
592 | PROC(UNLOCK_MSG, unlockargs, norep), | ||
593 | PROC(GRANTED_MSG, testargs, norep), | ||
594 | PROC(TEST_RES, testres, norep), | ||
595 | PROC(LOCK_RES, res, norep), | ||
596 | PROC(CANCEL_RES, res, norep), | ||
597 | PROC(UNLOCK_RES, res, norep), | ||
598 | PROC(GRANTED_RES, res, norep), | ||
599 | }; | ||
600 | |||
601 | struct rpc_version nlm_version4 = { | ||
602 | .number = 4, | ||
603 | .nrprocs = ARRAY_SIZE(nlm4_procedures), | ||
604 | .procs = nlm4_procedures, | ||
605 | }; | ||
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 25509eb28fd7..8d4ea8351e3d 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(nlmclnt_init); | |||
79 | */ | 79 | */ |
80 | void nlmclnt_done(struct nlm_host *host) | 80 | void nlmclnt_done(struct nlm_host *host) |
81 | { | 81 | { |
82 | nlm_release_host(host); | 82 | nlmclnt_release_host(host); |
83 | lockd_down(); | 83 | lockd_down(); |
84 | } | 84 | } |
85 | EXPORT_SYMBOL_GPL(nlmclnt_done); | 85 | EXPORT_SYMBOL_GPL(nlmclnt_done); |
@@ -273,7 +273,7 @@ restart: | |||
273 | spin_unlock(&nlm_blocked_lock); | 273 | spin_unlock(&nlm_blocked_lock); |
274 | 274 | ||
275 | /* Release host handle after use */ | 275 | /* Release host handle after use */ |
276 | nlm_release_host(host); | 276 | nlmclnt_release_host(host); |
277 | lockd_down(); | 277 | lockd_down(); |
278 | return 0; | 278 | return 0; |
279 | } | 279 | } |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 332c54cf75e0..adb45ec9038c 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -58,7 +58,7 @@ static void nlm_put_lockowner(struct nlm_lockowner *lockowner) | |||
58 | return; | 58 | return; |
59 | list_del(&lockowner->list); | 59 | list_del(&lockowner->list); |
60 | spin_unlock(&lockowner->host->h_lock); | 60 | spin_unlock(&lockowner->host->h_lock); |
61 | nlm_release_host(lockowner->host); | 61 | nlmclnt_release_host(lockowner->host); |
62 | kfree(lockowner); | 62 | kfree(lockowner); |
63 | } | 63 | } |
64 | 64 | ||
@@ -207,22 +207,22 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
207 | printk("nlm_alloc_call: failed, waiting for memory\n"); | 207 | printk("nlm_alloc_call: failed, waiting for memory\n"); |
208 | schedule_timeout_interruptible(5*HZ); | 208 | schedule_timeout_interruptible(5*HZ); |
209 | } | 209 | } |
210 | nlm_release_host(host); | 210 | nlmclnt_release_host(host); |
211 | return NULL; | 211 | return NULL; |
212 | } | 212 | } |
213 | 213 | ||
214 | void nlm_release_call(struct nlm_rqst *call) | 214 | void nlmclnt_release_call(struct nlm_rqst *call) |
215 | { | 215 | { |
216 | if (!atomic_dec_and_test(&call->a_count)) | 216 | if (!atomic_dec_and_test(&call->a_count)) |
217 | return; | 217 | return; |
218 | nlm_release_host(call->a_host); | 218 | nlmclnt_release_host(call->a_host); |
219 | nlmclnt_release_lockargs(call); | 219 | nlmclnt_release_lockargs(call); |
220 | kfree(call); | 220 | kfree(call); |
221 | } | 221 | } |
222 | 222 | ||
223 | static void nlmclnt_rpc_release(void *data) | 223 | static void nlmclnt_rpc_release(void *data) |
224 | { | 224 | { |
225 | nlm_release_call(data); | 225 | nlmclnt_release_call(data); |
226 | } | 226 | } |
227 | 227 | ||
228 | static int nlm_wait_on_grace(wait_queue_head_t *queue) | 228 | static int nlm_wait_on_grace(wait_queue_head_t *queue) |
@@ -436,7 +436,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
436 | status = nlm_stat_to_errno(req->a_res.status); | 436 | status = nlm_stat_to_errno(req->a_res.status); |
437 | } | 437 | } |
438 | out: | 438 | out: |
439 | nlm_release_call(req); | 439 | nlmclnt_release_call(req); |
440 | return status; | 440 | return status; |
441 | } | 441 | } |
442 | 442 | ||
@@ -593,7 +593,7 @@ again: | |||
593 | out_unblock: | 593 | out_unblock: |
594 | nlmclnt_finish_block(block); | 594 | nlmclnt_finish_block(block); |
595 | out: | 595 | out: |
596 | nlm_release_call(req); | 596 | nlmclnt_release_call(req); |
597 | return status; | 597 | return status; |
598 | out_unlock: | 598 | out_unlock: |
599 | /* Fatal error: ensure that we remove the lock altogether */ | 599 | /* Fatal error: ensure that we remove the lock altogether */ |
@@ -694,7 +694,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
694 | /* What to do now? I'm out of my depth... */ | 694 | /* What to do now? I'm out of my depth... */ |
695 | status = -ENOLCK; | 695 | status = -ENOLCK; |
696 | out: | 696 | out: |
697 | nlm_release_call(req); | 697 | nlmclnt_release_call(req); |
698 | return status; | 698 | return status; |
699 | } | 699 | } |
700 | 700 | ||
@@ -755,7 +755,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
755 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 755 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
756 | if (status == 0 && req->a_res.status == nlm_lck_denied) | 756 | if (status == 0 && req->a_res.status == nlm_lck_denied) |
757 | status = -ENOLCK; | 757 | status = -ENOLCK; |
758 | nlm_release_call(req); | 758 | nlmclnt_release_call(req); |
759 | return status; | 759 | return status; |
760 | } | 760 | } |
761 | 761 | ||
diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c new file mode 100644 index 000000000000..180ac34feb9a --- /dev/null +++ b/fs/lockd/clntxdr.c | |||
@@ -0,0 +1,627 @@ | |||
1 | /* | ||
2 | * linux/fs/lockd/clntxdr.c | ||
3 | * | ||
4 | * XDR functions to encode/decode NLM version 3 RPC arguments and results. | ||
5 | * NLM version 3 is backwards compatible with NLM versions 1 and 2. | ||
6 | * | ||
7 | * NLM client-side only. | ||
8 | * | ||
9 | * Copyright (C) 2010, Oracle. All rights reserved. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/sunrpc/xdr.h> | ||
14 | #include <linux/sunrpc/clnt.h> | ||
15 | #include <linux/sunrpc/stats.h> | ||
16 | #include <linux/lockd/lockd.h> | ||
17 | |||
18 | #define NLMDBG_FACILITY NLMDBG_XDR | ||
19 | |||
20 | #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) | ||
21 | # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" | ||
22 | #endif | ||
23 | |||
24 | /* | ||
25 | * Declare the space requirements for NLM arguments and replies as | ||
26 | * number of 32bit-words | ||
27 | */ | ||
28 | #define NLM_cookie_sz (1+(NLM_MAXCOOKIELEN>>2)) | ||
29 | #define NLM_caller_sz (1+(NLMCLNT_OHSIZE>>2)) | ||
30 | #define NLM_owner_sz (1+(NLMCLNT_OHSIZE>>2)) | ||
31 | #define NLM_fhandle_sz (1+(NFS2_FHSIZE>>2)) | ||
32 | #define NLM_lock_sz (3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz) | ||
33 | #define NLM_holder_sz (4+NLM_owner_sz) | ||
34 | |||
35 | #define NLM_testargs_sz (NLM_cookie_sz+1+NLM_lock_sz) | ||
36 | #define NLM_lockargs_sz (NLM_cookie_sz+4+NLM_lock_sz) | ||
37 | #define NLM_cancargs_sz (NLM_cookie_sz+2+NLM_lock_sz) | ||
38 | #define NLM_unlockargs_sz (NLM_cookie_sz+NLM_lock_sz) | ||
39 | |||
40 | #define NLM_testres_sz (NLM_cookie_sz+1+NLM_holder_sz) | ||
41 | #define NLM_res_sz (NLM_cookie_sz+1) | ||
42 | #define NLM_norep_sz (0) | ||
43 | |||
44 | |||
45 | static s32 loff_t_to_s32(loff_t offset) | ||
46 | { | ||
47 | s32 res; | ||
48 | |||
49 | if (offset >= NLM_OFFSET_MAX) | ||
50 | res = NLM_OFFSET_MAX; | ||
51 | else if (offset <= -NLM_OFFSET_MAX) | ||
52 | res = -NLM_OFFSET_MAX; | ||
53 | else | ||
54 | res = offset; | ||
55 | return res; | ||
56 | } | ||
57 | |||
58 | static void nlm_compute_offsets(const struct nlm_lock *lock, | ||
59 | u32 *l_offset, u32 *l_len) | ||
60 | { | ||
61 | const struct file_lock *fl = &lock->fl; | ||
62 | |||
63 | BUG_ON(fl->fl_start > NLM_OFFSET_MAX); | ||
64 | BUG_ON(fl->fl_end > NLM_OFFSET_MAX && | ||
65 | fl->fl_end != OFFSET_MAX); | ||
66 | |||
67 | *l_offset = loff_t_to_s32(fl->fl_start); | ||
68 | if (fl->fl_end == OFFSET_MAX) | ||
69 | *l_len = 0; | ||
70 | else | ||
71 | *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Handle decode buffer overflows out-of-line. | ||
76 | */ | ||
77 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | ||
78 | { | ||
79 | dprintk("lockd: %s prematurely hit the end of our receive buffer. " | ||
80 | "Remaining buffer length is %tu words.\n", | ||
81 | func, xdr->end - xdr->p); | ||
82 | } | ||
83 | |||
84 | |||
85 | /* | ||
86 | * Encode/decode NLMv3 basic data types | ||
87 | * | ||
88 | * Basic NLMv3 data types are not defined in an IETF standards | ||
89 | * document. X/Open has a description of these data types that | ||
90 | * is useful. See Chapter 10 of "Protocols for Interworking: | ||
91 | * XNFS, Version 3W". | ||
92 | * | ||
93 | * Not all basic data types have their own encoding and decoding | ||
94 | * functions. For run-time efficiency, some data types are encoded | ||
95 | * or decoded inline. | ||
96 | */ | ||
97 | |||
98 | static void encode_bool(struct xdr_stream *xdr, const int value) | ||
99 | { | ||
100 | __be32 *p; | ||
101 | |||
102 | p = xdr_reserve_space(xdr, 4); | ||
103 | *p = value ? xdr_one : xdr_zero; | ||
104 | } | ||
105 | |||
106 | static void encode_int32(struct xdr_stream *xdr, const s32 value) | ||
107 | { | ||
108 | __be32 *p; | ||
109 | |||
110 | p = xdr_reserve_space(xdr, 4); | ||
111 | *p = cpu_to_be32(value); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * typedef opaque netobj<MAXNETOBJ_SZ> | ||
116 | */ | ||
117 | static void encode_netobj(struct xdr_stream *xdr, | ||
118 | const u8 *data, const unsigned int length) | ||
119 | { | ||
120 | __be32 *p; | ||
121 | |||
122 | BUG_ON(length > XDR_MAX_NETOBJ); | ||
123 | p = xdr_reserve_space(xdr, 4 + length); | ||
124 | xdr_encode_opaque(p, data, length); | ||
125 | } | ||
126 | |||
127 | static int decode_netobj(struct xdr_stream *xdr, | ||
128 | struct xdr_netobj *obj) | ||
129 | { | ||
130 | u32 length; | ||
131 | __be32 *p; | ||
132 | |||
133 | p = xdr_inline_decode(xdr, 4); | ||
134 | if (unlikely(p == NULL)) | ||
135 | goto out_overflow; | ||
136 | length = be32_to_cpup(p++); | ||
137 | if (unlikely(length > XDR_MAX_NETOBJ)) | ||
138 | goto out_size; | ||
139 | obj->len = length; | ||
140 | obj->data = (u8 *)p; | ||
141 | return 0; | ||
142 | out_size: | ||
143 | dprintk("NFS: returned netobj was too long: %u\n", length); | ||
144 | return -EIO; | ||
145 | out_overflow: | ||
146 | print_overflow_msg(__func__, xdr); | ||
147 | return -EIO; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * netobj cookie; | ||
152 | */ | ||
153 | static void encode_cookie(struct xdr_stream *xdr, | ||
154 | const struct nlm_cookie *cookie) | ||
155 | { | ||
156 | BUG_ON(cookie->len > NLM_MAXCOOKIELEN); | ||
157 | encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); | ||
158 | } | ||
159 | |||
160 | static int decode_cookie(struct xdr_stream *xdr, | ||
161 | struct nlm_cookie *cookie) | ||
162 | { | ||
163 | u32 length; | ||
164 | __be32 *p; | ||
165 | |||
166 | p = xdr_inline_decode(xdr, 4); | ||
167 | if (unlikely(p == NULL)) | ||
168 | goto out_overflow; | ||
169 | length = be32_to_cpup(p++); | ||
170 | /* apparently HPUX can return empty cookies */ | ||
171 | if (length == 0) | ||
172 | goto out_hpux; | ||
173 | if (length > NLM_MAXCOOKIELEN) | ||
174 | goto out_size; | ||
175 | p = xdr_inline_decode(xdr, length); | ||
176 | if (unlikely(p == NULL)) | ||
177 | goto out_overflow; | ||
178 | cookie->len = length; | ||
179 | memcpy(cookie->data, p, length); | ||
180 | return 0; | ||
181 | out_hpux: | ||
182 | cookie->len = 4; | ||
183 | memset(cookie->data, 0, 4); | ||
184 | return 0; | ||
185 | out_size: | ||
186 | dprintk("NFS: returned cookie was too long: %u\n", length); | ||
187 | return -EIO; | ||
188 | out_overflow: | ||
189 | print_overflow_msg(__func__, xdr); | ||
190 | return -EIO; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * netobj fh; | ||
195 | */ | ||
196 | static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) | ||
197 | { | ||
198 | BUG_ON(fh->size != NFS2_FHSIZE); | ||
199 | encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * enum nlm_stats { | ||
204 | * LCK_GRANTED = 0, | ||
205 | * LCK_DENIED = 1, | ||
206 | * LCK_DENIED_NOLOCKS = 2, | ||
207 | * LCK_BLOCKED = 3, | ||
208 | * LCK_DENIED_GRACE_PERIOD = 4 | ||
209 | * }; | ||
210 | * | ||
211 | * | ||
212 | * struct nlm_stat { | ||
213 | * nlm_stats stat; | ||
214 | * }; | ||
215 | * | ||
216 | * NB: we don't swap bytes for the NLM status values. The upper | ||
217 | * layers deal directly with the status value in network byte | ||
218 | * order. | ||
219 | */ | ||
220 | |||
221 | static void encode_nlm_stat(struct xdr_stream *xdr, | ||
222 | const __be32 stat) | ||
223 | { | ||
224 | __be32 *p; | ||
225 | |||
226 | BUG_ON(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD); | ||
227 | p = xdr_reserve_space(xdr, 4); | ||
228 | *p = stat; | ||
229 | } | ||
230 | |||
231 | static int decode_nlm_stat(struct xdr_stream *xdr, | ||
232 | __be32 *stat) | ||
233 | { | ||
234 | __be32 *p; | ||
235 | |||
236 | p = xdr_inline_decode(xdr, 4); | ||
237 | if (unlikely(p == NULL)) | ||
238 | goto out_overflow; | ||
239 | if (unlikely(*p > nlm_lck_denied_grace_period)) | ||
240 | goto out_enum; | ||
241 | *stat = *p; | ||
242 | return 0; | ||
243 | out_enum: | ||
244 | dprintk("%s: server returned invalid nlm_stats value: %u\n", | ||
245 | __func__, be32_to_cpup(p)); | ||
246 | return -EIO; | ||
247 | out_overflow: | ||
248 | print_overflow_msg(__func__, xdr); | ||
249 | return -EIO; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * struct nlm_holder { | ||
254 | * bool exclusive; | ||
255 | * int uppid; | ||
256 | * netobj oh; | ||
257 | * unsigned l_offset; | ||
258 | * unsigned l_len; | ||
259 | * }; | ||
260 | */ | ||
261 | static void encode_nlm_holder(struct xdr_stream *xdr, | ||
262 | const struct nlm_res *result) | ||
263 | { | ||
264 | const struct nlm_lock *lock = &result->lock; | ||
265 | u32 l_offset, l_len; | ||
266 | __be32 *p; | ||
267 | |||
268 | encode_bool(xdr, lock->fl.fl_type == F_RDLCK); | ||
269 | encode_int32(xdr, lock->svid); | ||
270 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | ||
271 | |||
272 | p = xdr_reserve_space(xdr, 4 + 4); | ||
273 | nlm_compute_offsets(lock, &l_offset, &l_len); | ||
274 | *p++ = cpu_to_be32(l_offset); | ||
275 | *p = cpu_to_be32(l_len); | ||
276 | } | ||
277 | |||
278 | static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result) | ||
279 | { | ||
280 | struct nlm_lock *lock = &result->lock; | ||
281 | struct file_lock *fl = &lock->fl; | ||
282 | u32 exclusive, l_offset, l_len; | ||
283 | int error; | ||
284 | __be32 *p; | ||
285 | s32 end; | ||
286 | |||
287 | memset(lock, 0, sizeof(*lock)); | ||
288 | locks_init_lock(fl); | ||
289 | |||
290 | p = xdr_inline_decode(xdr, 4 + 4); | ||
291 | if (unlikely(p == NULL)) | ||
292 | goto out_overflow; | ||
293 | exclusive = be32_to_cpup(p++); | ||
294 | lock->svid = be32_to_cpup(p); | ||
295 | fl->fl_pid = (pid_t)lock->svid; | ||
296 | |||
297 | error = decode_netobj(xdr, &lock->oh); | ||
298 | if (unlikely(error)) | ||
299 | goto out; | ||
300 | |||
301 | p = xdr_inline_decode(xdr, 4 + 4); | ||
302 | if (unlikely(p == NULL)) | ||
303 | goto out_overflow; | ||
304 | |||
305 | fl->fl_flags = FL_POSIX; | ||
306 | fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; | ||
307 | l_offset = be32_to_cpup(p++); | ||
308 | l_len = be32_to_cpup(p); | ||
309 | end = l_offset + l_len - 1; | ||
310 | |||
311 | fl->fl_start = (loff_t)l_offset; | ||
312 | if (l_len == 0 || end < 0) | ||
313 | fl->fl_end = OFFSET_MAX; | ||
314 | else | ||
315 | fl->fl_end = (loff_t)end; | ||
316 | error = 0; | ||
317 | out: | ||
318 | return error; | ||
319 | out_overflow: | ||
320 | print_overflow_msg(__func__, xdr); | ||
321 | return -EIO; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * string caller_name<LM_MAXSTRLEN>; | ||
326 | */ | ||
327 | static void encode_caller_name(struct xdr_stream *xdr, const char *name) | ||
328 | { | ||
329 | /* NB: client-side does not set lock->len */ | ||
330 | u32 length = strlen(name); | ||
331 | __be32 *p; | ||
332 | |||
333 | BUG_ON(length > NLM_MAXSTRLEN); | ||
334 | p = xdr_reserve_space(xdr, 4 + length); | ||
335 | xdr_encode_opaque(p, name, length); | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * struct nlm_lock { | ||
340 | * string caller_name<LM_MAXSTRLEN>; | ||
341 | * netobj fh; | ||
342 | * netobj oh; | ||
343 | * int uppid; | ||
344 | * unsigned l_offset; | ||
345 | * unsigned l_len; | ||
346 | * }; | ||
347 | */ | ||
348 | static void encode_nlm_lock(struct xdr_stream *xdr, | ||
349 | const struct nlm_lock *lock) | ||
350 | { | ||
351 | u32 l_offset, l_len; | ||
352 | __be32 *p; | ||
353 | |||
354 | encode_caller_name(xdr, lock->caller); | ||
355 | encode_fh(xdr, &lock->fh); | ||
356 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | ||
357 | |||
358 | p = xdr_reserve_space(xdr, 4 + 4 + 4); | ||
359 | *p++ = cpu_to_be32(lock->svid); | ||
360 | |||
361 | nlm_compute_offsets(lock, &l_offset, &l_len); | ||
362 | *p++ = cpu_to_be32(l_offset); | ||
363 | *p = cpu_to_be32(l_len); | ||
364 | } | ||
365 | |||
366 | |||
367 | /* | ||
368 | * NLMv3 XDR encode functions | ||
369 | * | ||
370 | * NLMv3 argument types are defined in Chapter 10 of The Open Group's | ||
371 | * "Protocols for Interworking: XNFS, Version 3W". | ||
372 | */ | ||
373 | |||
374 | /* | ||
375 | * struct nlm_testargs { | ||
376 | * netobj cookie; | ||
377 | * bool exclusive; | ||
378 | * struct nlm_lock alock; | ||
379 | * }; | ||
380 | */ | ||
381 | static void nlm_xdr_enc_testargs(struct rpc_rqst *req, | ||
382 | struct xdr_stream *xdr, | ||
383 | const struct nlm_args *args) | ||
384 | { | ||
385 | const struct nlm_lock *lock = &args->lock; | ||
386 | |||
387 | encode_cookie(xdr, &args->cookie); | ||
388 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
389 | encode_nlm_lock(xdr, lock); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * struct nlm_lockargs { | ||
394 | * netobj cookie; | ||
395 | * bool block; | ||
396 | * bool exclusive; | ||
397 | * struct nlm_lock alock; | ||
398 | * bool reclaim; | ||
399 | * int state; | ||
400 | * }; | ||
401 | */ | ||
402 | static void nlm_xdr_enc_lockargs(struct rpc_rqst *req, | ||
403 | struct xdr_stream *xdr, | ||
404 | const struct nlm_args *args) | ||
405 | { | ||
406 | const struct nlm_lock *lock = &args->lock; | ||
407 | |||
408 | encode_cookie(xdr, &args->cookie); | ||
409 | encode_bool(xdr, args->block); | ||
410 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
411 | encode_nlm_lock(xdr, lock); | ||
412 | encode_bool(xdr, args->reclaim); | ||
413 | encode_int32(xdr, args->state); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * struct nlm_cancargs { | ||
418 | * netobj cookie; | ||
419 | * bool block; | ||
420 | * bool exclusive; | ||
421 | * struct nlm_lock alock; | ||
422 | * }; | ||
423 | */ | ||
424 | static void nlm_xdr_enc_cancargs(struct rpc_rqst *req, | ||
425 | struct xdr_stream *xdr, | ||
426 | const struct nlm_args *args) | ||
427 | { | ||
428 | const struct nlm_lock *lock = &args->lock; | ||
429 | |||
430 | encode_cookie(xdr, &args->cookie); | ||
431 | encode_bool(xdr, args->block); | ||
432 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | ||
433 | encode_nlm_lock(xdr, lock); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * struct nlm_unlockargs { | ||
438 | * netobj cookie; | ||
439 | * struct nlm_lock alock; | ||
440 | * }; | ||
441 | */ | ||
442 | static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req, | ||
443 | struct xdr_stream *xdr, | ||
444 | const struct nlm_args *args) | ||
445 | { | ||
446 | const struct nlm_lock *lock = &args->lock; | ||
447 | |||
448 | encode_cookie(xdr, &args->cookie); | ||
449 | encode_nlm_lock(xdr, lock); | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * struct nlm_res { | ||
454 | * netobj cookie; | ||
455 | * nlm_stat stat; | ||
456 | * }; | ||
457 | */ | ||
458 | static void nlm_xdr_enc_res(struct rpc_rqst *req, | ||
459 | struct xdr_stream *xdr, | ||
460 | const struct nlm_res *result) | ||
461 | { | ||
462 | encode_cookie(xdr, &result->cookie); | ||
463 | encode_nlm_stat(xdr, result->status); | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * union nlm_testrply switch (nlm_stats stat) { | ||
468 | * case LCK_DENIED: | ||
469 | * struct nlm_holder holder; | ||
470 | * default: | ||
471 | * void; | ||
472 | * }; | ||
473 | * | ||
474 | * struct nlm_testres { | ||
475 | * netobj cookie; | ||
476 | * nlm_testrply test_stat; | ||
477 | * }; | ||
478 | */ | ||
479 | static void encode_nlm_testrply(struct xdr_stream *xdr, | ||
480 | const struct nlm_res *result) | ||
481 | { | ||
482 | if (result->status == nlm_lck_denied) | ||
483 | encode_nlm_holder(xdr, result); | ||
484 | } | ||
485 | |||
486 | static void nlm_xdr_enc_testres(struct rpc_rqst *req, | ||
487 | struct xdr_stream *xdr, | ||
488 | const struct nlm_res *result) | ||
489 | { | ||
490 | encode_cookie(xdr, &result->cookie); | ||
491 | encode_nlm_stat(xdr, result->status); | ||
492 | encode_nlm_testrply(xdr, result); | ||
493 | } | ||
494 | |||
495 | |||
496 | /* | ||
497 | * NLMv3 XDR decode functions | ||
498 | * | ||
499 | * NLMv3 result types are defined in Chapter 10 of The Open Group's | ||
500 | * "Protocols for Interworking: XNFS, Version 3W". | ||
501 | */ | ||
502 | |||
503 | /* | ||
504 | * union nlm_testrply switch (nlm_stats stat) { | ||
505 | * case LCK_DENIED: | ||
506 | * struct nlm_holder holder; | ||
507 | * default: | ||
508 | * void; | ||
509 | * }; | ||
510 | * | ||
511 | * struct nlm_testres { | ||
512 | * netobj cookie; | ||
513 | * nlm_testrply test_stat; | ||
514 | * }; | ||
515 | */ | ||
516 | static int decode_nlm_testrply(struct xdr_stream *xdr, | ||
517 | struct nlm_res *result) | ||
518 | { | ||
519 | int error; | ||
520 | |||
521 | error = decode_nlm_stat(xdr, &result->status); | ||
522 | if (unlikely(error)) | ||
523 | goto out; | ||
524 | if (result->status == nlm_lck_denied) | ||
525 | error = decode_nlm_holder(xdr, result); | ||
526 | out: | ||
527 | return error; | ||
528 | } | ||
529 | |||
530 | static int nlm_xdr_dec_testres(struct rpc_rqst *req, | ||
531 | struct xdr_stream *xdr, | ||
532 | struct nlm_res *result) | ||
533 | { | ||
534 | int error; | ||
535 | |||
536 | error = decode_cookie(xdr, &result->cookie); | ||
537 | if (unlikely(error)) | ||
538 | goto out; | ||
539 | error = decode_nlm_testrply(xdr, result); | ||
540 | out: | ||
541 | return error; | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * struct nlm_res { | ||
546 | * netobj cookie; | ||
547 | * nlm_stat stat; | ||
548 | * }; | ||
549 | */ | ||
550 | static int nlm_xdr_dec_res(struct rpc_rqst *req, | ||
551 | struct xdr_stream *xdr, | ||
552 | struct nlm_res *result) | ||
553 | { | ||
554 | int error; | ||
555 | |||
556 | error = decode_cookie(xdr, &result->cookie); | ||
557 | if (unlikely(error)) | ||
558 | goto out; | ||
559 | error = decode_nlm_stat(xdr, &result->status); | ||
560 | out: | ||
561 | return error; | ||
562 | } | ||
563 | |||
564 | |||
565 | /* | ||
566 | * For NLM, a void procedure really returns nothing | ||
567 | */ | ||
568 | #define nlm_xdr_dec_norep NULL | ||
569 | |||
570 | #define PROC(proc, argtype, restype) \ | ||
571 | [NLMPROC_##proc] = { \ | ||
572 | .p_proc = NLMPROC_##proc, \ | ||
573 | .p_encode = (kxdreproc_t)nlm_xdr_enc_##argtype, \ | ||
574 | .p_decode = (kxdrdproc_t)nlm_xdr_dec_##restype, \ | ||
575 | .p_arglen = NLM_##argtype##_sz, \ | ||
576 | .p_replen = NLM_##restype##_sz, \ | ||
577 | .p_statidx = NLMPROC_##proc, \ | ||
578 | .p_name = #proc, \ | ||
579 | } | ||
580 | |||
581 | static struct rpc_procinfo nlm_procedures[] = { | ||
582 | PROC(TEST, testargs, testres), | ||
583 | PROC(LOCK, lockargs, res), | ||
584 | PROC(CANCEL, cancargs, res), | ||
585 | PROC(UNLOCK, unlockargs, res), | ||
586 | PROC(GRANTED, testargs, res), | ||
587 | PROC(TEST_MSG, testargs, norep), | ||
588 | PROC(LOCK_MSG, lockargs, norep), | ||
589 | PROC(CANCEL_MSG, cancargs, norep), | ||
590 | PROC(UNLOCK_MSG, unlockargs, norep), | ||
591 | PROC(GRANTED_MSG, testargs, norep), | ||
592 | PROC(TEST_RES, testres, norep), | ||
593 | PROC(LOCK_RES, res, norep), | ||
594 | PROC(CANCEL_RES, res, norep), | ||
595 | PROC(UNLOCK_RES, res, norep), | ||
596 | PROC(GRANTED_RES, res, norep), | ||
597 | }; | ||
598 | |||
599 | static struct rpc_version nlm_version1 = { | ||
600 | .number = 1, | ||
601 | .nrprocs = ARRAY_SIZE(nlm_procedures), | ||
602 | .procs = nlm_procedures, | ||
603 | }; | ||
604 | |||
605 | static struct rpc_version nlm_version3 = { | ||
606 | .number = 3, | ||
607 | .nrprocs = ARRAY_SIZE(nlm_procedures), | ||
608 | .procs = nlm_procedures, | ||
609 | }; | ||
610 | |||
611 | static struct rpc_version *nlm_versions[] = { | ||
612 | [1] = &nlm_version1, | ||
613 | [3] = &nlm_version3, | ||
614 | #ifdef CONFIG_LOCKD_V4 | ||
615 | [4] = &nlm_version4, | ||
616 | #endif | ||
617 | }; | ||
618 | |||
619 | static struct rpc_stat nlm_rpc_stats; | ||
620 | |||
621 | struct rpc_program nlm_program = { | ||
622 | .name = "lockd", | ||
623 | .number = NLM_PROGRAM, | ||
624 | .nrvers = ARRAY_SIZE(nlm_versions), | ||
625 | .version = nlm_versions, | ||
626 | .stats = &nlm_rpc_stats, | ||
627 | }; | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index ed0c59fe23ce..b7c99bfb3da6 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -25,9 +25,22 @@ | |||
25 | #define NLM_HOST_EXPIRE (300 * HZ) | 25 | #define NLM_HOST_EXPIRE (300 * HZ) |
26 | #define NLM_HOST_COLLECT (120 * HZ) | 26 | #define NLM_HOST_COLLECT (120 * HZ) |
27 | 27 | ||
28 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; | 28 | static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; |
29 | static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; | ||
30 | |||
31 | #define for_each_host(host, pos, chain, table) \ | ||
32 | for ((chain) = (table); \ | ||
33 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | ||
34 | hlist_for_each_entry((host), (pos), (chain), h_hash) | ||
35 | |||
36 | #define for_each_host_safe(host, pos, next, chain, table) \ | ||
37 | for ((chain) = (table); \ | ||
38 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | ||
39 | hlist_for_each_entry_safe((host), (pos), (next), \ | ||
40 | (chain), h_hash) | ||
41 | |||
29 | static unsigned long next_gc; | 42 | static unsigned long next_gc; |
30 | static int nrhosts; | 43 | static unsigned long nrhosts; |
31 | static DEFINE_MUTEX(nlm_host_mutex); | 44 | static DEFINE_MUTEX(nlm_host_mutex); |
32 | 45 | ||
33 | static void nlm_gc_hosts(void); | 46 | static void nlm_gc_hosts(void); |
@@ -40,8 +53,6 @@ struct nlm_lookup_host_info { | |||
40 | const u32 version; /* NLM version to search for */ | 53 | const u32 version; /* NLM version to search for */ |
41 | const char *hostname; /* remote's hostname */ | 54 | const char *hostname; /* remote's hostname */ |
42 | const size_t hostname_len; /* it's length */ | 55 | const size_t hostname_len; /* it's length */ |
43 | const struct sockaddr *src_sap; /* our address (optional) */ | ||
44 | const size_t src_len; /* it's length */ | ||
45 | const int noresvport; /* use non-priv port */ | 56 | const int noresvport; /* use non-priv port */ |
46 | }; | 57 | }; |
47 | 58 | ||
@@ -88,127 +99,83 @@ static unsigned int nlm_hash_address(const struct sockaddr *sap) | |||
88 | } | 99 | } |
89 | 100 | ||
90 | /* | 101 | /* |
91 | * Common host lookup routine for server & client | 102 | * Allocate and initialize an nlm_host. Common to both client and server. |
92 | */ | 103 | */ |
93 | static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | 104 | static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, |
105 | struct nsm_handle *nsm) | ||
94 | { | 106 | { |
95 | struct hlist_head *chain; | 107 | struct nlm_host *host = NULL; |
96 | struct hlist_node *pos; | 108 | unsigned long now = jiffies; |
97 | struct nlm_host *host; | ||
98 | struct nsm_handle *nsm = NULL; | ||
99 | |||
100 | mutex_lock(&nlm_host_mutex); | ||
101 | |||
102 | if (time_after_eq(jiffies, next_gc)) | ||
103 | nlm_gc_hosts(); | ||
104 | |||
105 | /* We may keep several nlm_host objects for a peer, because each | ||
106 | * nlm_host is identified by | ||
107 | * (address, protocol, version, server/client) | ||
108 | * We could probably simplify this a little by putting all those | ||
109 | * different NLM rpc_clients into one single nlm_host object. | ||
110 | * This would allow us to have one nlm_host per address. | ||
111 | */ | ||
112 | chain = &nlm_hosts[nlm_hash_address(ni->sap)]; | ||
113 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
114 | if (!rpc_cmp_addr(nlm_addr(host), ni->sap)) | ||
115 | continue; | ||
116 | |||
117 | /* See if we have an NSM handle for this client */ | ||
118 | if (!nsm) | ||
119 | nsm = host->h_nsmhandle; | ||
120 | |||
121 | if (host->h_proto != ni->protocol) | ||
122 | continue; | ||
123 | if (host->h_version != ni->version) | ||
124 | continue; | ||
125 | if (host->h_server != ni->server) | ||
126 | continue; | ||
127 | if (ni->server && ni->src_len != 0 && | ||
128 | !rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap)) | ||
129 | continue; | ||
130 | |||
131 | /* Move to head of hash chain. */ | ||
132 | hlist_del(&host->h_hash); | ||
133 | hlist_add_head(&host->h_hash, chain); | ||
134 | |||
135 | nlm_get_host(host); | ||
136 | dprintk("lockd: nlm_lookup_host found host %s (%s)\n", | ||
137 | host->h_name, host->h_addrbuf); | ||
138 | goto out; | ||
139 | } | ||
140 | 109 | ||
141 | /* | 110 | if (nsm != NULL) |
142 | * The host wasn't in our hash table. If we don't | ||
143 | * have an NSM handle for it yet, create one. | ||
144 | */ | ||
145 | if (nsm) | ||
146 | atomic_inc(&nsm->sm_count); | 111 | atomic_inc(&nsm->sm_count); |
147 | else { | 112 | else { |
148 | host = NULL; | 113 | host = NULL; |
149 | nsm = nsm_get_handle(ni->sap, ni->salen, | 114 | nsm = nsm_get_handle(ni->sap, ni->salen, |
150 | ni->hostname, ni->hostname_len); | 115 | ni->hostname, ni->hostname_len); |
151 | if (!nsm) { | 116 | if (unlikely(nsm == NULL)) { |
152 | dprintk("lockd: nlm_lookup_host failed; " | 117 | dprintk("lockd: %s failed; no nsm handle\n", |
153 | "no nsm handle\n"); | 118 | __func__); |
154 | goto out; | 119 | goto out; |
155 | } | 120 | } |
156 | } | 121 | } |
157 | 122 | ||
158 | host = kzalloc(sizeof(*host), GFP_KERNEL); | 123 | host = kmalloc(sizeof(*host), GFP_KERNEL); |
159 | if (!host) { | 124 | if (unlikely(host == NULL)) { |
125 | dprintk("lockd: %s failed; no memory\n", __func__); | ||
160 | nsm_release(nsm); | 126 | nsm_release(nsm); |
161 | dprintk("lockd: nlm_lookup_host failed; no memory\n"); | ||
162 | goto out; | 127 | goto out; |
163 | } | 128 | } |
164 | host->h_name = nsm->sm_name; | 129 | |
165 | host->h_addrbuf = nsm->sm_addrbuf; | ||
166 | memcpy(nlm_addr(host), ni->sap, ni->salen); | 130 | memcpy(nlm_addr(host), ni->sap, ni->salen); |
167 | host->h_addrlen = ni->salen; | 131 | host->h_addrlen = ni->salen; |
168 | rpc_set_port(nlm_addr(host), 0); | 132 | rpc_set_port(nlm_addr(host), 0); |
169 | memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len); | 133 | host->h_srcaddrlen = 0; |
170 | host->h_srcaddrlen = ni->src_len; | 134 | |
135 | host->h_rpcclnt = NULL; | ||
136 | host->h_name = nsm->sm_name; | ||
171 | host->h_version = ni->version; | 137 | host->h_version = ni->version; |
172 | host->h_proto = ni->protocol; | 138 | host->h_proto = ni->protocol; |
173 | host->h_rpcclnt = NULL; | 139 | host->h_reclaiming = 0; |
174 | mutex_init(&host->h_mutex); | 140 | host->h_server = ni->server; |
175 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 141 | host->h_noresvport = ni->noresvport; |
176 | host->h_expires = jiffies + NLM_HOST_EXPIRE; | 142 | host->h_inuse = 0; |
177 | atomic_set(&host->h_count, 1); | ||
178 | init_waitqueue_head(&host->h_gracewait); | 143 | init_waitqueue_head(&host->h_gracewait); |
179 | init_rwsem(&host->h_rwsem); | 144 | init_rwsem(&host->h_rwsem); |
180 | host->h_state = 0; /* pseudo NSM state */ | 145 | host->h_state = 0; |
181 | host->h_nsmstate = 0; /* real NSM state */ | 146 | host->h_nsmstate = 0; |
182 | host->h_nsmhandle = nsm; | 147 | host->h_pidcount = 0; |
183 | host->h_server = ni->server; | 148 | atomic_set(&host->h_count, 1); |
184 | host->h_noresvport = ni->noresvport; | 149 | mutex_init(&host->h_mutex); |
185 | hlist_add_head(&host->h_hash, chain); | 150 | host->h_nextrebind = now + NLM_HOST_REBIND; |
151 | host->h_expires = now + NLM_HOST_EXPIRE; | ||
186 | INIT_LIST_HEAD(&host->h_lockowners); | 152 | INIT_LIST_HEAD(&host->h_lockowners); |
187 | spin_lock_init(&host->h_lock); | 153 | spin_lock_init(&host->h_lock); |
188 | INIT_LIST_HEAD(&host->h_granted); | 154 | INIT_LIST_HEAD(&host->h_granted); |
189 | INIT_LIST_HEAD(&host->h_reclaim); | 155 | INIT_LIST_HEAD(&host->h_reclaim); |
190 | 156 | host->h_nsmhandle = nsm; | |
191 | nrhosts++; | 157 | host->h_addrbuf = nsm->sm_addrbuf; |
192 | |||
193 | dprintk("lockd: nlm_lookup_host created host %s\n", | ||
194 | host->h_name); | ||
195 | 158 | ||
196 | out: | 159 | out: |
197 | mutex_unlock(&nlm_host_mutex); | ||
198 | return host; | 160 | return host; |
199 | } | 161 | } |
200 | 162 | ||
201 | /* | 163 | /* |
202 | * Destroy a host | 164 | * Destroy an nlm_host and free associated resources |
165 | * | ||
166 | * Caller must hold nlm_host_mutex. | ||
203 | */ | 167 | */ |
204 | static void | 168 | static void nlm_destroy_host_locked(struct nlm_host *host) |
205 | nlm_destroy_host(struct nlm_host *host) | ||
206 | { | 169 | { |
207 | struct rpc_clnt *clnt; | 170 | struct rpc_clnt *clnt; |
208 | 171 | ||
172 | dprintk("lockd: destroy host %s\n", host->h_name); | ||
173 | |||
209 | BUG_ON(!list_empty(&host->h_lockowners)); | 174 | BUG_ON(!list_empty(&host->h_lockowners)); |
210 | BUG_ON(atomic_read(&host->h_count)); | 175 | BUG_ON(atomic_read(&host->h_count)); |
211 | 176 | ||
177 | hlist_del_init(&host->h_hash); | ||
178 | |||
212 | nsm_unmonitor(host); | 179 | nsm_unmonitor(host); |
213 | nsm_release(host->h_nsmhandle); | 180 | nsm_release(host->h_nsmhandle); |
214 | 181 | ||
@@ -216,6 +183,8 @@ nlm_destroy_host(struct nlm_host *host) | |||
216 | if (clnt != NULL) | 183 | if (clnt != NULL) |
217 | rpc_shutdown_client(clnt); | 184 | rpc_shutdown_client(clnt); |
218 | kfree(host); | 185 | kfree(host); |
186 | |||
187 | nrhosts--; | ||
219 | } | 188 | } |
220 | 189 | ||
221 | /** | 190 | /** |
@@ -249,12 +218,76 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
249 | .hostname_len = strlen(hostname), | 218 | .hostname_len = strlen(hostname), |
250 | .noresvport = noresvport, | 219 | .noresvport = noresvport, |
251 | }; | 220 | }; |
221 | struct hlist_head *chain; | ||
222 | struct hlist_node *pos; | ||
223 | struct nlm_host *host; | ||
224 | struct nsm_handle *nsm = NULL; | ||
252 | 225 | ||
253 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, | 226 | dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, |
254 | (hostname ? hostname : "<none>"), version, | 227 | (hostname ? hostname : "<none>"), version, |
255 | (protocol == IPPROTO_UDP ? "udp" : "tcp")); | 228 | (protocol == IPPROTO_UDP ? "udp" : "tcp")); |
256 | 229 | ||
257 | return nlm_lookup_host(&ni); | 230 | mutex_lock(&nlm_host_mutex); |
231 | |||
232 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; | ||
233 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
234 | if (!rpc_cmp_addr(nlm_addr(host), sap)) | ||
235 | continue; | ||
236 | |||
237 | /* Same address. Share an NSM handle if we already have one */ | ||
238 | if (nsm == NULL) | ||
239 | nsm = host->h_nsmhandle; | ||
240 | |||
241 | if (host->h_proto != protocol) | ||
242 | continue; | ||
243 | if (host->h_version != version) | ||
244 | continue; | ||
245 | |||
246 | nlm_get_host(host); | ||
247 | dprintk("lockd: %s found host %s (%s)\n", __func__, | ||
248 | host->h_name, host->h_addrbuf); | ||
249 | goto out; | ||
250 | } | ||
251 | |||
252 | host = nlm_alloc_host(&ni, nsm); | ||
253 | if (unlikely(host == NULL)) | ||
254 | goto out; | ||
255 | |||
256 | hlist_add_head(&host->h_hash, chain); | ||
257 | nrhosts++; | ||
258 | |||
259 | dprintk("lockd: %s created host %s (%s)\n", __func__, | ||
260 | host->h_name, host->h_addrbuf); | ||
261 | |||
262 | out: | ||
263 | mutex_unlock(&nlm_host_mutex); | ||
264 | return host; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * nlmclnt_release_host - release client nlm_host | ||
269 | * @host: nlm_host to release | ||
270 | * | ||
271 | */ | ||
272 | void nlmclnt_release_host(struct nlm_host *host) | ||
273 | { | ||
274 | if (host == NULL) | ||
275 | return; | ||
276 | |||
277 | dprintk("lockd: release client host %s\n", host->h_name); | ||
278 | |||
279 | BUG_ON(atomic_read(&host->h_count) < 0); | ||
280 | BUG_ON(host->h_server); | ||
281 | |||
282 | if (atomic_dec_and_test(&host->h_count)) { | ||
283 | BUG_ON(!list_empty(&host->h_lockowners)); | ||
284 | BUG_ON(!list_empty(&host->h_granted)); | ||
285 | BUG_ON(!list_empty(&host->h_reclaim)); | ||
286 | |||
287 | mutex_lock(&nlm_host_mutex); | ||
288 | nlm_destroy_host_locked(host); | ||
289 | mutex_unlock(&nlm_host_mutex); | ||
290 | } | ||
258 | } | 291 | } |
259 | 292 | ||
260 | /** | 293 | /** |
@@ -279,12 +312,18 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
279 | const char *hostname, | 312 | const char *hostname, |
280 | const size_t hostname_len) | 313 | const size_t hostname_len) |
281 | { | 314 | { |
315 | struct hlist_head *chain; | ||
316 | struct hlist_node *pos; | ||
317 | struct nlm_host *host = NULL; | ||
318 | struct nsm_handle *nsm = NULL; | ||
282 | struct sockaddr_in sin = { | 319 | struct sockaddr_in sin = { |
283 | .sin_family = AF_INET, | 320 | .sin_family = AF_INET, |
284 | }; | 321 | }; |
285 | struct sockaddr_in6 sin6 = { | 322 | struct sockaddr_in6 sin6 = { |
286 | .sin6_family = AF_INET6, | 323 | .sin6_family = AF_INET6, |
287 | }; | 324 | }; |
325 | struct sockaddr *src_sap; | ||
326 | size_t src_len = rqstp->rq_addrlen; | ||
288 | struct nlm_lookup_host_info ni = { | 327 | struct nlm_lookup_host_info ni = { |
289 | .server = 1, | 328 | .server = 1, |
290 | .sap = svc_addr(rqstp), | 329 | .sap = svc_addr(rqstp), |
@@ -293,27 +332,91 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
293 | .version = rqstp->rq_vers, | 332 | .version = rqstp->rq_vers, |
294 | .hostname = hostname, | 333 | .hostname = hostname, |
295 | .hostname_len = hostname_len, | 334 | .hostname_len = hostname_len, |
296 | .src_len = rqstp->rq_addrlen, | ||
297 | }; | 335 | }; |
298 | 336 | ||
299 | dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, | 337 | dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, |
300 | (int)hostname_len, hostname, rqstp->rq_vers, | 338 | (int)hostname_len, hostname, rqstp->rq_vers, |
301 | (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp")); | 339 | (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp")); |
302 | 340 | ||
341 | mutex_lock(&nlm_host_mutex); | ||
342 | |||
303 | switch (ni.sap->sa_family) { | 343 | switch (ni.sap->sa_family) { |
304 | case AF_INET: | 344 | case AF_INET: |
305 | sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; | 345 | sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; |
306 | ni.src_sap = (struct sockaddr *)&sin; | 346 | src_sap = (struct sockaddr *)&sin; |
307 | break; | 347 | break; |
308 | case AF_INET6: | 348 | case AF_INET6: |
309 | ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); | 349 | ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); |
310 | ni.src_sap = (struct sockaddr *)&sin6; | 350 | src_sap = (struct sockaddr *)&sin6; |
311 | break; | 351 | break; |
312 | default: | 352 | default: |
313 | return NULL; | 353 | dprintk("lockd: %s failed; unrecognized address family\n", |
354 | __func__); | ||
355 | goto out; | ||
314 | } | 356 | } |
315 | 357 | ||
316 | return nlm_lookup_host(&ni); | 358 | if (time_after_eq(jiffies, next_gc)) |
359 | nlm_gc_hosts(); | ||
360 | |||
361 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; | ||
362 | hlist_for_each_entry(host, pos, chain, h_hash) { | ||
363 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) | ||
364 | continue; | ||
365 | |||
366 | /* Same address. Share an NSM handle if we already have one */ | ||
367 | if (nsm == NULL) | ||
368 | nsm = host->h_nsmhandle; | ||
369 | |||
370 | if (host->h_proto != ni.protocol) | ||
371 | continue; | ||
372 | if (host->h_version != ni.version) | ||
373 | continue; | ||
374 | if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap)) | ||
375 | continue; | ||
376 | |||
377 | /* Move to head of hash chain. */ | ||
378 | hlist_del(&host->h_hash); | ||
379 | hlist_add_head(&host->h_hash, chain); | ||
380 | |||
381 | nlm_get_host(host); | ||
382 | dprintk("lockd: %s found host %s (%s)\n", | ||
383 | __func__, host->h_name, host->h_addrbuf); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | host = nlm_alloc_host(&ni, nsm); | ||
388 | if (unlikely(host == NULL)) | ||
389 | goto out; | ||
390 | |||
391 | memcpy(nlm_srcaddr(host), src_sap, src_len); | ||
392 | host->h_srcaddrlen = src_len; | ||
393 | hlist_add_head(&host->h_hash, chain); | ||
394 | nrhosts++; | ||
395 | |||
396 | dprintk("lockd: %s created host %s (%s)\n", | ||
397 | __func__, host->h_name, host->h_addrbuf); | ||
398 | |||
399 | out: | ||
400 | mutex_unlock(&nlm_host_mutex); | ||
401 | return host; | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * nlmsvc_release_host - release server nlm_host | ||
406 | * @host: nlm_host to release | ||
407 | * | ||
408 | * Host is destroyed later in nlm_gc_host(). | ||
409 | */ | ||
410 | void nlmsvc_release_host(struct nlm_host *host) | ||
411 | { | ||
412 | if (host == NULL) | ||
413 | return; | ||
414 | |||
415 | dprintk("lockd: release server host %s\n", host->h_name); | ||
416 | |||
417 | BUG_ON(atomic_read(&host->h_count) < 0); | ||
418 | BUG_ON(!host->h_server); | ||
419 | atomic_dec(&host->h_count); | ||
317 | } | 420 | } |
318 | 421 | ||
319 | /* | 422 | /* |
@@ -413,20 +516,29 @@ struct nlm_host * nlm_get_host(struct nlm_host *host) | |||
413 | return host; | 516 | return host; |
414 | } | 517 | } |
415 | 518 | ||
416 | /* | 519 | static struct nlm_host *next_host_state(struct hlist_head *cache, |
417 | * Release NLM host after use | 520 | struct nsm_handle *nsm, |
418 | */ | 521 | const struct nlm_reboot *info) |
419 | void nlm_release_host(struct nlm_host *host) | ||
420 | { | 522 | { |
421 | if (host != NULL) { | 523 | struct nlm_host *host; |
422 | dprintk("lockd: release host %s\n", host->h_name); | 524 | struct hlist_head *chain; |
423 | BUG_ON(atomic_read(&host->h_count) < 0); | 525 | struct hlist_node *pos; |
424 | if (atomic_dec_and_test(&host->h_count)) { | 526 | |
425 | BUG_ON(!list_empty(&host->h_lockowners)); | 527 | mutex_lock(&nlm_host_mutex); |
426 | BUG_ON(!list_empty(&host->h_granted)); | 528 | for_each_host(host, pos, chain, cache) { |
427 | BUG_ON(!list_empty(&host->h_reclaim)); | 529 | if (host->h_nsmhandle == nsm |
530 | && host->h_nsmstate != info->state) { | ||
531 | host->h_nsmstate = info->state; | ||
532 | host->h_state++; | ||
533 | |||
534 | nlm_get_host(host); | ||
535 | mutex_unlock(&nlm_host_mutex); | ||
536 | return host; | ||
428 | } | 537 | } |
429 | } | 538 | } |
539 | |||
540 | mutex_unlock(&nlm_host_mutex); | ||
541 | return NULL; | ||
430 | } | 542 | } |
431 | 543 | ||
432 | /** | 544 | /** |
@@ -438,8 +550,6 @@ void nlm_release_host(struct nlm_host *host) | |||
438 | */ | 550 | */ |
439 | void nlm_host_rebooted(const struct nlm_reboot *info) | 551 | void nlm_host_rebooted(const struct nlm_reboot *info) |
440 | { | 552 | { |
441 | struct hlist_head *chain; | ||
442 | struct hlist_node *pos; | ||
443 | struct nsm_handle *nsm; | 553 | struct nsm_handle *nsm; |
444 | struct nlm_host *host; | 554 | struct nlm_host *host; |
445 | 555 | ||
@@ -452,32 +562,15 @@ void nlm_host_rebooted(const struct nlm_reboot *info) | |||
452 | * lock for this. | 562 | * lock for this. |
453 | * To avoid processing a host several times, we match the nsmstate. | 563 | * To avoid processing a host several times, we match the nsmstate. |
454 | */ | 564 | */ |
455 | again: mutex_lock(&nlm_host_mutex); | 565 | while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) { |
456 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 566 | nlmsvc_free_host_resources(host); |
457 | hlist_for_each_entry(host, pos, chain, h_hash) { | 567 | nlmsvc_release_host(host); |
458 | if (host->h_nsmhandle == nsm | ||
459 | && host->h_nsmstate != info->state) { | ||
460 | host->h_nsmstate = info->state; | ||
461 | host->h_state++; | ||
462 | |||
463 | nlm_get_host(host); | ||
464 | mutex_unlock(&nlm_host_mutex); | ||
465 | |||
466 | if (host->h_server) { | ||
467 | /* We're server for this guy, just ditch | ||
468 | * all the locks he held. */ | ||
469 | nlmsvc_free_host_resources(host); | ||
470 | } else { | ||
471 | /* He's the server, initiate lock recovery. */ | ||
472 | nlmclnt_recovery(host); | ||
473 | } | ||
474 | |||
475 | nlm_release_host(host); | ||
476 | goto again; | ||
477 | } | ||
478 | } | ||
479 | } | 568 | } |
480 | mutex_unlock(&nlm_host_mutex); | 569 | while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) { |
570 | nlmclnt_recovery(host); | ||
571 | nlmclnt_release_host(host); | ||
572 | } | ||
573 | |||
481 | nsm_release(nsm); | 574 | nsm_release(nsm); |
482 | } | 575 | } |
483 | 576 | ||
@@ -497,13 +590,11 @@ nlm_shutdown_hosts(void) | |||
497 | 590 | ||
498 | /* First, make all hosts eligible for gc */ | 591 | /* First, make all hosts eligible for gc */ |
499 | dprintk("lockd: nuking all hosts...\n"); | 592 | dprintk("lockd: nuking all hosts...\n"); |
500 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 593 | for_each_host(host, pos, chain, nlm_server_hosts) { |
501 | hlist_for_each_entry(host, pos, chain, h_hash) { | 594 | host->h_expires = jiffies - 1; |
502 | host->h_expires = jiffies - 1; | 595 | if (host->h_rpcclnt) { |
503 | if (host->h_rpcclnt) { | 596 | rpc_shutdown_client(host->h_rpcclnt); |
504 | rpc_shutdown_client(host->h_rpcclnt); | 597 | host->h_rpcclnt = NULL; |
505 | host->h_rpcclnt = NULL; | ||
506 | } | ||
507 | } | 598 | } |
508 | } | 599 | } |
509 | 600 | ||
@@ -512,15 +603,13 @@ nlm_shutdown_hosts(void) | |||
512 | mutex_unlock(&nlm_host_mutex); | 603 | mutex_unlock(&nlm_host_mutex); |
513 | 604 | ||
514 | /* complain if any hosts are left */ | 605 | /* complain if any hosts are left */ |
515 | if (nrhosts) { | 606 | if (nrhosts != 0) { |
516 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); | 607 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); |
517 | dprintk("lockd: %d hosts left:\n", nrhosts); | 608 | dprintk("lockd: %lu hosts left:\n", nrhosts); |
518 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 609 | for_each_host(host, pos, chain, nlm_server_hosts) { |
519 | hlist_for_each_entry(host, pos, chain, h_hash) { | 610 | dprintk(" %s (cnt %d use %d exp %ld)\n", |
520 | dprintk(" %s (cnt %d use %d exp %ld)\n", | 611 | host->h_name, atomic_read(&host->h_count), |
521 | host->h_name, atomic_read(&host->h_count), | 612 | host->h_inuse, host->h_expires); |
522 | host->h_inuse, host->h_expires); | ||
523 | } | ||
524 | } | 613 | } |
525 | } | 614 | } |
526 | } | 615 | } |
@@ -538,29 +627,22 @@ nlm_gc_hosts(void) | |||
538 | struct nlm_host *host; | 627 | struct nlm_host *host; |
539 | 628 | ||
540 | dprintk("lockd: host garbage collection\n"); | 629 | dprintk("lockd: host garbage collection\n"); |
541 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 630 | for_each_host(host, pos, chain, nlm_server_hosts) |
542 | hlist_for_each_entry(host, pos, chain, h_hash) | 631 | host->h_inuse = 0; |
543 | host->h_inuse = 0; | ||
544 | } | ||
545 | 632 | ||
546 | /* Mark all hosts that hold locks, blocks or shares */ | 633 | /* Mark all hosts that hold locks, blocks or shares */ |
547 | nlmsvc_mark_resources(); | 634 | nlmsvc_mark_resources(); |
548 | 635 | ||
549 | for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { | 636 | for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { |
550 | hlist_for_each_entry_safe(host, pos, next, chain, h_hash) { | 637 | if (atomic_read(&host->h_count) || host->h_inuse |
551 | if (atomic_read(&host->h_count) || host->h_inuse | 638 | || time_before(jiffies, host->h_expires)) { |
552 | || time_before(jiffies, host->h_expires)) { | 639 | dprintk("nlm_gc_hosts skipping %s " |
553 | dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", | 640 | "(cnt %d use %d exp %ld)\n", |
554 | host->h_name, atomic_read(&host->h_count), | 641 | host->h_name, atomic_read(&host->h_count), |
555 | host->h_inuse, host->h_expires); | 642 | host->h_inuse, host->h_expires); |
556 | continue; | 643 | continue; |
557 | } | ||
558 | dprintk("lockd: delete host %s\n", host->h_name); | ||
559 | hlist_del_init(&host->h_hash); | ||
560 | |||
561 | nlm_destroy_host(host); | ||
562 | nrhosts--; | ||
563 | } | 644 | } |
645 | nlm_destroy_host_locked(host); | ||
564 | } | 646 | } |
565 | 647 | ||
566 | next_gc = jiffies + NLM_HOST_COLLECT; | 648 | next_gc = jiffies + NLM_HOST_COLLECT; |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e0c918949644..23d7451b2938 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -401,26 +401,22 @@ void nsm_release(struct nsm_handle *nsm) | |||
401 | * Status Monitor wire protocol. | 401 | * Status Monitor wire protocol. |
402 | */ | 402 | */ |
403 | 403 | ||
404 | static int encode_nsm_string(struct xdr_stream *xdr, const char *string) | 404 | static void encode_nsm_string(struct xdr_stream *xdr, const char *string) |
405 | { | 405 | { |
406 | const u32 len = strlen(string); | 406 | const u32 len = strlen(string); |
407 | __be32 *p; | 407 | __be32 *p; |
408 | 408 | ||
409 | if (unlikely(len > SM_MAXSTRLEN)) | 409 | BUG_ON(len > SM_MAXSTRLEN); |
410 | return -EIO; | 410 | p = xdr_reserve_space(xdr, 4 + len); |
411 | p = xdr_reserve_space(xdr, sizeof(u32) + len); | ||
412 | if (unlikely(p == NULL)) | ||
413 | return -EIO; | ||
414 | xdr_encode_opaque(p, string, len); | 411 | xdr_encode_opaque(p, string, len); |
415 | return 0; | ||
416 | } | 412 | } |
417 | 413 | ||
418 | /* | 414 | /* |
419 | * "mon_name" specifies the host to be monitored. | 415 | * "mon_name" specifies the host to be monitored. |
420 | */ | 416 | */ |
421 | static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) | 417 | static void encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) |
422 | { | 418 | { |
423 | return encode_nsm_string(xdr, argp->mon_name); | 419 | encode_nsm_string(xdr, argp->mon_name); |
424 | } | 420 | } |
425 | 421 | ||
426 | /* | 422 | /* |
@@ -429,35 +425,25 @@ static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) | |||
429 | * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name" | 425 | * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name" |
430 | * has changed. | 426 | * has changed. |
431 | */ | 427 | */ |
432 | static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) | 428 | static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) |
433 | { | 429 | { |
434 | int status; | ||
435 | __be32 *p; | 430 | __be32 *p; |
436 | 431 | ||
437 | status = encode_nsm_string(xdr, utsname()->nodename); | 432 | encode_nsm_string(xdr, utsname()->nodename); |
438 | if (unlikely(status != 0)) | 433 | p = xdr_reserve_space(xdr, 4 + 4 + 4); |
439 | return status; | 434 | *p++ = cpu_to_be32(argp->prog); |
440 | p = xdr_reserve_space(xdr, 3 * sizeof(u32)); | 435 | *p++ = cpu_to_be32(argp->vers); |
441 | if (unlikely(p == NULL)) | 436 | *p = cpu_to_be32(argp->proc); |
442 | return -EIO; | ||
443 | *p++ = htonl(argp->prog); | ||
444 | *p++ = htonl(argp->vers); | ||
445 | *p++ = htonl(argp->proc); | ||
446 | return 0; | ||
447 | } | 437 | } |
448 | 438 | ||
449 | /* | 439 | /* |
450 | * The "mon_id" argument specifies the non-private arguments | 440 | * The "mon_id" argument specifies the non-private arguments |
451 | * of an NSMPROC_MON or NSMPROC_UNMON call. | 441 | * of an NSMPROC_MON or NSMPROC_UNMON call. |
452 | */ | 442 | */ |
453 | static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) | 443 | static void encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) |
454 | { | 444 | { |
455 | int status; | 445 | encode_mon_name(xdr, argp); |
456 | 446 | encode_my_id(xdr, argp); | |
457 | status = encode_mon_name(xdr, argp); | ||
458 | if (unlikely(status != 0)) | ||
459 | return status; | ||
460 | return encode_my_id(xdr, argp); | ||
461 | } | 447 | } |
462 | 448 | ||
463 | /* | 449 | /* |
@@ -465,68 +451,56 @@ static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) | |||
465 | * by the NSMPROC_MON call. This information will be supplied in the | 451 | * by the NSMPROC_MON call. This information will be supplied in the |
466 | * NLMPROC_SM_NOTIFY call. | 452 | * NLMPROC_SM_NOTIFY call. |
467 | */ | 453 | */ |
468 | static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp) | 454 | static void encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp) |
469 | { | 455 | { |
470 | __be32 *p; | 456 | __be32 *p; |
471 | 457 | ||
472 | p = xdr_reserve_space(xdr, SM_PRIV_SIZE); | 458 | p = xdr_reserve_space(xdr, SM_PRIV_SIZE); |
473 | if (unlikely(p == NULL)) | ||
474 | return -EIO; | ||
475 | xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE); | 459 | xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE); |
476 | return 0; | ||
477 | } | 460 | } |
478 | 461 | ||
479 | static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p, | 462 | static void nsm_xdr_enc_mon(struct rpc_rqst *req, struct xdr_stream *xdr, |
480 | const struct nsm_args *argp) | 463 | const struct nsm_args *argp) |
481 | { | 464 | { |
482 | struct xdr_stream xdr; | 465 | encode_mon_id(xdr, argp); |
483 | int status; | 466 | encode_priv(xdr, argp); |
484 | |||
485 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
486 | status = encode_mon_id(&xdr, argp); | ||
487 | if (unlikely(status)) | ||
488 | return status; | ||
489 | return encode_priv(&xdr, argp); | ||
490 | } | 467 | } |
491 | 468 | ||
492 | static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p, | 469 | static void nsm_xdr_enc_unmon(struct rpc_rqst *req, struct xdr_stream *xdr, |
493 | const struct nsm_args *argp) | 470 | const struct nsm_args *argp) |
494 | { | 471 | { |
495 | struct xdr_stream xdr; | 472 | encode_mon_id(xdr, argp); |
496 | |||
497 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
498 | return encode_mon_id(&xdr, argp); | ||
499 | } | 473 | } |
500 | 474 | ||
501 | static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p, | 475 | static int nsm_xdr_dec_stat_res(struct rpc_rqst *rqstp, |
502 | struct nsm_res *resp) | 476 | struct xdr_stream *xdr, |
477 | struct nsm_res *resp) | ||
503 | { | 478 | { |
504 | struct xdr_stream xdr; | 479 | __be32 *p; |
505 | 480 | ||
506 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 481 | p = xdr_inline_decode(xdr, 4 + 4); |
507 | p = xdr_inline_decode(&xdr, 2 * sizeof(u32)); | ||
508 | if (unlikely(p == NULL)) | 482 | if (unlikely(p == NULL)) |
509 | return -EIO; | 483 | return -EIO; |
510 | resp->status = ntohl(*p++); | 484 | resp->status = be32_to_cpup(p++); |
511 | resp->state = ntohl(*p); | 485 | resp->state = be32_to_cpup(p); |
512 | 486 | ||
513 | dprintk("lockd: xdr_dec_stat_res status %d state %d\n", | 487 | dprintk("lockd: %s status %d state %d\n", |
514 | resp->status, resp->state); | 488 | __func__, resp->status, resp->state); |
515 | return 0; | 489 | return 0; |
516 | } | 490 | } |
517 | 491 | ||
518 | static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p, | 492 | static int nsm_xdr_dec_stat(struct rpc_rqst *rqstp, |
519 | struct nsm_res *resp) | 493 | struct xdr_stream *xdr, |
494 | struct nsm_res *resp) | ||
520 | { | 495 | { |
521 | struct xdr_stream xdr; | 496 | __be32 *p; |
522 | 497 | ||
523 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 498 | p = xdr_inline_decode(xdr, 4); |
524 | p = xdr_inline_decode(&xdr, sizeof(u32)); | ||
525 | if (unlikely(p == NULL)) | 499 | if (unlikely(p == NULL)) |
526 | return -EIO; | 500 | return -EIO; |
527 | resp->state = ntohl(*p); | 501 | resp->state = be32_to_cpup(p); |
528 | 502 | ||
529 | dprintk("lockd: xdr_dec_stat state %d\n", resp->state); | 503 | dprintk("lockd: %s state %d\n", __func__, resp->state); |
530 | return 0; | 504 | return 0; |
531 | } | 505 | } |
532 | 506 | ||
@@ -542,8 +516,8 @@ static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p, | |||
542 | static struct rpc_procinfo nsm_procedures[] = { | 516 | static struct rpc_procinfo nsm_procedures[] = { |
543 | [NSMPROC_MON] = { | 517 | [NSMPROC_MON] = { |
544 | .p_proc = NSMPROC_MON, | 518 | .p_proc = NSMPROC_MON, |
545 | .p_encode = (kxdrproc_t)xdr_enc_mon, | 519 | .p_encode = (kxdreproc_t)nsm_xdr_enc_mon, |
546 | .p_decode = (kxdrproc_t)xdr_dec_stat_res, | 520 | .p_decode = (kxdrdproc_t)nsm_xdr_dec_stat_res, |
547 | .p_arglen = SM_mon_sz, | 521 | .p_arglen = SM_mon_sz, |
548 | .p_replen = SM_monres_sz, | 522 | .p_replen = SM_monres_sz, |
549 | .p_statidx = NSMPROC_MON, | 523 | .p_statidx = NSMPROC_MON, |
@@ -551,8 +525,8 @@ static struct rpc_procinfo nsm_procedures[] = { | |||
551 | }, | 525 | }, |
552 | [NSMPROC_UNMON] = { | 526 | [NSMPROC_UNMON] = { |
553 | .p_proc = NSMPROC_UNMON, | 527 | .p_proc = NSMPROC_UNMON, |
554 | .p_encode = (kxdrproc_t)xdr_enc_unmon, | 528 | .p_encode = (kxdreproc_t)nsm_xdr_enc_unmon, |
555 | .p_decode = (kxdrproc_t)xdr_dec_stat, | 529 | .p_decode = (kxdrdproc_t)nsm_xdr_dec_stat, |
556 | .p_arglen = SM_mon_id_sz, | 530 | .p_arglen = SM_mon_id_sz, |
557 | .p_replen = SM_unmonres_sz, | 531 | .p_replen = SM_unmonres_sz, |
558 | .p_statidx = NSMPROC_UNMON, | 532 | .p_statidx = NSMPROC_UNMON, |
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 38d261192453..9a41fdc19511 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -51,7 +51,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
51 | return 0; | 51 | return 0; |
52 | 52 | ||
53 | no_locks: | 53 | no_locks: |
54 | nlm_release_host(host); | 54 | nlmsvc_release_host(host); |
55 | if (error) | 55 | if (error) |
56 | return error; | 56 | return error; |
57 | return nlm_lck_denied_nolocks; | 57 | return nlm_lck_denied_nolocks; |
@@ -92,7 +92,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
92 | else | 92 | else |
93 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); | 93 | dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); |
94 | 94 | ||
95 | nlm_release_host(host); | 95 | nlmsvc_release_host(host); |
96 | nlm_release_file(file); | 96 | nlm_release_file(file); |
97 | return rc; | 97 | return rc; |
98 | } | 98 | } |
@@ -134,7 +134,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
134 | else | 134 | else |
135 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 135 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
136 | 136 | ||
137 | nlm_release_host(host); | 137 | nlmsvc_release_host(host); |
138 | nlm_release_file(file); | 138 | nlm_release_file(file); |
139 | return rc; | 139 | return rc; |
140 | } | 140 | } |
@@ -164,7 +164,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
164 | resp->status = nlmsvc_cancel_blocked(file, &argp->lock); | 164 | resp->status = nlmsvc_cancel_blocked(file, &argp->lock); |
165 | 165 | ||
166 | dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); | 166 | dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); |
167 | nlm_release_host(host); | 167 | nlmsvc_release_host(host); |
168 | nlm_release_file(file); | 168 | nlm_release_file(file); |
169 | return rpc_success; | 169 | return rpc_success; |
170 | } | 170 | } |
@@ -197,7 +197,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
197 | resp->status = nlmsvc_unlock(file, &argp->lock); | 197 | resp->status = nlmsvc_unlock(file, &argp->lock); |
198 | 198 | ||
199 | dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); | 199 | dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); |
200 | nlm_release_host(host); | 200 | nlmsvc_release_host(host); |
201 | nlm_release_file(file); | 201 | nlm_release_file(file); |
202 | return rpc_success; | 202 | return rpc_success; |
203 | } | 203 | } |
@@ -229,7 +229,7 @@ static void nlm4svc_callback_exit(struct rpc_task *task, void *data) | |||
229 | 229 | ||
230 | static void nlm4svc_callback_release(void *data) | 230 | static void nlm4svc_callback_release(void *data) |
231 | { | 231 | { |
232 | nlm_release_call(data); | 232 | nlmsvc_release_call(data); |
233 | } | 233 | } |
234 | 234 | ||
235 | static const struct rpc_call_ops nlm4svc_callback_ops = { | 235 | static const struct rpc_call_ops nlm4svc_callback_ops = { |
@@ -261,7 +261,7 @@ static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args | |||
261 | 261 | ||
262 | stat = func(rqstp, argp, &call->a_res); | 262 | stat = func(rqstp, argp, &call->a_res); |
263 | if (stat != 0) { | 263 | if (stat != 0) { |
264 | nlm_release_call(call); | 264 | nlmsvc_release_call(call); |
265 | return stat; | 265 | return stat; |
266 | } | 266 | } |
267 | 267 | ||
@@ -334,7 +334,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
334 | resp->status = nlmsvc_share_file(host, file, argp); | 334 | resp->status = nlmsvc_share_file(host, file, argp); |
335 | 335 | ||
336 | dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); | 336 | dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); |
337 | nlm_release_host(host); | 337 | nlmsvc_release_host(host); |
338 | nlm_release_file(file); | 338 | nlm_release_file(file); |
339 | return rpc_success; | 339 | return rpc_success; |
340 | } | 340 | } |
@@ -367,7 +367,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
367 | resp->status = nlmsvc_unshare_file(host, file, argp); | 367 | resp->status = nlmsvc_unshare_file(host, file, argp); |
368 | 368 | ||
369 | dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); | 369 | dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); |
370 | nlm_release_host(host); | 370 | nlmsvc_release_host(host); |
371 | nlm_release_file(file); | 371 | nlm_release_file(file); |
372 | return rpc_success; | 372 | return rpc_success; |
373 | } | 373 | } |
@@ -399,7 +399,7 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
399 | return rpc_success; | 399 | return rpc_success; |
400 | 400 | ||
401 | nlmsvc_free_host_resources(host); | 401 | nlmsvc_free_host_resources(host); |
402 | nlm_release_host(host); | 402 | nlmsvc_release_host(host); |
403 | return rpc_success; | 403 | return rpc_success; |
404 | } | 404 | } |
405 | 405 | ||
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index ef5659b211e9..6e31695d046f 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -46,6 +46,7 @@ static void nlmsvc_remove_block(struct nlm_block *block); | |||
46 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); | 46 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); |
47 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); | 47 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); |
48 | static const struct rpc_call_ops nlmsvc_grant_ops; | 48 | static const struct rpc_call_ops nlmsvc_grant_ops; |
49 | static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie); | ||
49 | 50 | ||
50 | /* | 51 | /* |
51 | * The list of blocked locks to retry | 52 | * The list of blocked locks to retry |
@@ -233,7 +234,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host, | |||
233 | failed_free: | 234 | failed_free: |
234 | kfree(block); | 235 | kfree(block); |
235 | failed: | 236 | failed: |
236 | nlm_release_call(call); | 237 | nlmsvc_release_call(call); |
237 | return NULL; | 238 | return NULL; |
238 | } | 239 | } |
239 | 240 | ||
@@ -266,7 +267,7 @@ static void nlmsvc_free_block(struct kref *kref) | |||
266 | mutex_unlock(&file->f_mutex); | 267 | mutex_unlock(&file->f_mutex); |
267 | 268 | ||
268 | nlmsvc_freegrantargs(block->b_call); | 269 | nlmsvc_freegrantargs(block->b_call); |
269 | nlm_release_call(block->b_call); | 270 | nlmsvc_release_call(block->b_call); |
270 | nlm_release_file(block->b_file); | 271 | nlm_release_file(block->b_file); |
271 | kfree(block->b_fl); | 272 | kfree(block->b_fl); |
272 | kfree(block); | 273 | kfree(block); |
@@ -934,3 +935,32 @@ nlmsvc_retry_blocked(void) | |||
934 | 935 | ||
935 | return timeout; | 936 | return timeout; |
936 | } | 937 | } |
938 | |||
939 | #ifdef RPC_DEBUG | ||
940 | static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | ||
941 | { | ||
942 | /* | ||
943 | * We can get away with a static buffer because we're only | ||
944 | * called with BKL held. | ||
945 | */ | ||
946 | static char buf[2*NLM_MAXCOOKIELEN+1]; | ||
947 | unsigned int i, len = sizeof(buf); | ||
948 | char *p = buf; | ||
949 | |||
950 | len--; /* allow for trailing \0 */ | ||
951 | if (len < 3) | ||
952 | return "???"; | ||
953 | for (i = 0 ; i < cookie->len ; i++) { | ||
954 | if (len < 2) { | ||
955 | strcpy(p-3, "..."); | ||
956 | break; | ||
957 | } | ||
958 | sprintf(p, "%02x", cookie->data[i]); | ||
959 | p += 2; | ||
960 | len -= 2; | ||
961 | } | ||
962 | *p = '\0'; | ||
963 | |||
964 | return buf; | ||
965 | } | ||
966 | #endif | ||
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 0caea5310ac3..d27aab11f324 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -80,7 +80,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
80 | return 0; | 80 | return 0; |
81 | 81 | ||
82 | no_locks: | 82 | no_locks: |
83 | nlm_release_host(host); | 83 | nlmsvc_release_host(host); |
84 | if (error) | 84 | if (error) |
85 | return error; | 85 | return error; |
86 | return nlm_lck_denied_nolocks; | 86 | return nlm_lck_denied_nolocks; |
@@ -122,7 +122,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
122 | dprintk("lockd: TEST status %d vers %d\n", | 122 | dprintk("lockd: TEST status %d vers %d\n", |
123 | ntohl(resp->status), rqstp->rq_vers); | 123 | ntohl(resp->status), rqstp->rq_vers); |
124 | 124 | ||
125 | nlm_release_host(host); | 125 | nlmsvc_release_host(host); |
126 | nlm_release_file(file); | 126 | nlm_release_file(file); |
127 | return rc; | 127 | return rc; |
128 | } | 128 | } |
@@ -164,7 +164,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
164 | else | 164 | else |
165 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); | 165 | dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); |
166 | 166 | ||
167 | nlm_release_host(host); | 167 | nlmsvc_release_host(host); |
168 | nlm_release_file(file); | 168 | nlm_release_file(file); |
169 | return rc; | 169 | return rc; |
170 | } | 170 | } |
@@ -194,7 +194,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
194 | resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); | 194 | resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); |
195 | 195 | ||
196 | dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); | 196 | dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); |
197 | nlm_release_host(host); | 197 | nlmsvc_release_host(host); |
198 | nlm_release_file(file); | 198 | nlm_release_file(file); |
199 | return rpc_success; | 199 | return rpc_success; |
200 | } | 200 | } |
@@ -227,7 +227,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
227 | resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); | 227 | resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); |
228 | 228 | ||
229 | dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); | 229 | dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); |
230 | nlm_release_host(host); | 230 | nlmsvc_release_host(host); |
231 | nlm_release_file(file); | 231 | nlm_release_file(file); |
232 | return rpc_success; | 232 | return rpc_success; |
233 | } | 233 | } |
@@ -257,9 +257,17 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data) | |||
257 | -task->tk_status); | 257 | -task->tk_status); |
258 | } | 258 | } |
259 | 259 | ||
260 | void nlmsvc_release_call(struct nlm_rqst *call) | ||
261 | { | ||
262 | if (!atomic_dec_and_test(&call->a_count)) | ||
263 | return; | ||
264 | nlmsvc_release_host(call->a_host); | ||
265 | kfree(call); | ||
266 | } | ||
267 | |||
260 | static void nlmsvc_callback_release(void *data) | 268 | static void nlmsvc_callback_release(void *data) |
261 | { | 269 | { |
262 | nlm_release_call(data); | 270 | nlmsvc_release_call(data); |
263 | } | 271 | } |
264 | 272 | ||
265 | static const struct rpc_call_ops nlmsvc_callback_ops = { | 273 | static const struct rpc_call_ops nlmsvc_callback_ops = { |
@@ -291,7 +299,7 @@ static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args | |||
291 | 299 | ||
292 | stat = func(rqstp, argp, &call->a_res); | 300 | stat = func(rqstp, argp, &call->a_res); |
293 | if (stat != 0) { | 301 | if (stat != 0) { |
294 | nlm_release_call(call); | 302 | nlmsvc_release_call(call); |
295 | return stat; | 303 | return stat; |
296 | } | 304 | } |
297 | 305 | ||
@@ -366,7 +374,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
366 | resp->status = cast_status(nlmsvc_share_file(host, file, argp)); | 374 | resp->status = cast_status(nlmsvc_share_file(host, file, argp)); |
367 | 375 | ||
368 | dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); | 376 | dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); |
369 | nlm_release_host(host); | 377 | nlmsvc_release_host(host); |
370 | nlm_release_file(file); | 378 | nlm_release_file(file); |
371 | return rpc_success; | 379 | return rpc_success; |
372 | } | 380 | } |
@@ -399,7 +407,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
399 | resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); | 407 | resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); |
400 | 408 | ||
401 | dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); | 409 | dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); |
402 | nlm_release_host(host); | 410 | nlmsvc_release_host(host); |
403 | nlm_release_file(file); | 411 | nlm_release_file(file); |
404 | return rpc_success; | 412 | return rpc_success; |
405 | } | 413 | } |
@@ -431,7 +439,7 @@ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
431 | return rpc_success; | 439 | return rpc_success; |
432 | 440 | ||
433 | nlmsvc_free_host_resources(host); | 441 | nlmsvc_free_host_resources(host); |
434 | nlm_release_host(host); | 442 | nlmsvc_release_host(host); |
435 | return rpc_success; | 443 | return rpc_success; |
436 | } | 444 | } |
437 | 445 | ||
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index b583ab0a4cbb..964666c68a86 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c | |||
@@ -149,37 +149,6 @@ nlm_decode_lock(__be32 *p, struct nlm_lock *lock) | |||
149 | } | 149 | } |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * Encode a lock as part of an NLM call | ||
153 | */ | ||
154 | static __be32 * | ||
155 | nlm_encode_lock(__be32 *p, struct nlm_lock *lock) | ||
156 | { | ||
157 | struct file_lock *fl = &lock->fl; | ||
158 | __s32 start, len; | ||
159 | |||
160 | if (!(p = xdr_encode_string(p, lock->caller)) | ||
161 | || !(p = nlm_encode_fh(p, &lock->fh)) | ||
162 | || !(p = nlm_encode_oh(p, &lock->oh))) | ||
163 | return NULL; | ||
164 | |||
165 | if (fl->fl_start > NLM_OFFSET_MAX | ||
166 | || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) | ||
167 | return NULL; | ||
168 | |||
169 | start = loff_t_to_s32(fl->fl_start); | ||
170 | if (fl->fl_end == OFFSET_MAX) | ||
171 | len = 0; | ||
172 | else | ||
173 | len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); | ||
174 | |||
175 | *p++ = htonl(lock->svid); | ||
176 | *p++ = htonl(start); | ||
177 | *p++ = htonl(len); | ||
178 | |||
179 | return p; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Encode result of a TEST/TEST_MSG call | 152 | * Encode result of a TEST/TEST_MSG call |
184 | */ | 153 | */ |
185 | static __be32 * | 154 | static __be32 * |
@@ -372,259 +341,3 @@ nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) | |||
372 | { | 341 | { |
373 | return xdr_ressize_check(rqstp, p); | 342 | return xdr_ressize_check(rqstp, p); |
374 | } | 343 | } |
375 | |||
376 | /* | ||
377 | * Now, the client side XDR functions | ||
378 | */ | ||
379 | #ifdef NLMCLNT_SUPPORT_SHARES | ||
380 | static int | ||
381 | nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) | ||
382 | { | ||
383 | return 0; | ||
384 | } | ||
385 | #endif | ||
386 | |||
387 | static int | ||
388 | nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
389 | { | ||
390 | struct nlm_lock *lock = &argp->lock; | ||
391 | |||
392 | if (!(p = nlm_encode_cookie(p, &argp->cookie))) | ||
393 | return -EIO; | ||
394 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
395 | if (!(p = nlm_encode_lock(p, lock))) | ||
396 | return -EIO; | ||
397 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int | ||
402 | nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
403 | { | ||
404 | if (!(p = nlm_decode_cookie(p, &resp->cookie))) | ||
405 | return -EIO; | ||
406 | resp->status = *p++; | ||
407 | if (resp->status == nlm_lck_denied) { | ||
408 | struct file_lock *fl = &resp->lock.fl; | ||
409 | u32 excl; | ||
410 | s32 start, len, end; | ||
411 | |||
412 | memset(&resp->lock, 0, sizeof(resp->lock)); | ||
413 | locks_init_lock(fl); | ||
414 | excl = ntohl(*p++); | ||
415 | resp->lock.svid = ntohl(*p++); | ||
416 | fl->fl_pid = (pid_t)resp->lock.svid; | ||
417 | if (!(p = nlm_decode_oh(p, &resp->lock.oh))) | ||
418 | return -EIO; | ||
419 | |||
420 | fl->fl_flags = FL_POSIX; | ||
421 | fl->fl_type = excl? F_WRLCK : F_RDLCK; | ||
422 | start = ntohl(*p++); | ||
423 | len = ntohl(*p++); | ||
424 | end = start + len - 1; | ||
425 | |||
426 | fl->fl_start = s32_to_loff_t(start); | ||
427 | if (len == 0 || end < 0) | ||
428 | fl->fl_end = OFFSET_MAX; | ||
429 | else | ||
430 | fl->fl_end = s32_to_loff_t(end); | ||
431 | } | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | |||
436 | static int | ||
437 | nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
438 | { | ||
439 | struct nlm_lock *lock = &argp->lock; | ||
440 | |||
441 | if (!(p = nlm_encode_cookie(p, &argp->cookie))) | ||
442 | return -EIO; | ||
443 | *p++ = argp->block? xdr_one : xdr_zero; | ||
444 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
445 | if (!(p = nlm_encode_lock(p, lock))) | ||
446 | return -EIO; | ||
447 | *p++ = argp->reclaim? xdr_one : xdr_zero; | ||
448 | *p++ = htonl(argp->state); | ||
449 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int | ||
454 | nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
455 | { | ||
456 | struct nlm_lock *lock = &argp->lock; | ||
457 | |||
458 | if (!(p = nlm_encode_cookie(p, &argp->cookie))) | ||
459 | return -EIO; | ||
460 | *p++ = argp->block? xdr_one : xdr_zero; | ||
461 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
462 | if (!(p = nlm_encode_lock(p, lock))) | ||
463 | return -EIO; | ||
464 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int | ||
469 | nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
470 | { | ||
471 | struct nlm_lock *lock = &argp->lock; | ||
472 | |||
473 | if (!(p = nlm_encode_cookie(p, &argp->cookie))) | ||
474 | return -EIO; | ||
475 | if (!(p = nlm_encode_lock(p, lock))) | ||
476 | return -EIO; | ||
477 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int | ||
482 | nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
483 | { | ||
484 | if (!(p = nlm_encode_cookie(p, &resp->cookie))) | ||
485 | return -EIO; | ||
486 | *p++ = resp->status; | ||
487 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int | ||
492 | nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
493 | { | ||
494 | if (!(p = nlm_encode_testres(p, resp))) | ||
495 | return -EIO; | ||
496 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int | ||
501 | nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
502 | { | ||
503 | if (!(p = nlm_decode_cookie(p, &resp->cookie))) | ||
504 | return -EIO; | ||
505 | resp->status = *p++; | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) | ||
510 | # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" | ||
511 | #endif | ||
512 | |||
513 | /* | ||
514 | * Buffer requirements for NLM | ||
515 | */ | ||
516 | #define NLM_void_sz 0 | ||
517 | #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) | ||
518 | #define NLM_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) | ||
519 | #define NLM_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) | ||
520 | #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) | ||
521 | #define NLM_lock_sz 3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz | ||
522 | #define NLM_holder_sz 4+NLM_owner_sz | ||
523 | |||
524 | #define NLM_testargs_sz NLM_cookie_sz+1+NLM_lock_sz | ||
525 | #define NLM_lockargs_sz NLM_cookie_sz+4+NLM_lock_sz | ||
526 | #define NLM_cancargs_sz NLM_cookie_sz+2+NLM_lock_sz | ||
527 | #define NLM_unlockargs_sz NLM_cookie_sz+NLM_lock_sz | ||
528 | |||
529 | #define NLM_testres_sz NLM_cookie_sz+1+NLM_holder_sz | ||
530 | #define NLM_res_sz NLM_cookie_sz+1 | ||
531 | #define NLM_norep_sz 0 | ||
532 | |||
533 | /* | ||
534 | * For NLM, a void procedure really returns nothing | ||
535 | */ | ||
536 | #define nlmclt_decode_norep NULL | ||
537 | |||
538 | #define PROC(proc, argtype, restype) \ | ||
539 | [NLMPROC_##proc] = { \ | ||
540 | .p_proc = NLMPROC_##proc, \ | ||
541 | .p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \ | ||
542 | .p_decode = (kxdrproc_t) nlmclt_decode_##restype, \ | ||
543 | .p_arglen = NLM_##argtype##_sz, \ | ||
544 | .p_replen = NLM_##restype##_sz, \ | ||
545 | .p_statidx = NLMPROC_##proc, \ | ||
546 | .p_name = #proc, \ | ||
547 | } | ||
548 | |||
549 | static struct rpc_procinfo nlm_procedures[] = { | ||
550 | PROC(TEST, testargs, testres), | ||
551 | PROC(LOCK, lockargs, res), | ||
552 | PROC(CANCEL, cancargs, res), | ||
553 | PROC(UNLOCK, unlockargs, res), | ||
554 | PROC(GRANTED, testargs, res), | ||
555 | PROC(TEST_MSG, testargs, norep), | ||
556 | PROC(LOCK_MSG, lockargs, norep), | ||
557 | PROC(CANCEL_MSG, cancargs, norep), | ||
558 | PROC(UNLOCK_MSG, unlockargs, norep), | ||
559 | PROC(GRANTED_MSG, testargs, norep), | ||
560 | PROC(TEST_RES, testres, norep), | ||
561 | PROC(LOCK_RES, res, norep), | ||
562 | PROC(CANCEL_RES, res, norep), | ||
563 | PROC(UNLOCK_RES, res, norep), | ||
564 | PROC(GRANTED_RES, res, norep), | ||
565 | #ifdef NLMCLNT_SUPPORT_SHARES | ||
566 | PROC(SHARE, shareargs, shareres), | ||
567 | PROC(UNSHARE, shareargs, shareres), | ||
568 | PROC(NM_LOCK, lockargs, res), | ||
569 | PROC(FREE_ALL, notify, void), | ||
570 | #endif | ||
571 | }; | ||
572 | |||
573 | static struct rpc_version nlm_version1 = { | ||
574 | .number = 1, | ||
575 | .nrprocs = 16, | ||
576 | .procs = nlm_procedures, | ||
577 | }; | ||
578 | |||
579 | static struct rpc_version nlm_version3 = { | ||
580 | .number = 3, | ||
581 | .nrprocs = 24, | ||
582 | .procs = nlm_procedures, | ||
583 | }; | ||
584 | |||
585 | static struct rpc_version * nlm_versions[] = { | ||
586 | [1] = &nlm_version1, | ||
587 | [3] = &nlm_version3, | ||
588 | #ifdef CONFIG_LOCKD_V4 | ||
589 | [4] = &nlm_version4, | ||
590 | #endif | ||
591 | }; | ||
592 | |||
593 | static struct rpc_stat nlm_stats; | ||
594 | |||
595 | struct rpc_program nlm_program = { | ||
596 | .name = "lockd", | ||
597 | .number = NLM_PROGRAM, | ||
598 | .nrvers = ARRAY_SIZE(nlm_versions), | ||
599 | .version = nlm_versions, | ||
600 | .stats = &nlm_stats, | ||
601 | }; | ||
602 | |||
603 | #ifdef RPC_DEBUG | ||
604 | const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | ||
605 | { | ||
606 | /* | ||
607 | * We can get away with a static buffer because we're only | ||
608 | * called with BKL held. | ||
609 | */ | ||
610 | static char buf[2*NLM_MAXCOOKIELEN+1]; | ||
611 | unsigned int i, len = sizeof(buf); | ||
612 | char *p = buf; | ||
613 | |||
614 | len--; /* allow for trailing \0 */ | ||
615 | if (len < 3) | ||
616 | return "???"; | ||
617 | for (i = 0 ; i < cookie->len ; i++) { | ||
618 | if (len < 2) { | ||
619 | strcpy(p-3, "..."); | ||
620 | break; | ||
621 | } | ||
622 | sprintf(p, "%02x", cookie->data[i]); | ||
623 | p += 2; | ||
624 | len -= 2; | ||
625 | } | ||
626 | *p = '\0'; | ||
627 | |||
628 | return buf; | ||
629 | } | ||
630 | #endif | ||
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index ad9dbbc9145d..dfa4789cd460 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c | |||
@@ -93,15 +93,6 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f) | |||
93 | return p + XDR_QUADLEN(f->size); | 93 | return p + XDR_QUADLEN(f->size); |
94 | } | 94 | } |
95 | 95 | ||
96 | static __be32 * | ||
97 | nlm4_encode_fh(__be32 *p, struct nfs_fh *f) | ||
98 | { | ||
99 | *p++ = htonl(f->size); | ||
100 | if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */ | ||
101 | memcpy(p, f->data, f->size); | ||
102 | return p + XDR_QUADLEN(f->size); | ||
103 | } | ||
104 | |||
105 | /* | 96 | /* |
106 | * Encode and decode owner handle | 97 | * Encode and decode owner handle |
107 | */ | 98 | */ |
@@ -112,12 +103,6 @@ nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) | |||
112 | } | 103 | } |
113 | 104 | ||
114 | static __be32 * | 105 | static __be32 * |
115 | nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh) | ||
116 | { | ||
117 | return xdr_encode_netobj(p, oh); | ||
118 | } | ||
119 | |||
120 | static __be32 * | ||
121 | nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) | 106 | nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) |
122 | { | 107 | { |
123 | struct file_lock *fl = &lock->fl; | 108 | struct file_lock *fl = &lock->fl; |
@@ -150,38 +135,6 @@ nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) | |||
150 | } | 135 | } |
151 | 136 | ||
152 | /* | 137 | /* |
153 | * Encode a lock as part of an NLM call | ||
154 | */ | ||
155 | static __be32 * | ||
156 | nlm4_encode_lock(__be32 *p, struct nlm_lock *lock) | ||
157 | { | ||
158 | struct file_lock *fl = &lock->fl; | ||
159 | __s64 start, len; | ||
160 | |||
161 | if (!(p = xdr_encode_string(p, lock->caller)) | ||
162 | || !(p = nlm4_encode_fh(p, &lock->fh)) | ||
163 | || !(p = nlm4_encode_oh(p, &lock->oh))) | ||
164 | return NULL; | ||
165 | |||
166 | if (fl->fl_start > NLM4_OFFSET_MAX | ||
167 | || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) | ||
168 | return NULL; | ||
169 | |||
170 | *p++ = htonl(lock->svid); | ||
171 | |||
172 | start = loff_t_to_s64(fl->fl_start); | ||
173 | if (fl->fl_end == OFFSET_MAX) | ||
174 | len = 0; | ||
175 | else | ||
176 | len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); | ||
177 | |||
178 | p = xdr_encode_hyper(p, start); | ||
179 | p = xdr_encode_hyper(p, len); | ||
180 | |||
181 | return p; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Encode result of a TEST/TEST_MSG call | 138 | * Encode result of a TEST/TEST_MSG call |
186 | */ | 139 | */ |
187 | static __be32 * | 140 | static __be32 * |
@@ -379,211 +332,3 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) | |||
379 | { | 332 | { |
380 | return xdr_ressize_check(rqstp, p); | 333 | return xdr_ressize_check(rqstp, p); |
381 | } | 334 | } |
382 | |||
383 | /* | ||
384 | * Now, the client side XDR functions | ||
385 | */ | ||
386 | #ifdef NLMCLNT_SUPPORT_SHARES | ||
387 | static int | ||
388 | nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr) | ||
389 | { | ||
390 | return 0; | ||
391 | } | ||
392 | #endif | ||
393 | |||
394 | static int | ||
395 | nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
396 | { | ||
397 | struct nlm_lock *lock = &argp->lock; | ||
398 | |||
399 | if (!(p = nlm4_encode_cookie(p, &argp->cookie))) | ||
400 | return -EIO; | ||
401 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
402 | if (!(p = nlm4_encode_lock(p, lock))) | ||
403 | return -EIO; | ||
404 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int | ||
409 | nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
410 | { | ||
411 | if (!(p = nlm4_decode_cookie(p, &resp->cookie))) | ||
412 | return -EIO; | ||
413 | resp->status = *p++; | ||
414 | if (resp->status == nlm_lck_denied) { | ||
415 | struct file_lock *fl = &resp->lock.fl; | ||
416 | u32 excl; | ||
417 | __u64 start, len; | ||
418 | __s64 end; | ||
419 | |||
420 | memset(&resp->lock, 0, sizeof(resp->lock)); | ||
421 | locks_init_lock(fl); | ||
422 | excl = ntohl(*p++); | ||
423 | resp->lock.svid = ntohl(*p++); | ||
424 | fl->fl_pid = (pid_t)resp->lock.svid; | ||
425 | if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) | ||
426 | return -EIO; | ||
427 | |||
428 | fl->fl_flags = FL_POSIX; | ||
429 | fl->fl_type = excl? F_WRLCK : F_RDLCK; | ||
430 | p = xdr_decode_hyper(p, &start); | ||
431 | p = xdr_decode_hyper(p, &len); | ||
432 | end = start + len - 1; | ||
433 | |||
434 | fl->fl_start = s64_to_loff_t(start); | ||
435 | if (len == 0 || end < 0) | ||
436 | fl->fl_end = OFFSET_MAX; | ||
437 | else | ||
438 | fl->fl_end = s64_to_loff_t(end); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | |||
444 | static int | ||
445 | nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
446 | { | ||
447 | struct nlm_lock *lock = &argp->lock; | ||
448 | |||
449 | if (!(p = nlm4_encode_cookie(p, &argp->cookie))) | ||
450 | return -EIO; | ||
451 | *p++ = argp->block? xdr_one : xdr_zero; | ||
452 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
453 | if (!(p = nlm4_encode_lock(p, lock))) | ||
454 | return -EIO; | ||
455 | *p++ = argp->reclaim? xdr_one : xdr_zero; | ||
456 | *p++ = htonl(argp->state); | ||
457 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int | ||
462 | nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
463 | { | ||
464 | struct nlm_lock *lock = &argp->lock; | ||
465 | |||
466 | if (!(p = nlm4_encode_cookie(p, &argp->cookie))) | ||
467 | return -EIO; | ||
468 | *p++ = argp->block? xdr_one : xdr_zero; | ||
469 | *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; | ||
470 | if (!(p = nlm4_encode_lock(p, lock))) | ||
471 | return -EIO; | ||
472 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int | ||
477 | nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) | ||
478 | { | ||
479 | struct nlm_lock *lock = &argp->lock; | ||
480 | |||
481 | if (!(p = nlm4_encode_cookie(p, &argp->cookie))) | ||
482 | return -EIO; | ||
483 | if (!(p = nlm4_encode_lock(p, lock))) | ||
484 | return -EIO; | ||
485 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int | ||
490 | nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
491 | { | ||
492 | if (!(p = nlm4_encode_cookie(p, &resp->cookie))) | ||
493 | return -EIO; | ||
494 | *p++ = resp->status; | ||
495 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static int | ||
500 | nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
501 | { | ||
502 | if (!(p = nlm4_encode_testres(p, resp))) | ||
503 | return -EIO; | ||
504 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int | ||
509 | nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) | ||
510 | { | ||
511 | if (!(p = nlm4_decode_cookie(p, &resp->cookie))) | ||
512 | return -EIO; | ||
513 | resp->status = *p++; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) | ||
518 | # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" | ||
519 | #endif | ||
520 | |||
521 | #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) | ||
522 | # error "NLM host name cannot be larger than NLM's maximum string length!" | ||
523 | #endif | ||
524 | |||
525 | /* | ||
526 | * Buffer requirements for NLM | ||
527 | */ | ||
528 | #define NLM4_void_sz 0 | ||
529 | #define NLM4_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) | ||
530 | #define NLM4_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) | ||
531 | #define NLM4_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) | ||
532 | #define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE) | ||
533 | #define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz | ||
534 | #define NLM4_holder_sz 6+NLM4_owner_sz | ||
535 | |||
536 | #define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz | ||
537 | #define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz | ||
538 | #define NLM4_cancargs_sz NLM4_cookie_sz+2+NLM4_lock_sz | ||
539 | #define NLM4_unlockargs_sz NLM4_cookie_sz+NLM4_lock_sz | ||
540 | |||
541 | #define NLM4_testres_sz NLM4_cookie_sz+1+NLM4_holder_sz | ||
542 | #define NLM4_res_sz NLM4_cookie_sz+1 | ||
543 | #define NLM4_norep_sz 0 | ||
544 | |||
545 | /* | ||
546 | * For NLM, a void procedure really returns nothing | ||
547 | */ | ||
548 | #define nlm4clt_decode_norep NULL | ||
549 | |||
550 | #define PROC(proc, argtype, restype) \ | ||
551 | [NLMPROC_##proc] = { \ | ||
552 | .p_proc = NLMPROC_##proc, \ | ||
553 | .p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \ | ||
554 | .p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \ | ||
555 | .p_arglen = NLM4_##argtype##_sz, \ | ||
556 | .p_replen = NLM4_##restype##_sz, \ | ||
557 | .p_statidx = NLMPROC_##proc, \ | ||
558 | .p_name = #proc, \ | ||
559 | } | ||
560 | |||
561 | static struct rpc_procinfo nlm4_procedures[] = { | ||
562 | PROC(TEST, testargs, testres), | ||
563 | PROC(LOCK, lockargs, res), | ||
564 | PROC(CANCEL, cancargs, res), | ||
565 | PROC(UNLOCK, unlockargs, res), | ||
566 | PROC(GRANTED, testargs, res), | ||
567 | PROC(TEST_MSG, testargs, norep), | ||
568 | PROC(LOCK_MSG, lockargs, norep), | ||
569 | PROC(CANCEL_MSG, cancargs, norep), | ||
570 | PROC(UNLOCK_MSG, unlockargs, norep), | ||
571 | PROC(GRANTED_MSG, testargs, norep), | ||
572 | PROC(TEST_RES, testres, norep), | ||
573 | PROC(LOCK_RES, res, norep), | ||
574 | PROC(CANCEL_RES, res, norep), | ||
575 | PROC(UNLOCK_RES, res, norep), | ||
576 | PROC(GRANTED_RES, res, norep), | ||
577 | #ifdef NLMCLNT_SUPPORT_SHARES | ||
578 | PROC(SHARE, shareargs, shareres), | ||
579 | PROC(UNSHARE, shareargs, shareres), | ||
580 | PROC(NM_LOCK, lockargs, res), | ||
581 | PROC(FREE_ALL, notify, void), | ||
582 | #endif | ||
583 | }; | ||
584 | |||
585 | struct rpc_version nlm_version4 = { | ||
586 | .number = 4, | ||
587 | .nrprocs = 24, | ||
588 | .procs = nlm4_procedures, | ||
589 | }; | ||