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