diff options
Diffstat (limited to 'fs/lockd/clnt4xdr.c')
-rw-r--r-- | fs/lockd/clnt4xdr.c | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c new file mode 100644 index 000000000000..1a1c3e21ed2c --- /dev/null +++ b/fs/lockd/clnt4xdr.c | |||
@@ -0,0 +1,621 @@ | |||
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 int nlm4_xdr_enc_testargs(struct rpc_rqst *req, __be32 *p, | ||
389 | const struct nlm_args *args) | ||
390 | { | ||
391 | const struct nlm_lock *lock = &args->lock; | ||
392 | struct xdr_stream xdr; | ||
393 | |||
394 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
395 | encode_cookie(&xdr, &args->cookie); | ||
396 | encode_bool(&xdr, lock->fl.fl_type == F_WRLCK); | ||
397 | encode_nlm4_lock(&xdr, lock); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * struct nlm4_lockargs { | ||
403 | * netobj cookie; | ||
404 | * bool block; | ||
405 | * bool exclusive; | ||
406 | * struct nlm4_lock alock; | ||
407 | * bool reclaim; | ||
408 | * int state; | ||
409 | * }; | ||
410 | */ | ||
411 | static int nlm4_xdr_enc_lockargs(struct rpc_rqst *req, __be32 *p, | ||
412 | const struct nlm_args *args) | ||
413 | { | ||
414 | const struct nlm_lock *lock = &args->lock; | ||
415 | struct xdr_stream xdr; | ||
416 | |||
417 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
418 | encode_cookie(&xdr, &args->cookie); | ||
419 | encode_bool(&xdr, args->block); | ||
420 | encode_bool(&xdr, lock->fl.fl_type == F_WRLCK); | ||
421 | encode_nlm4_lock(&xdr, lock); | ||
422 | encode_bool(&xdr, args->reclaim); | ||
423 | encode_int32(&xdr, args->state); | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * struct nlm4_cancargs { | ||
429 | * netobj cookie; | ||
430 | * bool block; | ||
431 | * bool exclusive; | ||
432 | * struct nlm4_lock alock; | ||
433 | * }; | ||
434 | */ | ||
435 | static int nlm4_xdr_enc_cancargs(struct rpc_rqst *req, __be32 *p, | ||
436 | const struct nlm_args *args) | ||
437 | { | ||
438 | const struct nlm_lock *lock = &args->lock; | ||
439 | struct xdr_stream xdr; | ||
440 | |||
441 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
442 | encode_cookie(&xdr, &args->cookie); | ||
443 | encode_bool(&xdr, args->block); | ||
444 | encode_bool(&xdr, lock->fl.fl_type == F_WRLCK); | ||
445 | encode_nlm4_lock(&xdr, lock); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * struct nlm4_unlockargs { | ||
451 | * netobj cookie; | ||
452 | * struct nlm4_lock alock; | ||
453 | * }; | ||
454 | */ | ||
455 | static int nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, __be32 *p, | ||
456 | const struct nlm_args *args) | ||
457 | { | ||
458 | const struct nlm_lock *lock = &args->lock; | ||
459 | struct xdr_stream xdr; | ||
460 | |||
461 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
462 | encode_cookie(&xdr, &args->cookie); | ||
463 | encode_nlm4_lock(&xdr, lock); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * struct nlm4_res { | ||
469 | * netobj cookie; | ||
470 | * nlm4_stat stat; | ||
471 | * }; | ||
472 | */ | ||
473 | static int nlm4_xdr_enc_res(struct rpc_rqst *req, __be32 *p, | ||
474 | const struct nlm_res *result) | ||
475 | { | ||
476 | struct xdr_stream xdr; | ||
477 | |||
478 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
479 | encode_cookie(&xdr, &result->cookie); | ||
480 | encode_nlm4_stat(&xdr, result->status); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * union nlm4_testrply switch (nlm4_stats stat) { | ||
486 | * case NLM4_DENIED: | ||
487 | * struct nlm4_holder holder; | ||
488 | * default: | ||
489 | * void; | ||
490 | * }; | ||
491 | * | ||
492 | * struct nlm4_testres { | ||
493 | * netobj cookie; | ||
494 | * nlm4_testrply test_stat; | ||
495 | * }; | ||
496 | */ | ||
497 | static int nlm4_xdr_enc_testres(struct rpc_rqst *req, __be32 *p, | ||
498 | const struct nlm_res *result) | ||
499 | { | ||
500 | struct xdr_stream xdr; | ||
501 | |||
502 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
503 | encode_cookie(&xdr, &result->cookie); | ||
504 | encode_nlm4_stat(&xdr, result->status); | ||
505 | if (result->status == nlm_lck_denied) | ||
506 | encode_nlm4_holder(&xdr, result); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | |||
511 | /* | ||
512 | * NLMv4 XDR decode functions | ||
513 | * | ||
514 | * NLMv4 argument types are defined in Appendix II of RFC 1813: | ||
515 | * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's | ||
516 | * "Protocols for Interworking: XNFS, Version 3W". | ||
517 | */ | ||
518 | |||
519 | /* | ||
520 | * union nlm4_testrply switch (nlm4_stats stat) { | ||
521 | * case NLM4_DENIED: | ||
522 | * struct nlm4_holder holder; | ||
523 | * default: | ||
524 | * void; | ||
525 | * }; | ||
526 | * | ||
527 | * struct nlm4_testres { | ||
528 | * netobj cookie; | ||
529 | * nlm4_testrply test_stat; | ||
530 | * }; | ||
531 | */ | ||
532 | static int decode_nlm4_testrply(struct xdr_stream *xdr, | ||
533 | struct nlm_res *result) | ||
534 | { | ||
535 | int error; | ||
536 | |||
537 | error = decode_nlm4_stat(xdr, &result->status); | ||
538 | if (unlikely(error)) | ||
539 | goto out; | ||
540 | if (result->status == nlm_lck_denied) | ||
541 | error = decode_nlm4_holder(xdr, result); | ||
542 | out: | ||
543 | return error; | ||
544 | } | ||
545 | |||
546 | static int nlm4_xdr_dec_testres(struct rpc_rqst *req, __be32 *p, | ||
547 | struct nlm_res *result) | ||
548 | { | ||
549 | struct xdr_stream xdr; | ||
550 | int error; | ||
551 | |||
552 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
553 | error = decode_cookie(&xdr, &result->cookie); | ||
554 | if (unlikely(error)) | ||
555 | goto out; | ||
556 | error = decode_nlm4_testrply(&xdr, result); | ||
557 | out: | ||
558 | return error; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * struct nlm4_res { | ||
563 | * netobj cookie; | ||
564 | * nlm4_stat stat; | ||
565 | * }; | ||
566 | */ | ||
567 | static int nlm4_xdr_dec_res(struct rpc_rqst *req, __be32 *p, | ||
568 | struct nlm_res *result) | ||
569 | { | ||
570 | struct xdr_stream xdr; | ||
571 | int error; | ||
572 | |||
573 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
574 | error = decode_cookie(&xdr, &result->cookie); | ||
575 | if (unlikely(error)) | ||
576 | goto out; | ||
577 | error = decode_nlm4_stat(&xdr, &result->status); | ||
578 | out: | ||
579 | return error; | ||
580 | } | ||
581 | |||
582 | |||
583 | /* | ||
584 | * For NLM, a void procedure really returns nothing | ||
585 | */ | ||
586 | #define nlm4_xdr_dec_norep NULL | ||
587 | |||
588 | #define PROC(proc, argtype, restype) \ | ||
589 | [NLMPROC_##proc] = { \ | ||
590 | .p_proc = NLMPROC_##proc, \ | ||
591 | .p_encode = (kxdrproc_t)nlm4_xdr_enc_##argtype, \ | ||
592 | .p_decode = (kxdrproc_t)nlm4_xdr_dec_##restype, \ | ||
593 | .p_arglen = NLM4_##argtype##_sz, \ | ||
594 | .p_replen = NLM4_##restype##_sz, \ | ||
595 | .p_statidx = NLMPROC_##proc, \ | ||
596 | .p_name = #proc, \ | ||
597 | } | ||
598 | |||
599 | static struct rpc_procinfo nlm4_procedures[] = { | ||
600 | PROC(TEST, testargs, testres), | ||
601 | PROC(LOCK, lockargs, res), | ||
602 | PROC(CANCEL, cancargs, res), | ||
603 | PROC(UNLOCK, unlockargs, res), | ||
604 | PROC(GRANTED, testargs, res), | ||
605 | PROC(TEST_MSG, testargs, norep), | ||
606 | PROC(LOCK_MSG, lockargs, norep), | ||
607 | PROC(CANCEL_MSG, cancargs, norep), | ||
608 | PROC(UNLOCK_MSG, unlockargs, norep), | ||
609 | PROC(GRANTED_MSG, testargs, norep), | ||
610 | PROC(TEST_RES, testres, norep), | ||
611 | PROC(LOCK_RES, res, norep), | ||
612 | PROC(CANCEL_RES, res, norep), | ||
613 | PROC(UNLOCK_RES, res, norep), | ||
614 | PROC(GRANTED_RES, res, norep), | ||
615 | }; | ||
616 | |||
617 | struct rpc_version nlm_version4 = { | ||
618 | .number = 4, | ||
619 | .nrprocs = ARRAY_SIZE(nlm4_procedures), | ||
620 | .procs = nlm4_procedures, | ||
621 | }; | ||