]>
Commit | Line | Data |
---|---|---|
2b061f9e CL |
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 | ||
9c69de4c CH |
18 | #include <uapi/linux/nfs2.h> |
19 | ||
2b061f9e CL |
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 | /* | |
27 | * Declare the space requirements for NLM arguments and replies as | |
28 | * number of 32bit-words | |
29 | */ | |
30 | #define NLM_cookie_sz (1+(NLM_MAXCOOKIELEN>>2)) | |
31 | #define NLM_caller_sz (1+(NLMCLNT_OHSIZE>>2)) | |
32 | #define NLM_owner_sz (1+(NLMCLNT_OHSIZE>>2)) | |
33 | #define NLM_fhandle_sz (1+(NFS2_FHSIZE>>2)) | |
34 | #define NLM_lock_sz (3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz) | |
35 | #define NLM_holder_sz (4+NLM_owner_sz) | |
36 | ||
37 | #define NLM_testargs_sz (NLM_cookie_sz+1+NLM_lock_sz) | |
38 | #define NLM_lockargs_sz (NLM_cookie_sz+4+NLM_lock_sz) | |
39 | #define NLM_cancargs_sz (NLM_cookie_sz+2+NLM_lock_sz) | |
40 | #define NLM_unlockargs_sz (NLM_cookie_sz+NLM_lock_sz) | |
41 | ||
42 | #define NLM_testres_sz (NLM_cookie_sz+1+NLM_holder_sz) | |
43 | #define NLM_res_sz (NLM_cookie_sz+1) | |
44 | #define NLM_norep_sz (0) | |
45 | ||
46 | ||
47 | static s32 loff_t_to_s32(loff_t offset) | |
48 | { | |
49 | s32 res; | |
50 | ||
51 | if (offset >= NLM_OFFSET_MAX) | |
52 | res = NLM_OFFSET_MAX; | |
53 | else if (offset <= -NLM_OFFSET_MAX) | |
54 | res = -NLM_OFFSET_MAX; | |
55 | else | |
56 | res = offset; | |
57 | return res; | |
58 | } | |
59 | ||
60 | static void nlm_compute_offsets(const struct nlm_lock *lock, | |
61 | u32 *l_offset, u32 *l_len) | |
62 | { | |
63 | const struct file_lock *fl = &lock->fl; | |
64 | ||
2b061f9e CL |
65 | *l_offset = loff_t_to_s32(fl->fl_start); |
66 | if (fl->fl_end == OFFSET_MAX) | |
67 | *l_len = 0; | |
68 | else | |
69 | *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); | |
70 | } | |
71 | ||
72 | /* | |
73 | * Handle decode buffer overflows out-of-line. | |
74 | */ | |
75 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | |
76 | { | |
77 | dprintk("lockd: %s prematurely hit the end of our receive buffer. " | |
78 | "Remaining buffer length is %tu words.\n", | |
79 | func, xdr->end - xdr->p); | |
80 | } | |
81 | ||
82 | ||
83 | /* | |
84 | * Encode/decode NLMv3 basic data types | |
85 | * | |
86 | * Basic NLMv3 data types are not defined in an IETF standards | |
87 | * document. X/Open has a description of these data types that | |
88 | * is useful. See Chapter 10 of "Protocols for Interworking: | |
89 | * XNFS, Version 3W". | |
90 | * | |
91 | * Not all basic data types have their own encoding and decoding | |
92 | * functions. For run-time efficiency, some data types are encoded | |
93 | * or decoded inline. | |
94 | */ | |
95 | ||
96 | static void encode_bool(struct xdr_stream *xdr, const int value) | |
97 | { | |
98 | __be32 *p; | |
99 | ||
100 | p = xdr_reserve_space(xdr, 4); | |
101 | *p = value ? xdr_one : xdr_zero; | |
102 | } | |
103 | ||
104 | static void encode_int32(struct xdr_stream *xdr, const s32 value) | |
105 | { | |
106 | __be32 *p; | |
107 | ||
108 | p = xdr_reserve_space(xdr, 4); | |
109 | *p = cpu_to_be32(value); | |
110 | } | |
111 | ||
112 | /* | |
113 | * typedef opaque netobj<MAXNETOBJ_SZ> | |
114 | */ | |
115 | static void encode_netobj(struct xdr_stream *xdr, | |
116 | const u8 *data, const unsigned int length) | |
117 | { | |
118 | __be32 *p; | |
119 | ||
2b061f9e CL |
120 | p = xdr_reserve_space(xdr, 4 + length); |
121 | xdr_encode_opaque(p, data, length); | |
122 | } | |
123 | ||
124 | static int decode_netobj(struct xdr_stream *xdr, | |
125 | struct xdr_netobj *obj) | |
126 | { | |
127 | u32 length; | |
128 | __be32 *p; | |
129 | ||
130 | p = xdr_inline_decode(xdr, 4); | |
131 | if (unlikely(p == NULL)) | |
132 | goto out_overflow; | |
133 | length = be32_to_cpup(p++); | |
134 | if (unlikely(length > XDR_MAX_NETOBJ)) | |
135 | goto out_size; | |
136 | obj->len = length; | |
137 | obj->data = (u8 *)p; | |
138 | return 0; | |
139 | out_size: | |
140 | dprintk("NFS: returned netobj was too long: %u\n", length); | |
141 | return -EIO; | |
142 | out_overflow: | |
143 | print_overflow_msg(__func__, xdr); | |
144 | return -EIO; | |
145 | } | |
146 | ||
147 | /* | |
148 | * netobj cookie; | |
149 | */ | |
150 | static void encode_cookie(struct xdr_stream *xdr, | |
151 | const struct nlm_cookie *cookie) | |
152 | { | |
2b061f9e CL |
153 | encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); |
154 | } | |
155 | ||
156 | static int decode_cookie(struct xdr_stream *xdr, | |
157 | struct nlm_cookie *cookie) | |
158 | { | |
159 | u32 length; | |
160 | __be32 *p; | |
161 | ||
162 | p = xdr_inline_decode(xdr, 4); | |
163 | if (unlikely(p == NULL)) | |
164 | goto out_overflow; | |
165 | length = be32_to_cpup(p++); | |
166 | /* apparently HPUX can return empty cookies */ | |
167 | if (length == 0) | |
168 | goto out_hpux; | |
169 | if (length > NLM_MAXCOOKIELEN) | |
170 | goto out_size; | |
171 | p = xdr_inline_decode(xdr, length); | |
172 | if (unlikely(p == NULL)) | |
173 | goto out_overflow; | |
174 | cookie->len = length; | |
175 | memcpy(cookie->data, p, length); | |
176 | return 0; | |
177 | out_hpux: | |
178 | cookie->len = 4; | |
179 | memset(cookie->data, 0, 4); | |
180 | return 0; | |
181 | out_size: | |
182 | dprintk("NFS: returned cookie was too long: %u\n", length); | |
183 | return -EIO; | |
184 | out_overflow: | |
185 | print_overflow_msg(__func__, xdr); | |
186 | return -EIO; | |
187 | } | |
188 | ||
189 | /* | |
190 | * netobj fh; | |
191 | */ | |
192 | static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) | |
193 | { | |
2b061f9e CL |
194 | encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE); |
195 | } | |
196 | ||
197 | /* | |
198 | * enum nlm_stats { | |
199 | * LCK_GRANTED = 0, | |
200 | * LCK_DENIED = 1, | |
201 | * LCK_DENIED_NOLOCKS = 2, | |
202 | * LCK_BLOCKED = 3, | |
203 | * LCK_DENIED_GRACE_PERIOD = 4 | |
204 | * }; | |
205 | * | |
206 | * | |
207 | * struct nlm_stat { | |
208 | * nlm_stats stat; | |
209 | * }; | |
210 | * | |
211 | * NB: we don't swap bytes for the NLM status values. The upper | |
212 | * layers deal directly with the status value in network byte | |
213 | * order. | |
214 | */ | |
215 | ||
216 | static void encode_nlm_stat(struct xdr_stream *xdr, | |
217 | const __be32 stat) | |
218 | { | |
219 | __be32 *p; | |
220 | ||
cd0b16c1 | 221 | WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD); |
2b061f9e CL |
222 | p = xdr_reserve_space(xdr, 4); |
223 | *p = stat; | |
224 | } | |
225 | ||
226 | static int decode_nlm_stat(struct xdr_stream *xdr, | |
227 | __be32 *stat) | |
228 | { | |
229 | __be32 *p; | |
230 | ||
231 | p = xdr_inline_decode(xdr, 4); | |
232 | if (unlikely(p == NULL)) | |
233 | goto out_overflow; | |
e847469b | 234 | if (unlikely(ntohl(*p) > ntohl(nlm_lck_denied_grace_period))) |
2b061f9e CL |
235 | goto out_enum; |
236 | *stat = *p; | |
237 | return 0; | |
238 | out_enum: | |
239 | dprintk("%s: server returned invalid nlm_stats value: %u\n", | |
240 | __func__, be32_to_cpup(p)); | |
241 | return -EIO; | |
242 | out_overflow: | |
243 | print_overflow_msg(__func__, xdr); | |
244 | return -EIO; | |
245 | } | |
246 | ||
247 | /* | |
248 | * struct nlm_holder { | |
249 | * bool exclusive; | |
250 | * int uppid; | |
251 | * netobj oh; | |
252 | * unsigned l_offset; | |
253 | * unsigned l_len; | |
254 | * }; | |
255 | */ | |
256 | static void encode_nlm_holder(struct xdr_stream *xdr, | |
257 | const struct nlm_res *result) | |
258 | { | |
259 | const struct nlm_lock *lock = &result->lock; | |
260 | u32 l_offset, l_len; | |
261 | __be32 *p; | |
262 | ||
263 | encode_bool(xdr, lock->fl.fl_type == F_RDLCK); | |
264 | encode_int32(xdr, lock->svid); | |
265 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | |
266 | ||
267 | p = xdr_reserve_space(xdr, 4 + 4); | |
268 | nlm_compute_offsets(lock, &l_offset, &l_len); | |
269 | *p++ = cpu_to_be32(l_offset); | |
270 | *p = cpu_to_be32(l_len); | |
271 | } | |
272 | ||
273 | static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result) | |
274 | { | |
275 | struct nlm_lock *lock = &result->lock; | |
276 | struct file_lock *fl = &lock->fl; | |
277 | u32 exclusive, l_offset, l_len; | |
278 | int error; | |
279 | __be32 *p; | |
280 | s32 end; | |
281 | ||
282 | memset(lock, 0, sizeof(*lock)); | |
283 | locks_init_lock(fl); | |
284 | ||
285 | p = xdr_inline_decode(xdr, 4 + 4); | |
286 | if (unlikely(p == NULL)) | |
287 | goto out_overflow; | |
288 | exclusive = be32_to_cpup(p++); | |
289 | lock->svid = be32_to_cpup(p); | |
290 | fl->fl_pid = (pid_t)lock->svid; | |
291 | ||
292 | error = decode_netobj(xdr, &lock->oh); | |
293 | if (unlikely(error)) | |
294 | goto out; | |
295 | ||
296 | p = xdr_inline_decode(xdr, 4 + 4); | |
297 | if (unlikely(p == NULL)) | |
298 | goto out_overflow; | |
299 | ||
300 | fl->fl_flags = FL_POSIX; | |
301 | fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; | |
302 | l_offset = be32_to_cpup(p++); | |
303 | l_len = be32_to_cpup(p); | |
304 | end = l_offset + l_len - 1; | |
305 | ||
306 | fl->fl_start = (loff_t)l_offset; | |
307 | if (l_len == 0 || end < 0) | |
308 | fl->fl_end = OFFSET_MAX; | |
309 | else | |
310 | fl->fl_end = (loff_t)end; | |
311 | error = 0; | |
312 | out: | |
313 | return error; | |
314 | out_overflow: | |
315 | print_overflow_msg(__func__, xdr); | |
316 | return -EIO; | |
317 | } | |
318 | ||
319 | /* | |
320 | * string caller_name<LM_MAXSTRLEN>; | |
321 | */ | |
322 | static void encode_caller_name(struct xdr_stream *xdr, const char *name) | |
323 | { | |
324 | /* NB: client-side does not set lock->len */ | |
325 | u32 length = strlen(name); | |
326 | __be32 *p; | |
327 | ||
2b061f9e CL |
328 | p = xdr_reserve_space(xdr, 4 + length); |
329 | xdr_encode_opaque(p, name, length); | |
330 | } | |
331 | ||
332 | /* | |
333 | * struct nlm_lock { | |
334 | * string caller_name<LM_MAXSTRLEN>; | |
335 | * netobj fh; | |
336 | * netobj oh; | |
337 | * int uppid; | |
338 | * unsigned l_offset; | |
339 | * unsigned l_len; | |
340 | * }; | |
341 | */ | |
342 | static void encode_nlm_lock(struct xdr_stream *xdr, | |
343 | const struct nlm_lock *lock) | |
344 | { | |
345 | u32 l_offset, l_len; | |
346 | __be32 *p; | |
347 | ||
348 | encode_caller_name(xdr, lock->caller); | |
349 | encode_fh(xdr, &lock->fh); | |
350 | encode_netobj(xdr, lock->oh.data, lock->oh.len); | |
351 | ||
352 | p = xdr_reserve_space(xdr, 4 + 4 + 4); | |
353 | *p++ = cpu_to_be32(lock->svid); | |
354 | ||
355 | nlm_compute_offsets(lock, &l_offset, &l_len); | |
356 | *p++ = cpu_to_be32(l_offset); | |
357 | *p = cpu_to_be32(l_len); | |
358 | } | |
359 | ||
360 | ||
361 | /* | |
362 | * NLMv3 XDR encode functions | |
363 | * | |
364 | * NLMv3 argument types are defined in Chapter 10 of The Open Group's | |
365 | * "Protocols for Interworking: XNFS, Version 3W". | |
366 | */ | |
367 | ||
368 | /* | |
369 | * struct nlm_testargs { | |
370 | * netobj cookie; | |
371 | * bool exclusive; | |
372 | * struct nlm_lock alock; | |
373 | * }; | |
374 | */ | |
9f06c719 CL |
375 | static void nlm_xdr_enc_testargs(struct rpc_rqst *req, |
376 | struct xdr_stream *xdr, | |
377 | const struct nlm_args *args) | |
2b061f9e CL |
378 | { |
379 | const struct nlm_lock *lock = &args->lock; | |
2b061f9e | 380 | |
9f06c719 CL |
381 | encode_cookie(xdr, &args->cookie); |
382 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | |
383 | encode_nlm_lock(xdr, lock); | |
2b061f9e CL |
384 | } |
385 | ||
386 | /* | |
387 | * struct nlm_lockargs { | |
388 | * netobj cookie; | |
389 | * bool block; | |
390 | * bool exclusive; | |
391 | * struct nlm_lock alock; | |
392 | * bool reclaim; | |
393 | * int state; | |
394 | * }; | |
395 | */ | |
9f06c719 CL |
396 | static void nlm_xdr_enc_lockargs(struct rpc_rqst *req, |
397 | struct xdr_stream *xdr, | |
398 | const struct nlm_args *args) | |
2b061f9e CL |
399 | { |
400 | const struct nlm_lock *lock = &args->lock; | |
2b061f9e | 401 | |
9f06c719 CL |
402 | encode_cookie(xdr, &args->cookie); |
403 | encode_bool(xdr, args->block); | |
404 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | |
405 | encode_nlm_lock(xdr, lock); | |
406 | encode_bool(xdr, args->reclaim); | |
407 | encode_int32(xdr, args->state); | |
2b061f9e CL |
408 | } |
409 | ||
410 | /* | |
411 | * struct nlm_cancargs { | |
412 | * netobj cookie; | |
413 | * bool block; | |
414 | * bool exclusive; | |
415 | * struct nlm_lock alock; | |
416 | * }; | |
417 | */ | |
9f06c719 CL |
418 | static void nlm_xdr_enc_cancargs(struct rpc_rqst *req, |
419 | struct xdr_stream *xdr, | |
420 | const struct nlm_args *args) | |
2b061f9e CL |
421 | { |
422 | const struct nlm_lock *lock = &args->lock; | |
2b061f9e | 423 | |
9f06c719 CL |
424 | encode_cookie(xdr, &args->cookie); |
425 | encode_bool(xdr, args->block); | |
426 | encode_bool(xdr, lock->fl.fl_type == F_WRLCK); | |
427 | encode_nlm_lock(xdr, lock); | |
2b061f9e CL |
428 | } |
429 | ||
430 | /* | |
431 | * struct nlm_unlockargs { | |
432 | * netobj cookie; | |
433 | * struct nlm_lock alock; | |
434 | * }; | |
435 | */ | |
9f06c719 CL |
436 | static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req, |
437 | struct xdr_stream *xdr, | |
438 | const struct nlm_args *args) | |
2b061f9e CL |
439 | { |
440 | const struct nlm_lock *lock = &args->lock; | |
2b061f9e | 441 | |
9f06c719 CL |
442 | encode_cookie(xdr, &args->cookie); |
443 | encode_nlm_lock(xdr, lock); | |
2b061f9e CL |
444 | } |
445 | ||
446 | /* | |
447 | * struct nlm_res { | |
448 | * netobj cookie; | |
449 | * nlm_stat stat; | |
450 | * }; | |
451 | */ | |
9f06c719 CL |
452 | static void nlm_xdr_enc_res(struct rpc_rqst *req, |
453 | struct xdr_stream *xdr, | |
454 | const struct nlm_res *result) | |
2b061f9e | 455 | { |
9f06c719 CL |
456 | encode_cookie(xdr, &result->cookie); |
457 | encode_nlm_stat(xdr, result->status); | |
2b061f9e CL |
458 | } |
459 | ||
460 | /* | |
461 | * union nlm_testrply switch (nlm_stats stat) { | |
462 | * case LCK_DENIED: | |
463 | * struct nlm_holder holder; | |
464 | * default: | |
465 | * void; | |
466 | * }; | |
467 | * | |
468 | * struct nlm_testres { | |
469 | * netobj cookie; | |
470 | * nlm_testrply test_stat; | |
471 | * }; | |
472 | */ | |
473 | static void encode_nlm_testrply(struct xdr_stream *xdr, | |
474 | const struct nlm_res *result) | |
475 | { | |
476 | if (result->status == nlm_lck_denied) | |
477 | encode_nlm_holder(xdr, result); | |
478 | } | |
479 | ||
9f06c719 CL |
480 | static void nlm_xdr_enc_testres(struct rpc_rqst *req, |
481 | struct xdr_stream *xdr, | |
482 | const struct nlm_res *result) | |
2b061f9e | 483 | { |
9f06c719 CL |
484 | encode_cookie(xdr, &result->cookie); |
485 | encode_nlm_stat(xdr, result->status); | |
486 | encode_nlm_testrply(xdr, result); | |
2b061f9e CL |
487 | } |
488 | ||
489 | ||
490 | /* | |
491 | * NLMv3 XDR decode functions | |
492 | * | |
493 | * NLMv3 result types are defined in Chapter 10 of The Open Group's | |
494 | * "Protocols for Interworking: XNFS, Version 3W". | |
495 | */ | |
496 | ||
497 | /* | |
498 | * union nlm_testrply switch (nlm_stats stat) { | |
499 | * case LCK_DENIED: | |
500 | * struct nlm_holder holder; | |
501 | * default: | |
502 | * void; | |
503 | * }; | |
504 | * | |
505 | * struct nlm_testres { | |
506 | * netobj cookie; | |
507 | * nlm_testrply test_stat; | |
508 | * }; | |
509 | */ | |
510 | static int decode_nlm_testrply(struct xdr_stream *xdr, | |
511 | struct nlm_res *result) | |
512 | { | |
513 | int error; | |
514 | ||
515 | error = decode_nlm_stat(xdr, &result->status); | |
516 | if (unlikely(error)) | |
517 | goto out; | |
518 | if (result->status == nlm_lck_denied) | |
519 | error = decode_nlm_holder(xdr, result); | |
520 | out: | |
521 | return error; | |
522 | } | |
523 | ||
bf269551 CL |
524 | static int nlm_xdr_dec_testres(struct rpc_rqst *req, |
525 | struct xdr_stream *xdr, | |
2b061f9e CL |
526 | struct nlm_res *result) |
527 | { | |
2b061f9e CL |
528 | int error; |
529 | ||
bf269551 | 530 | error = decode_cookie(xdr, &result->cookie); |
2b061f9e CL |
531 | if (unlikely(error)) |
532 | goto out; | |
bf269551 | 533 | error = decode_nlm_testrply(xdr, result); |
2b061f9e CL |
534 | out: |
535 | return error; | |
536 | } | |
537 | ||
538 | /* | |
539 | * struct nlm_res { | |
540 | * netobj cookie; | |
541 | * nlm_stat stat; | |
542 | * }; | |
543 | */ | |
bf269551 CL |
544 | static int nlm_xdr_dec_res(struct rpc_rqst *req, |
545 | struct xdr_stream *xdr, | |
2b061f9e CL |
546 | struct nlm_res *result) |
547 | { | |
2b061f9e CL |
548 | int error; |
549 | ||
bf269551 | 550 | error = decode_cookie(xdr, &result->cookie); |
2b061f9e CL |
551 | if (unlikely(error)) |
552 | goto out; | |
bf269551 | 553 | error = decode_nlm_stat(xdr, &result->status); |
2b061f9e CL |
554 | out: |
555 | return error; | |
556 | } | |
557 | ||
558 | ||
559 | /* | |
560 | * For NLM, a void procedure really returns nothing | |
561 | */ | |
562 | #define nlm_xdr_dec_norep NULL | |
563 | ||
564 | #define PROC(proc, argtype, restype) \ | |
565 | [NLMPROC_##proc] = { \ | |
566 | .p_proc = NLMPROC_##proc, \ | |
9f06c719 | 567 | .p_encode = (kxdreproc_t)nlm_xdr_enc_##argtype, \ |
bf269551 | 568 | .p_decode = (kxdrdproc_t)nlm_xdr_dec_##restype, \ |
2b061f9e CL |
569 | .p_arglen = NLM_##argtype##_sz, \ |
570 | .p_replen = NLM_##restype##_sz, \ | |
571 | .p_statidx = NLMPROC_##proc, \ | |
572 | .p_name = #proc, \ | |
573 | } | |
574 | ||
575 | static struct rpc_procinfo nlm_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 | ||
a613fa16 | 593 | static const struct rpc_version nlm_version1 = { |
2b061f9e CL |
594 | .number = 1, |
595 | .nrprocs = ARRAY_SIZE(nlm_procedures), | |
596 | .procs = nlm_procedures, | |
597 | }; | |
598 | ||
a613fa16 | 599 | static const struct rpc_version nlm_version3 = { |
2b061f9e CL |
600 | .number = 3, |
601 | .nrprocs = ARRAY_SIZE(nlm_procedures), | |
602 | .procs = nlm_procedures, | |
603 | }; | |
604 | ||
a613fa16 | 605 | static const struct rpc_version *nlm_versions[] = { |
2b061f9e CL |
606 | [1] = &nlm_version1, |
607 | [3] = &nlm_version3, | |
608 | #ifdef CONFIG_LOCKD_V4 | |
609 | [4] = &nlm_version4, | |
610 | #endif | |
611 | }; | |
612 | ||
613 | static struct rpc_stat nlm_rpc_stats; | |
614 | ||
a613fa16 | 615 | const struct rpc_program nlm_program = { |
2b061f9e CL |
616 | .name = "lockd", |
617 | .number = NLM_PROGRAM, | |
618 | .nrvers = ARRAY_SIZE(nlm_versions), | |
619 | .version = nlm_versions, | |
620 | .stats = &nlm_rpc_stats, | |
621 | }; |