Branch data Line data Source code
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 [ # # ][ # # ]: 0 : if (offset >= NLM4_OFFSET_MAX)
54 : : res = NLM4_OFFSET_MAX;
55 [ # # ][ # # ]: 0 : else if (offset <= -NLM4_OFFSET_MAX)
56 : : res = -NLM4_OFFSET_MAX;
57 : : else
58 : : res = offset;
59 : : return res;
60 : : }
61 : :
62 : 0 : 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 : 0 : *l_offset = loff_t_to_s64(fl->fl_start);
68 [ # # ]: 0 : if (fl->fl_end == OFFSET_MAX)
69 : 0 : *l_len = 0;
70 : : else
71 : 0 : *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
72 : 0 : }
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 NLMv4 basic data types
87 : : *
88 : : * Basic NLMv4 data types are defined in Appendix II, section 6.1.4
89 : : * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter
90 : : * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W".
91 : : *
92 : : * Not all basic data types have their own encoding and decoding
93 : : * functions. For run-time efficiency, some data types are encoded
94 : : * or decoded inline.
95 : : */
96 : :
97 : : static void encode_bool(struct xdr_stream *xdr, const int value)
98 : : {
99 : : __be32 *p;
100 : :
101 : 0 : p = xdr_reserve_space(xdr, 4);
102 [ # # ][ # # ]: 0 : *p = value ? xdr_one : xdr_zero;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
103 : : }
104 : :
105 : 0 : static void encode_int32(struct xdr_stream *xdr, const s32 value)
106 : : {
107 : : __be32 *p;
108 : :
109 : 0 : p = xdr_reserve_space(xdr, 4);
110 [ # # ]: 0 : *p = cpu_to_be32(value);
111 : 0 : }
112 : :
113 : : /*
114 : : * typedef opaque netobj<MAXNETOBJ_SZ>
115 : : */
116 : 0 : static void encode_netobj(struct xdr_stream *xdr,
117 : : const u8 *data, const unsigned int length)
118 : : {
119 : : __be32 *p;
120 : :
121 : 0 : p = xdr_reserve_space(xdr, 4 + length);
122 : 0 : xdr_encode_opaque(p, data, length);
123 : 0 : }
124 : :
125 : 0 : static int decode_netobj(struct xdr_stream *xdr,
126 : : struct xdr_netobj *obj)
127 : : {
128 : : u32 length;
129 : : __be32 *p;
130 : :
131 : 0 : p = xdr_inline_decode(xdr, 4);
132 [ # # ]: 0 : if (unlikely(p == NULL))
133 : : goto out_overflow;
134 : 0 : length = be32_to_cpup(p++);
135 [ # # ]: 0 : if (unlikely(length > XDR_MAX_NETOBJ))
136 : : goto out_size;
137 : 0 : obj->len = length;
138 : 0 : obj->data = (u8 *)p;
139 : 0 : return 0;
140 : : out_size:
141 : : dprintk("NFS: returned netobj was too long: %u\n", length);
142 : : return -EIO;
143 : : out_overflow:
144 : : print_overflow_msg(__func__, xdr);
145 : : return -EIO;
146 : : }
147 : :
148 : : /*
149 : : * netobj cookie;
150 : : */
151 : : static void encode_cookie(struct xdr_stream *xdr,
152 : : const struct nlm_cookie *cookie)
153 : : {
154 : 0 : encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
155 : : }
156 : :
157 : 0 : static int decode_cookie(struct xdr_stream *xdr,
158 : : struct nlm_cookie *cookie)
159 : : {
160 : : u32 length;
161 : : __be32 *p;
162 : :
163 : 0 : p = xdr_inline_decode(xdr, 4);
164 [ # # ]: 0 : if (unlikely(p == NULL))
165 : : goto out_overflow;
166 : 0 : length = be32_to_cpup(p++);
167 : : /* apparently HPUX can return empty cookies */
168 [ # # ]: 0 : if (length == 0)
169 : : goto out_hpux;
170 [ # # ]: 0 : if (length > NLM_MAXCOOKIELEN)
171 : : goto out_size;
172 : 0 : p = xdr_inline_decode(xdr, length);
173 [ # # ]: 0 : if (unlikely(p == NULL))
174 : : goto out_overflow;
175 : 0 : cookie->len = length;
176 : 0 : memcpy(cookie->data, p, length);
177 : 0 : return 0;
178 : : out_hpux:
179 : 0 : cookie->len = 4;
180 : 0 : memset(cookie->data, 0, 4);
181 : 0 : return 0;
182 : : out_size:
183 : : dprintk("NFS: returned cookie was too long: %u\n", length);
184 : : return -EIO;
185 : : out_overflow:
186 : : print_overflow_msg(__func__, xdr);
187 : : return -EIO;
188 : : }
189 : :
190 : : /*
191 : : * netobj fh;
192 : : */
193 : : static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
194 : : {
195 : 0 : encode_netobj(xdr, (u8 *)&fh->data, fh->size);
196 : : }
197 : :
198 : : /*
199 : : * enum nlm4_stats {
200 : : * NLM4_GRANTED = 0,
201 : : * NLM4_DENIED = 1,
202 : : * NLM4_DENIED_NOLOCKS = 2,
203 : : * NLM4_BLOCKED = 3,
204 : : * NLM4_DENIED_GRACE_PERIOD = 4,
205 : : * NLM4_DEADLCK = 5,
206 : : * NLM4_ROFS = 6,
207 : : * NLM4_STALE_FH = 7,
208 : : * NLM4_FBIG = 8,
209 : : * NLM4_FAILED = 9
210 : : * };
211 : : *
212 : : * struct nlm4_stat {
213 : : * nlm4_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 : 0 : static void encode_nlm4_stat(struct xdr_stream *xdr,
221 : : const __be32 stat)
222 : : {
223 : : __be32 *p;
224 : :
225 [ # # ][ # # ]: 0 : BUG_ON(be32_to_cpu(stat) > NLM_FAILED);
226 : 0 : p = xdr_reserve_space(xdr, 4);
227 : 0 : *p = stat;
228 : 0 : }
229 : :
230 : 0 : static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat)
231 : : {
232 : : __be32 *p;
233 : :
234 : 0 : p = xdr_inline_decode(xdr, 4);
235 [ # # ]: 0 : if (unlikely(p == NULL))
236 : : goto out_overflow;
237 [ # # ][ # # ]: 0 : if (unlikely(ntohl(*p) > ntohl(nlm4_failed)))
238 : : goto out_bad_xdr;
239 : 0 : *stat = *p;
240 : 0 : return 0;
241 : : out_bad_xdr:
242 : : dprintk("%s: server returned invalid nlm4_stats value: %u\n",
243 : : __func__, be32_to_cpup(p));
244 : : return -EIO;
245 : : out_overflow:
246 : : print_overflow_msg(__func__, xdr);
247 : : return -EIO;
248 : : }
249 : :
250 : : /*
251 : : * struct nlm4_holder {
252 : : * bool exclusive;
253 : : * int32 svid;
254 : : * netobj oh;
255 : : * uint64 l_offset;
256 : : * uint64 l_len;
257 : : * };
258 : : */
259 : 0 : static void encode_nlm4_holder(struct xdr_stream *xdr,
260 : : const struct nlm_res *result)
261 : : {
262 : 0 : const struct nlm_lock *lock = &result->lock;
263 : : u64 l_offset, l_len;
264 : : __be32 *p;
265 : :
266 : 0 : encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
267 : 0 : encode_int32(xdr, lock->svid);
268 : 0 : encode_netobj(xdr, lock->oh.data, lock->oh.len);
269 : :
270 : 0 : p = xdr_reserve_space(xdr, 4 + 4);
271 : 0 : nlm4_compute_offsets(lock, &l_offset, &l_len);
272 : 0 : p = xdr_encode_hyper(p, l_offset);
273 : 0 : xdr_encode_hyper(p, l_len);
274 : 0 : }
275 : :
276 : 0 : static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
277 : : {
278 : 0 : struct nlm_lock *lock = &result->lock;
279 : 0 : struct file_lock *fl = &lock->fl;
280 : : u64 l_offset, l_len;
281 : : u32 exclusive;
282 : : int error;
283 : 0 : __be32 *p;
284 : : s32 end;
285 : :
286 : 0 : memset(lock, 0, sizeof(*lock));
287 : 0 : locks_init_lock(fl);
288 : :
289 : 0 : p = xdr_inline_decode(xdr, 4 + 4);
290 [ # # ]: 0 : if (unlikely(p == NULL))
291 : : goto out_overflow;
292 : 0 : exclusive = be32_to_cpup(p++);
293 : 0 : lock->svid = be32_to_cpup(p);
294 : 0 : fl->fl_pid = (pid_t)lock->svid;
295 : :
296 : 0 : error = decode_netobj(xdr, &lock->oh);
297 [ # # ]: 0 : if (unlikely(error))
298 : : goto out;
299 : :
300 : 0 : p = xdr_inline_decode(xdr, 8 + 8);
301 [ # # ]: 0 : if (unlikely(p == NULL))
302 : : goto out_overflow;
303 : :
304 : 0 : fl->fl_flags = FL_POSIX;
305 : 0 : fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK;
306 : : p = xdr_decode_hyper(p, &l_offset);
307 : : xdr_decode_hyper(p, &l_len);
308 : 0 : end = l_offset + l_len - 1;
309 : :
310 : 0 : fl->fl_start = (loff_t)l_offset;
311 [ # # ][ # # ]: 0 : if (l_len == 0 || end < 0)
312 : 0 : fl->fl_end = OFFSET_MAX;
313 : : else
314 : 0 : fl->fl_end = (loff_t)end;
315 : : error = 0;
316 : : out:
317 : 0 : return error;
318 : : out_overflow:
319 : : print_overflow_msg(__func__, xdr);
320 : : return -EIO;
321 : : }
322 : :
323 : : /*
324 : : * string caller_name<LM_MAXSTRLEN>;
325 : : */
326 : 0 : static void encode_caller_name(struct xdr_stream *xdr, const char *name)
327 : : {
328 : : /* NB: client-side does not set lock->len */
329 : 0 : u32 length = strlen(name);
330 : : __be32 *p;
331 : :
332 : 0 : p = xdr_reserve_space(xdr, 4 + length);
333 : 0 : xdr_encode_opaque(p, name, length);
334 : 0 : }
335 : :
336 : : /*
337 : : * struct nlm4_lock {
338 : : * string caller_name<LM_MAXSTRLEN>;
339 : : * netobj fh;
340 : : * netobj oh;
341 : : * int32 svid;
342 : : * uint64 l_offset;
343 : : * uint64 l_len;
344 : : * };
345 : : */
346 : 0 : static void encode_nlm4_lock(struct xdr_stream *xdr,
347 : : const struct nlm_lock *lock)
348 : : {
349 : : u64 l_offset, l_len;
350 : : __be32 *p;
351 : :
352 : 0 : encode_caller_name(xdr, lock->caller);
353 : : encode_fh(xdr, &lock->fh);
354 : 0 : encode_netobj(xdr, lock->oh.data, lock->oh.len);
355 : :
356 : 0 : p = xdr_reserve_space(xdr, 4 + 8 + 8);
357 [ # # ]: 0 : *p++ = cpu_to_be32(lock->svid);
358 : :
359 : 0 : nlm4_compute_offsets(lock, &l_offset, &l_len);
360 : 0 : p = xdr_encode_hyper(p, l_offset);
361 : 0 : xdr_encode_hyper(p, l_len);
362 : 0 : }
363 : :
364 : :
365 : : /*
366 : : * NLMv4 XDR encode functions
367 : : *
368 : : * NLMv4 argument types are defined in Appendix II of RFC 1813:
369 : : * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's
370 : : * "Protocols for Interworking: XNFS, Version 3W".
371 : : */
372 : :
373 : : /*
374 : : * struct nlm4_testargs {
375 : : * netobj cookie;
376 : : * bool exclusive;
377 : : * struct nlm4_lock alock;
378 : : * };
379 : : */
380 : 0 : static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
381 : : struct xdr_stream *xdr,
382 : : const struct nlm_args *args)
383 : : {
384 : 0 : const struct nlm_lock *lock = &args->lock;
385 : :
386 : : encode_cookie(xdr, &args->cookie);
387 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
388 : 0 : encode_nlm4_lock(xdr, lock);
389 : 0 : }
390 : :
391 : : /*
392 : : * struct nlm4_lockargs {
393 : : * netobj cookie;
394 : : * bool block;
395 : : * bool exclusive;
396 : : * struct nlm4_lock alock;
397 : : * bool reclaim;
398 : : * int state;
399 : : * };
400 : : */
401 : 0 : static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
402 : : struct xdr_stream *xdr,
403 : : const struct nlm_args *args)
404 : : {
405 : 0 : const struct nlm_lock *lock = &args->lock;
406 : :
407 : : encode_cookie(xdr, &args->cookie);
408 : 0 : encode_bool(xdr, args->block);
409 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
410 : 0 : encode_nlm4_lock(xdr, lock);
411 : 0 : encode_bool(xdr, args->reclaim);
412 : 0 : encode_int32(xdr, args->state);
413 : 0 : }
414 : :
415 : : /*
416 : : * struct nlm4_cancargs {
417 : : * netobj cookie;
418 : : * bool block;
419 : : * bool exclusive;
420 : : * struct nlm4_lock alock;
421 : : * };
422 : : */
423 : 0 : static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
424 : : struct xdr_stream *xdr,
425 : : const struct nlm_args *args)
426 : : {
427 : 0 : const struct nlm_lock *lock = &args->lock;
428 : :
429 : : encode_cookie(xdr, &args->cookie);
430 : 0 : encode_bool(xdr, args->block);
431 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
432 : 0 : encode_nlm4_lock(xdr, lock);
433 : 0 : }
434 : :
435 : : /*
436 : : * struct nlm4_unlockargs {
437 : : * netobj cookie;
438 : : * struct nlm4_lock alock;
439 : : * };
440 : : */
441 : 0 : static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
442 : : struct xdr_stream *xdr,
443 : : const struct nlm_args *args)
444 : : {
445 : 0 : const struct nlm_lock *lock = &args->lock;
446 : :
447 : : encode_cookie(xdr, &args->cookie);
448 : 0 : encode_nlm4_lock(xdr, lock);
449 : 0 : }
450 : :
451 : : /*
452 : : * struct nlm4_res {
453 : : * netobj cookie;
454 : : * nlm4_stat stat;
455 : : * };
456 : : */
457 : 0 : static void nlm4_xdr_enc_res(struct rpc_rqst *req,
458 : : struct xdr_stream *xdr,
459 : : const struct nlm_res *result)
460 : : {
461 : : encode_cookie(xdr, &result->cookie);
462 : 0 : encode_nlm4_stat(xdr, result->status);
463 : 0 : }
464 : :
465 : : /*
466 : : * union nlm4_testrply switch (nlm4_stats stat) {
467 : : * case NLM4_DENIED:
468 : : * struct nlm4_holder holder;
469 : : * default:
470 : : * void;
471 : : * };
472 : : *
473 : : * struct nlm4_testres {
474 : : * netobj cookie;
475 : : * nlm4_testrply test_stat;
476 : : * };
477 : : */
478 : 0 : static void nlm4_xdr_enc_testres(struct rpc_rqst *req,
479 : : struct xdr_stream *xdr,
480 : : const struct nlm_res *result)
481 : : {
482 : : encode_cookie(xdr, &result->cookie);
483 : 0 : encode_nlm4_stat(xdr, result->status);
484 [ # # ]: 0 : if (result->status == nlm_lck_denied)
485 : 0 : encode_nlm4_holder(xdr, result);
486 : 0 : }
487 : :
488 : :
489 : : /*
490 : : * NLMv4 XDR decode functions
491 : : *
492 : : * NLMv4 argument types are defined in Appendix II of RFC 1813:
493 : : * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's
494 : : * "Protocols for Interworking: XNFS, Version 3W".
495 : : */
496 : :
497 : : /*
498 : : * union nlm4_testrply switch (nlm4_stats stat) {
499 : : * case NLM4_DENIED:
500 : : * struct nlm4_holder holder;
501 : : * default:
502 : : * void;
503 : : * };
504 : : *
505 : : * struct nlm4_testres {
506 : : * netobj cookie;
507 : : * nlm4_testrply test_stat;
508 : : * };
509 : : */
510 : 0 : static int decode_nlm4_testrply(struct xdr_stream *xdr,
511 : : struct nlm_res *result)
512 : : {
513 : : int error;
514 : :
515 : 0 : error = decode_nlm4_stat(xdr, &result->status);
516 [ # # ]: 0 : if (unlikely(error))
517 : : goto out;
518 [ # # ]: 0 : if (result->status == nlm_lck_denied)
519 : 0 : error = decode_nlm4_holder(xdr, result);
520 : : out:
521 : 0 : return error;
522 : : }
523 : :
524 : 0 : static int nlm4_xdr_dec_testres(struct rpc_rqst *req,
525 : : struct xdr_stream *xdr,
526 : : struct nlm_res *result)
527 : : {
528 : : int error;
529 : :
530 : 0 : error = decode_cookie(xdr, &result->cookie);
531 [ # # ]: 0 : if (unlikely(error))
532 : : goto out;
533 : 0 : error = decode_nlm4_testrply(xdr, result);
534 : : out:
535 : 0 : return error;
536 : : }
537 : :
538 : : /*
539 : : * struct nlm4_res {
540 : : * netobj cookie;
541 : : * nlm4_stat stat;
542 : : * };
543 : : */
544 : 0 : static int nlm4_xdr_dec_res(struct rpc_rqst *req,
545 : : struct xdr_stream *xdr,
546 : : struct nlm_res *result)
547 : : {
548 : : int error;
549 : :
550 : 0 : error = decode_cookie(xdr, &result->cookie);
551 [ # # ]: 0 : if (unlikely(error))
552 : : goto out;
553 : 0 : error = decode_nlm4_stat(xdr, &result->status);
554 : : out:
555 : 0 : return error;
556 : : }
557 : :
558 : :
559 : : /*
560 : : * For NLM, a void procedure really returns nothing
561 : : */
562 : : #define nlm4_xdr_dec_norep NULL
563 : :
564 : : #define PROC(proc, argtype, restype) \
565 : : [NLMPROC_##proc] = { \
566 : : .p_proc = NLMPROC_##proc, \
567 : : .p_encode = (kxdreproc_t)nlm4_xdr_enc_##argtype, \
568 : : .p_decode = (kxdrdproc_t)nlm4_xdr_dec_##restype, \
569 : : .p_arglen = NLM4_##argtype##_sz, \
570 : : .p_replen = NLM4_##restype##_sz, \
571 : : .p_statidx = NLMPROC_##proc, \
572 : : .p_name = #proc, \
573 : : }
574 : :
575 : : static struct rpc_procinfo nlm4_procedures[] = {
576 : : PROC(TEST, testargs, testres),
577 : : PROC(LOCK, lockargs, res),
578 : : PROC(CANCEL, cancargs, res),
579 : : PROC(UNLOCK, unlockargs, res),
580 : : PROC(GRANTED, testargs, res),
581 : : PROC(TEST_MSG, testargs, norep),
582 : : PROC(LOCK_MSG, lockargs, norep),
583 : : PROC(CANCEL_MSG, cancargs, norep),
584 : : PROC(UNLOCK_MSG, unlockargs, norep),
585 : : PROC(GRANTED_MSG, testargs, norep),
586 : : PROC(TEST_RES, testres, norep),
587 : : PROC(LOCK_RES, res, norep),
588 : : PROC(CANCEL_RES, res, norep),
589 : : PROC(UNLOCK_RES, res, norep),
590 : : PROC(GRANTED_RES, res, norep),
591 : : };
592 : :
593 : : const struct rpc_version nlm_version4 = {
594 : : .number = 4,
595 : : .nrprocs = ARRAY_SIZE(nlm4_procedures),
596 : : .procs = nlm4_procedures,
597 : : };
|