1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * linux/fs/lockd/svc4proc.c
4 *
5 * Lockd server procedures. We don't implement the NLM_*_RES
6 * procedures because we don't use the async procedures.
7 *
8 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
9 */
10
11 #include <linux/types.h>
12 #include <linux/time.h>
13 #include <linux/sunrpc/svc_xprt.h>
14
15 #include "lockd.h"
16
17 /*
18 * xdr.h defines SM_MAXSTRLEN and SM_PRIV_SIZE as macros.
19 * nlm4xdr_gen.h defines them as enum constants. Undefine the
20 * macros to allow the xdrgen enum definitions to be used.
21 */
22 #undef SM_MAXSTRLEN
23 #undef SM_PRIV_SIZE
24
25 #include "share.h"
26 #include "nlm4xdr_gen.h"
27
28 /*
29 * Wrapper structures combine xdrgen types with legacy nlm_lock.
30 * The xdrgen field must be first so the structure can be cast
31 * to its XDR type for the RPC dispatch layer.
32 */
33 struct nlm4_testargs_wrapper {
34 struct nlm4_testargs xdrgen;
35 struct nlm_lock lock;
36 };
37
38 static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
39
40 struct nlm4_lockargs_wrapper {
41 struct nlm4_lockargs xdrgen;
42 struct nlm_cookie cookie;
43 struct nlm_lock lock;
44 };
45
46 static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0);
47
48 struct nlm4_cancargs_wrapper {
49 struct nlm4_cancargs xdrgen;
50 struct nlm_lock lock;
51 };
52
53 static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0);
54
55 struct nlm4_unlockargs_wrapper {
56 struct nlm4_unlockargs xdrgen;
57 struct nlm_lock lock;
58 };
59
60 static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0);
61
62 struct nlm4_notifyargs_wrapper {
63 struct nlm4_notifyargs xdrgen;
64 struct nlm_reboot reboot;
65 };
66
67 static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0);
68
69 struct nlm4_notify_wrapper {
70 struct nlm4_notify xdrgen;
71 };
72
73 static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0);
74
75 struct nlm4_testres_wrapper {
76 struct nlm4_testres xdrgen;
77 struct nlm_lock lock;
78 };
79
80 struct nlm4_shareargs_wrapper {
81 struct nlm4_shareargs xdrgen;
82 struct nlm_lock lock;
83 };
84
85 static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0);
86
87 static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
88
89 struct nlm4_res_wrapper {
90 struct nlm4_res xdrgen;
91 struct nlm_cookie cookie;
92 };
93
94 static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
95
96 struct nlm4_shareres_wrapper {
97 struct nlm4_shareres xdrgen;
98 };
99
100 static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0);
101
102 static __be32
nlm4_netobj_to_cookie(struct nlm_cookie * cookie,netobj * object)103 nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
104 {
105 if (object->len > NLM_MAXCOOKIELEN)
106 return nlm_lck_denied_nolocks;
107 cookie->len = object->len;
108 memcpy(cookie->data, object->data, object->len);
109 return nlm_granted;
110 }
111
112 static __be32
nlm4_lock_to_nlm_lock(struct nlm_lock * lock,struct nlm4_lock * alock)113 nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock)
114 {
115 if (alock->fh.len > NFS_MAXFHSIZE)
116 return nlm_lck_denied;
117 lock->fh.size = alock->fh.len;
118 memcpy(lock->fh.data, alock->fh.data, alock->fh.len);
119 lock->oh.len = alock->oh.len;
120 lock->oh.data = alock->oh.data;
121 lock->svid = alock->svid;
122 locks_init_lock(&lock->fl);
123 lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len);
124 return nlm_granted;
125 }
126
127 static struct nlm_host *
nlm4svc_lookup_host(struct svc_rqst * rqstp,string caller,bool monitored)128 nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
129 {
130 struct nlm_host *host;
131
132 if (!nlmsvc_ops)
133 return NULL;
134 host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
135 if (!host)
136 return NULL;
137 if (monitored && nsm_monitor(host) < 0) {
138 nlmsvc_release_host(host);
139 return NULL;
140 }
141 return host;
142 }
143
144 static __be32
nlm4svc_lookup_file(struct svc_rqst * rqstp,struct nlm_host * host,struct nlm_lock * lock,struct nlm_file ** filp,struct nlm4_lock * xdr_lock,unsigned char type)145 nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
146 struct nlm_lock *lock, struct nlm_file **filp,
147 struct nlm4_lock *xdr_lock, unsigned char type)
148 {
149 bool is_test = (rqstp->rq_proc == NLMPROC4_TEST ||
150 rqstp->rq_proc == NLMPROC4_TEST_MSG);
151 struct file_lock *fl = &lock->fl;
152 struct nlm_file *file = NULL;
153 int mode;
154 __be32 error;
155
156 if (xdr_lock->fh.len > NFS_MAXFHSIZE)
157 return nlm_lck_denied_nolocks;
158 lock->fh.size = xdr_lock->fh.len;
159 memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
160
161 lock->oh.len = xdr_lock->oh.len;
162 lock->oh.data = xdr_lock->oh.data;
163
164 lock->svid = xdr_lock->svid;
165 lock->lock_start = xdr_lock->l_offset;
166 lock->lock_len = xdr_lock->l_len;
167
168 if (lock->lock_start > OFFSET_MAX ||
169 (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
170 return nlm4_fbig;
171
172 locks_init_lock(fl);
173 fl->c.flc_type = type;
174 lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
175
176 mode = is_test ? O_RDWR : lock_to_openmode(fl);
177 error = nlm_lookup_file(rqstp, &file, lock, mode);
178 switch (error) {
179 case nlm_granted:
180 break;
181 case nlm__int__stale_fh:
182 return nlm4_stale_fh;
183 case nlm__int__failed:
184 return nlm4_failed;
185 default:
186 return error;
187 }
188 *filp = file;
189
190 fl->c.flc_flags = FL_POSIX;
191 fl->c.flc_file = is_test ? nlmsvc_file_file(file)
192 : file->f_file[mode];
193 fl->c.flc_pid = current->tgid;
194 fl->fl_lmops = &nlmsvc_lock_operations;
195 nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
196 if (!fl->c.flc_owner)
197 return nlm_lck_denied_nolocks;
198
199 return nlm_granted;
200 }
201
202 /**
203 * nlm4svc_proc_null - NULL: Test for presence of service
204 * @rqstp: RPC transaction context
205 *
206 * Returns:
207 * %rpc_success: RPC executed successfully
208 *
209 * RPC synopsis:
210 * void NLMPROC4_NULL(void) = 0;
211 */
212 static __be32
nlm4svc_proc_null(struct svc_rqst * rqstp)213 nlm4svc_proc_null(struct svc_rqst *rqstp)
214 {
215 return rpc_success;
216 }
217
218 /**
219 * nlm4svc_proc_test - TEST: Check for conflicting lock
220 * @rqstp: RPC transaction context
221 *
222 * Returns:
223 * %rpc_success: RPC executed successfully.
224 * %rpc_drop_reply: Do not send an RPC reply.
225 *
226 * RPC synopsis:
227 * nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1;
228 *
229 * Permissible procedure status codes:
230 * %NLM4_GRANTED: The server would be able to grant the
231 * requested lock.
232 * %NLM4_DENIED: The requested lock conflicted with existing
233 * lock reservations for the file.
234 * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
235 * needed to process the request.
236 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
237 * re-establishing existing locks, and is not
238 * yet ready to accept normal service requests.
239 *
240 * The Linux NLM server implementation also returns:
241 * %NLM4_STALE_FH: The request specified an invalid file handle.
242 * %NLM4_FBIG: The request specified a length or offset
243 * that exceeds the range supported by the
244 * server.
245 * %NLM4_FAILED: The request failed for an unspecified reason.
246 */
nlm4svc_proc_test(struct svc_rqst * rqstp)247 static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
248 {
249 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
250 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
251 struct nlm4_testres_wrapper *resp = rqstp->rq_resp;
252 struct nlm_file *file = NULL;
253 struct nlm_host *host;
254
255 resp->xdrgen.cookie = argp->xdrgen.cookie;
256
257 resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
258 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
259 if (!host)
260 goto out;
261
262 resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
263 &file, &argp->xdrgen.alock,
264 type);
265 if (resp->xdrgen.stat.stat)
266 goto out;
267
268 resp->xdrgen.stat.stat = nlmsvc_testlock(rqstp, file, host,
269 &argp->lock, &resp->lock);
270 nlmsvc_release_lockowner(&argp->lock);
271
272 if (resp->xdrgen.stat.stat == nlm_lck_denied) {
273 struct nlm_lock *conf = &resp->lock;
274 struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder;
275
276 holder->exclusive = (conf->fl.c.flc_type != F_RDLCK);
277 holder->svid = conf->svid;
278 holder->oh.len = conf->oh.len;
279 holder->oh.data = conf->oh.data;
280 holder->l_offset = conf->fl.fl_start;
281 if (conf->fl.fl_end == OFFSET_MAX)
282 holder->l_len = 0;
283 else
284 holder->l_len = conf->fl.fl_end - conf->fl.fl_start + 1;
285 }
286
287 out:
288 if (file)
289 nlm_release_file(file);
290 nlmsvc_release_host(host);
291 return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
292 rpc_drop_reply : rpc_success;
293 }
294
295 static __be32
nlm4svc_do_lock(struct svc_rqst * rqstp,bool monitored)296 nlm4svc_do_lock(struct svc_rqst *rqstp, bool monitored)
297 {
298 struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
299 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
300 struct nlm4_res_wrapper *resp = rqstp->rq_resp;
301 struct nlm_file *file = NULL;
302 struct nlm_host *host = NULL;
303
304 resp->xdrgen.cookie = argp->xdrgen.cookie;
305
306 resp->xdrgen.stat.stat = nlm4_netobj_to_cookie(&argp->cookie,
307 &argp->xdrgen.cookie);
308 if (resp->xdrgen.stat.stat)
309 goto out;
310
311 resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
312 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name,
313 monitored);
314 if (!host)
315 goto out;
316
317 resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
318 &file, &argp->xdrgen.alock,
319 type);
320 if (resp->xdrgen.stat.stat)
321 goto out;
322
323 resp->xdrgen.stat.stat = nlmsvc_lock(rqstp, file, host, &argp->lock,
324 argp->xdrgen.block, &argp->cookie,
325 argp->xdrgen.reclaim);
326 if (resp->xdrgen.stat.stat == nlm__int__deadlock)
327 resp->xdrgen.stat.stat = nlm4_deadlock;
328
329 nlmsvc_release_lockowner(&argp->lock);
330
331 out:
332 if (file)
333 nlm_release_file(file);
334 nlmsvc_release_host(host);
335 return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
336 rpc_drop_reply : rpc_success;
337 }
338
339 /**
340 * nlm4svc_proc_lock - LOCK: Establish a monitored lock
341 * @rqstp: RPC transaction context
342 *
343 * Returns:
344 * %rpc_success: RPC executed successfully.
345 * %rpc_drop_reply: Do not send an RPC reply.
346 *
347 * RPC synopsis:
348 * nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2;
349 *
350 * Permissible procedure status codes:
351 * %NLM4_GRANTED: The requested lock was granted.
352 * %NLM4_DENIED: The requested lock conflicted with existing
353 * lock reservations for the file.
354 * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
355 * needed to process the request.
356 * %NLM4_BLOCKED: The blocking request cannot be granted
357 * immediately. The server will send an
358 * NLMPROC4_GRANTED callback to the client when
359 * the lock can be granted.
360 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
361 * re-establishing existing locks, and is not
362 * yet ready to accept normal service requests.
363 *
364 * The Linux NLM server implementation also returns:
365 * %NLM4_DEADLCK: The request could not be granted and
366 * blocking would cause a deadlock.
367 * %NLM4_STALE_FH: The request specified an invalid file handle.
368 * %NLM4_FBIG: The request specified a length or offset
369 * that exceeds the range supported by the
370 * server.
371 * %NLM4_FAILED: The request failed for an unspecified reason.
372 */
373 static __be32
nlm4svc_proc_lock(struct svc_rqst * rqstp)374 nlm4svc_proc_lock(struct svc_rqst *rqstp)
375 {
376 return nlm4svc_do_lock(rqstp, true);
377 }
378
379 /**
380 * nlm4svc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request
381 * @rqstp: RPC transaction context
382 *
383 * Returns:
384 * %rpc_success: RPC executed successfully
385 * %rpc_drop_reply: Do not send an RPC reply
386 *
387 * RPC synopsis:
388 * nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3;
389 *
390 * Permissible procedure status codes:
391 * %NLM4_LCK_GRANTED: The requested lock was canceled.
392 * %NLM4_LCK_DENIED: There was no lock to cancel.
393 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
394 * re-establishing existing locks, and is not
395 * yet ready to accept normal service requests.
396 *
397 * The Linux NLM server implementation also returns:
398 * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
399 * %NLM4_STALE_FH: The request specified an invalid file handle.
400 * %NLM4_FBIG: The request specified a length or offset
401 * that exceeds the range supported by the
402 * server.
403 * %NLM4_FAILED: The request failed for an unspecified reason.
404 */
405 static __be32
nlm4svc_proc_cancel(struct svc_rqst * rqstp)406 nlm4svc_proc_cancel(struct svc_rqst *rqstp)
407 {
408 struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
409 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
410 struct nlm4_res_wrapper *resp = rqstp->rq_resp;
411 struct net *net = SVC_NET(rqstp);
412 struct nlm_host *host = NULL;
413 struct nlm_file *file = NULL;
414
415 resp->xdrgen.cookie = argp->xdrgen.cookie;
416
417 resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
418 if (locks_in_grace(net))
419 goto out;
420
421 resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
422 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
423 if (!host)
424 goto out;
425
426 resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
427 &file, &argp->xdrgen.alock,
428 type);
429 if (resp->xdrgen.stat.stat)
430 goto out;
431
432 resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock);
433 nlmsvc_release_lockowner(&argp->lock);
434
435 out:
436 if (file)
437 nlm_release_file(file);
438 nlmsvc_release_host(host);
439 return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
440 rpc_drop_reply : rpc_success;
441 }
442
443 /**
444 * nlm4svc_proc_unlock - UNLOCK: Remove a lock
445 * @rqstp: RPC transaction context
446 *
447 * Returns:
448 * %rpc_success: RPC executed successfully.
449 * %rpc_drop_reply: Do not send an RPC reply.
450 *
451 * RPC synopsis:
452 * nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4;
453 *
454 * Permissible procedure status codes:
455 * %NLM4_GRANTED: The requested lock was released.
456 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
457 * re-establishing existing locks, and is not
458 * yet ready to accept normal service requests.
459 *
460 * The Linux NLM server implementation also returns:
461 * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
462 * %NLM4_STALE_FH: The request specified an invalid file handle.
463 * %NLM4_FBIG: The request specified a length or offset
464 * that exceeds the range supported by the
465 * server.
466 * %NLM4_FAILED: The request failed for an unspecified reason.
467 */
468 static __be32
nlm4svc_proc_unlock(struct svc_rqst * rqstp)469 nlm4svc_proc_unlock(struct svc_rqst *rqstp)
470 {
471 struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
472 struct nlm4_res_wrapper *resp = rqstp->rq_resp;
473 struct net *net = SVC_NET(rqstp);
474 struct nlm_host *host = NULL;
475 struct nlm_file *file = NULL;
476
477 resp->xdrgen.cookie = argp->xdrgen.cookie;
478
479 resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
480 if (locks_in_grace(net))
481 goto out;
482
483 resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
484 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
485 if (!host)
486 goto out;
487
488 resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
489 &file, &argp->xdrgen.alock,
490 F_UNLCK);
491 if (resp->xdrgen.stat.stat)
492 goto out;
493
494 resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock);
495 nlmsvc_release_lockowner(&argp->lock);
496
497 out:
498 if (file)
499 nlm_release_file(file);
500 nlmsvc_release_host(host);
501 return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
502 rpc_drop_reply : rpc_success;
503 }
504
505 /**
506 * nlm4svc_proc_granted - GRANTED: Server grants a previously blocked lock
507 * @rqstp: RPC transaction context
508 *
509 * Returns:
510 * %rpc_success: RPC executed successfully.
511 *
512 * RPC synopsis:
513 * nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5;
514 *
515 * Permissible procedure status codes:
516 * %NLM4_GRANTED: The requested lock was granted.
517 * %NLM4_DENIED: The server could not allocate the resources
518 * needed to process the request.
519 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
520 * re-establishing existing locks, and is not
521 * yet ready to accept normal service requests.
522 */
523 static __be32
nlm4svc_proc_granted(struct svc_rqst * rqstp)524 nlm4svc_proc_granted(struct svc_rqst *rqstp)
525 {
526 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
527 struct nlm4_res_wrapper *resp = rqstp->rq_resp;
528
529 resp->xdrgen.cookie = argp->xdrgen.cookie;
530
531 resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock,
532 &argp->xdrgen.alock);
533 if (resp->xdrgen.stat.stat)
534 goto out;
535
536 resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
537
538 out:
539 return rpc_success;
540 }
541
542 /*
543 * This is the generic lockd callback for async RPC calls
544 */
nlm4svc_callback_exit(struct rpc_task * task,void * data)545 static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
546 {
547 }
548
nlm4svc_callback_release(void * data)549 static void nlm4svc_callback_release(void *data)
550 {
551 nlmsvc_release_call(data);
552 }
553
554 static const struct rpc_call_ops nlm4svc_callback_ops = {
555 .rpc_call_done = nlm4svc_callback_exit,
556 .rpc_release = nlm4svc_callback_release,
557 };
558
559 /*
560 * Dispatch an async callback RPC to a client with a pre-resolved host.
561 * Caller provides a reference to @host; this function takes ownership
562 * and releases it via nlmsvc_release_host() before returning.
563 */
564 static __be32
nlm4svc_callback(struct svc_rqst * rqstp,struct nlm_host * host,u32 proc,__be32 (* func)(struct svc_rqst *,struct nlm_res *))565 nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
566 __be32 (*func)(struct svc_rqst *, struct nlm_res *))
567 {
568 struct nlm_rqst *call;
569 __be32 stat;
570
571 call = nlm_alloc_call(host);
572 nlmsvc_release_host(host);
573 if (call == NULL)
574 return rpc_system_err;
575
576 stat = func(rqstp, &call->a_res);
577 if (stat != 0) {
578 nlmsvc_release_call(call);
579 return stat;
580 }
581
582 call->a_flags = RPC_TASK_ASYNC;
583 if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
584 return rpc_system_err;
585 return rpc_success;
586 }
587
588 static __be32
__nlm4svc_proc_test_msg(struct svc_rqst * rqstp,struct nlm_res * resp)589 __nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
590 {
591 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
592 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
593 struct nlm_lockowner *owner;
594 struct nlm_file *file = NULL;
595 struct nlm_host *host = NULL;
596
597 resp->status = nlm_lck_denied_nolocks;
598 if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
599 goto out;
600
601 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
602 if (!host)
603 goto out;
604
605 resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
606 &file, &argp->xdrgen.alock, type);
607 if (resp->status)
608 goto out;
609
610 owner = argp->lock.fl.c.flc_owner;
611 resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock,
612 &resp->lock);
613 nlmsvc_put_lockowner(owner);
614
615 out:
616 if (file)
617 nlm_release_file(file);
618 nlmsvc_release_host(host);
619 return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success;
620 }
621
622 /**
623 * nlm4svc_proc_test_msg - TEST_MSG: Check for conflicting lock
624 * @rqstp: RPC transaction context
625 *
626 * Returns:
627 * %rpc_success: RPC executed successfully.
628 * %rpc_system_err: RPC execution failed.
629 *
630 * RPC synopsis:
631 * void NLMPROC4_TEST_MSG(nlm4_testargs) = 6;
632 *
633 * The response to this request is delivered via the TEST_RES procedure.
634 */
nlm4svc_proc_test_msg(struct svc_rqst * rqstp)635 static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
636 {
637 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
638 struct nlm_host *host;
639
640 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
641 if (!host)
642 return rpc_system_err;
643
644 return nlm4svc_callback(rqstp, host, NLMPROC4_TEST_RES,
645 __nlm4svc_proc_test_msg);
646 }
647
648 static __be32
__nlm4svc_proc_lock_msg(struct svc_rqst * rqstp,struct nlm_res * resp)649 __nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
650 {
651 struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
652 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
653 struct nlm_file *file = NULL;
654 struct nlm_host *host = NULL;
655
656 resp->status = nlm_lck_denied_nolocks;
657 if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
658 goto out;
659
660 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
661 if (!host)
662 goto out;
663
664 resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
665 &file, &argp->xdrgen.alock, type);
666 if (resp->status)
667 goto out;
668
669 resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
670 argp->xdrgen.block, &resp->cookie,
671 argp->xdrgen.reclaim);
672 nlmsvc_release_lockowner(&argp->lock);
673
674 out:
675 if (file)
676 nlm_release_file(file);
677 nlmsvc_release_host(host);
678 return resp->status == nlm__int__drop_reply ?
679 rpc_drop_reply : rpc_success;
680 }
681
682 /**
683 * nlm4svc_proc_lock_msg - LOCK_MSG: Establish a monitored lock
684 * @rqstp: RPC transaction context
685 *
686 * Returns:
687 * %rpc_success: RPC executed successfully.
688 * %rpc_system_err: RPC execution failed.
689 *
690 * RPC synopsis:
691 * void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7;
692 *
693 * The response to this request is delivered via the LOCK_RES procedure.
694 */
nlm4svc_proc_lock_msg(struct svc_rqst * rqstp)695 static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
696 {
697 struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
698 struct nlm_host *host;
699
700 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
701 if (!host)
702 return rpc_system_err;
703
704 return nlm4svc_callback(rqstp, host, NLMPROC4_LOCK_RES,
705 __nlm4svc_proc_lock_msg);
706 }
707
708 static __be32
__nlm4svc_proc_cancel_msg(struct svc_rqst * rqstp,struct nlm_res * resp)709 __nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
710 {
711 struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
712 unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
713 struct net *net = SVC_NET(rqstp);
714 struct nlm_file *file = NULL;
715 struct nlm_host *host = NULL;
716
717 resp->status = nlm_lck_denied_nolocks;
718 if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
719 goto out;
720
721 resp->status = nlm_lck_denied_grace_period;
722 if (locks_in_grace(net))
723 goto out;
724
725 resp->status = nlm_lck_denied_nolocks;
726 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
727 if (!host)
728 goto out;
729
730 resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
731 &file, &argp->xdrgen.alock, type);
732 if (resp->status)
733 goto out;
734
735 resp->status = nlmsvc_cancel_blocked(net, file, &argp->lock);
736 nlmsvc_release_lockowner(&argp->lock);
737
738 out:
739 if (file)
740 nlm_release_file(file);
741 nlmsvc_release_host(host);
742 return resp->status == nlm__int__drop_reply ?
743 rpc_drop_reply : rpc_success;
744 }
745
746 /**
747 * nlm4svc_proc_cancel_msg - CANCEL_MSG: Cancel an outstanding lock request
748 * @rqstp: RPC transaction context
749 *
750 * Returns:
751 * %rpc_success: RPC executed successfully.
752 * %rpc_system_err: RPC execution failed.
753 *
754 * RPC synopsis:
755 * void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8;
756 *
757 * The response to this request is delivered via the CANCEL_RES procedure.
758 */
nlm4svc_proc_cancel_msg(struct svc_rqst * rqstp)759 static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
760 {
761 struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
762 struct nlm_host *host;
763
764 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
765 if (!host)
766 return rpc_system_err;
767
768 return nlm4svc_callback(rqstp, host, NLMPROC4_CANCEL_RES,
769 __nlm4svc_proc_cancel_msg);
770 }
771
772 static __be32
__nlm4svc_proc_unlock_msg(struct svc_rqst * rqstp,struct nlm_res * resp)773 __nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
774 {
775 struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
776 struct net *net = SVC_NET(rqstp);
777 struct nlm_file *file = NULL;
778 struct nlm_host *host = NULL;
779
780 resp->status = nlm_lck_denied_nolocks;
781 if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
782 goto out;
783
784 resp->status = nlm_lck_denied_grace_period;
785 if (locks_in_grace(net))
786 goto out;
787
788 resp->status = nlm_lck_denied_nolocks;
789 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
790 if (!host)
791 goto out;
792
793 resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
794 &file, &argp->xdrgen.alock, F_UNLCK);
795 if (resp->status)
796 goto out;
797
798 resp->status = nlmsvc_unlock(net, file, &argp->lock);
799 nlmsvc_release_lockowner(&argp->lock);
800
801 out:
802 if (file)
803 nlm_release_file(file);
804 nlmsvc_release_host(host);
805 return resp->status == nlm__int__drop_reply ?
806 rpc_drop_reply : rpc_success;
807 }
808
809 /**
810 * nlm4svc_proc_unlock_msg - UNLOCK_MSG: Remove an existing lock
811 * @rqstp: RPC transaction context
812 *
813 * Returns:
814 * %rpc_success: RPC executed successfully.
815 * %rpc_system_err: RPC execution failed.
816 *
817 * RPC synopsis:
818 * void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;
819 *
820 * The response to this request is delivered via the UNLOCK_RES procedure.
821 */
nlm4svc_proc_unlock_msg(struct svc_rqst * rqstp)822 static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
823 {
824 struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
825 struct nlm_host *host;
826
827 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
828 if (!host)
829 return rpc_system_err;
830
831 return nlm4svc_callback(rqstp, host, NLMPROC4_UNLOCK_RES,
832 __nlm4svc_proc_unlock_msg);
833 }
834
835 static __be32
__nlm4svc_proc_granted_msg(struct svc_rqst * rqstp,struct nlm_res * resp)836 __nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
837 {
838 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
839
840 resp->status = nlm_lck_denied;
841 if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
842 goto out;
843
844 if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock))
845 goto out;
846
847 resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
848
849 out:
850 return rpc_success;
851 }
852
853 /**
854 * nlm4svc_proc_granted_msg - GRANTED_MSG: Blocked lock has been granted
855 * @rqstp: RPC transaction context
856 *
857 * Returns:
858 * %rpc_success: RPC executed successfully.
859 * %rpc_system_err: RPC execution failed.
860 *
861 * RPC synopsis:
862 * void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;
863 *
864 * The response to this request is delivered via the GRANTED_RES procedure.
865 */
nlm4svc_proc_granted_msg(struct svc_rqst * rqstp)866 static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
867 {
868 struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
869 struct nlm_host *host;
870
871 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
872 if (!host)
873 return rpc_system_err;
874
875 return nlm4svc_callback(rqstp, host, NLMPROC4_GRANTED_RES,
876 __nlm4svc_proc_granted_msg);
877 }
878
879 /**
880 * nlm4svc_proc_granted_res - GRANTED_RES: Lock Granted result
881 * @rqstp: RPC transaction context
882 *
883 * Returns:
884 * %rpc_success: RPC executed successfully.
885 *
886 * RPC synopsis:
887 * void NLMPROC4_GRANTED_RES(nlm4_res) = 15;
888 */
nlm4svc_proc_granted_res(struct svc_rqst * rqstp)889 static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
890 {
891 struct nlm4_res_wrapper *argp = rqstp->rq_argp;
892
893 if (!nlmsvc_ops)
894 return rpc_success;
895
896 if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie))
897 return rpc_success;
898 nlmsvc_grant_reply(&argp->cookie, argp->xdrgen.stat.stat);
899
900 return rpc_success;
901 }
902
903 /**
904 * nlm4svc_proc_sm_notify - SM_NOTIFY: Peer has rebooted
905 * @rqstp: RPC transaction context
906 *
907 * Returns:
908 * %rpc_success: RPC executed successfully.
909 * %rpc_system_err: RPC execution failed.
910 *
911 * The SM_NOTIFY procedure is a private callback from Linux statd and is
912 * not part of the official NLM protocol.
913 *
914 * RPC synopsis:
915 * void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16;
916 */
nlm4svc_proc_sm_notify(struct svc_rqst * rqstp)917 static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
918 {
919 struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp;
920 struct nlm_reboot *reboot = &argp->reboot;
921
922 if (!nlm_privileged_requester(rqstp)) {
923 char buf[RPC_MAX_ADDRBUFLEN];
924
925 pr_warn("lockd: rejected NSM callback from %s\n",
926 svc_print_addr(rqstp, buf, sizeof(buf)));
927 return rpc_system_err;
928 }
929
930 reboot->len = argp->xdrgen.notify.name.len;
931 reboot->mon = (char *)argp->xdrgen.notify.name.data;
932 reboot->state = argp->xdrgen.notify.state;
933 memcpy(&reboot->priv.data, argp->xdrgen.private,
934 sizeof(reboot->priv.data));
935
936 nlm_host_rebooted(SVC_NET(rqstp), reboot);
937
938 return rpc_success;
939 }
940
941 /**
942 * nlm4svc_proc_unused - stub for unused procedures
943 * @rqstp: RPC transaction context
944 *
945 * Returns:
946 * %rpc_proc_unavail: Program can't support procedure.
947 */
nlm4svc_proc_unused(struct svc_rqst * rqstp)948 static __be32 nlm4svc_proc_unused(struct svc_rqst *rqstp)
949 {
950 return rpc_proc_unavail;
951 }
952
953 /**
954 * nlm4svc_proc_share - SHARE: Open a file using DOS file-sharing modes
955 * @rqstp: RPC transaction context
956 *
957 * Returns:
958 * %rpc_success: RPC executed successfully.
959 * %rpc_drop_reply: Do not send an RPC reply.
960 *
961 * RPC synopsis:
962 * nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20;
963 *
964 * Permissible procedure status codes:
965 * %NLM4_GRANTED: The requested share lock was granted.
966 * %NLM4_DENIED: The requested lock conflicted with existing
967 * lock reservations for the file.
968 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
969 * re-establishing existing locks, and is not
970 * yet ready to accept normal service requests.
971 *
972 * The Linux NLM server implementation also returns:
973 * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
974 * %NLM4_STALE_FH: The request specified an invalid file handle.
975 * %NLM4_FBIG: The request specified a length or offset
976 * that exceeds the range supported by the
977 * server.
978 * %NLM4_FAILED: The request failed for an unspecified reason.
979 */
nlm4svc_proc_share(struct svc_rqst * rqstp)980 static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
981 {
982 struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
983 struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
984 struct nlm_lock *lock = &argp->lock;
985 struct nlm_host *host = NULL;
986 struct nlm_file *file = NULL;
987 struct nlm4_lock xdr_lock = {
988 .fh = argp->xdrgen.share.fh,
989 .oh = argp->xdrgen.share.oh,
990 .svid = LOCKD_SHARE_SVID,
991 };
992
993 resp->xdrgen.cookie = argp->xdrgen.cookie;
994
995 resp->xdrgen.stat = nlm_lck_denied_grace_period;
996 if (locks_in_grace(SVC_NET(rqstp)) && !argp->xdrgen.reclaim)
997 goto out;
998
999 resp->xdrgen.stat = nlm_lck_denied_nolocks;
1000 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
1001 if (!host)
1002 goto out;
1003
1004 resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
1005 &xdr_lock, F_RDLCK);
1006 if (resp->xdrgen.stat)
1007 goto out;
1008
1009 resp->xdrgen.stat = nlmsvc_share_file(host, file, &lock->oh,
1010 argp->xdrgen.share.access,
1011 argp->xdrgen.share.mode);
1012
1013 nlmsvc_release_lockowner(lock);
1014
1015 out:
1016 if (file)
1017 nlm_release_file(file);
1018 nlmsvc_release_host(host);
1019 return resp->xdrgen.stat == nlm__int__drop_reply ?
1020 rpc_drop_reply : rpc_success;
1021 }
1022
1023 /**
1024 * nlm4svc_proc_unshare - UNSHARE: Release a share reservation
1025 * @rqstp: RPC transaction context
1026 *
1027 * Returns:
1028 * %rpc_success: RPC executed successfully.
1029 * %rpc_drop_reply: Do not send an RPC reply.
1030 *
1031 * RPC synopsis:
1032 * nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21;
1033 *
1034 * Permissible procedure status codes:
1035 * %NLM4_GRANTED: The share reservation was released.
1036 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
1037 * re-establishing existing locks, and is not
1038 * yet ready to accept normal service requests.
1039 *
1040 * The Linux NLM server implementation also returns:
1041 * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
1042 * %NLM4_STALE_FH: The request specified an invalid file handle.
1043 * %NLM4_FBIG: The request specified a length or offset
1044 * that exceeds the range supported by the
1045 * server.
1046 * %NLM4_FAILED: The request failed for an unspecified reason.
1047 */
nlm4svc_proc_unshare(struct svc_rqst * rqstp)1048 static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
1049 {
1050 struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
1051 struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
1052 struct nlm_lock *lock = &argp->lock;
1053 struct nlm4_lock xdr_lock = {
1054 .fh = argp->xdrgen.share.fh,
1055 .oh = argp->xdrgen.share.oh,
1056 .svid = LOCKD_SHARE_SVID,
1057 };
1058 struct nlm_host *host = NULL;
1059 struct nlm_file *file = NULL;
1060
1061 resp->xdrgen.cookie = argp->xdrgen.cookie;
1062
1063 resp->xdrgen.stat = nlm_lck_denied_grace_period;
1064 if (locks_in_grace(SVC_NET(rqstp)))
1065 goto out;
1066
1067 resp->xdrgen.stat = nlm_lck_denied_nolocks;
1068 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
1069 if (!host)
1070 goto out;
1071
1072 resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
1073 &xdr_lock, F_RDLCK);
1074 if (resp->xdrgen.stat)
1075 goto out;
1076
1077 resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh);
1078
1079 nlmsvc_release_lockowner(lock);
1080
1081 out:
1082 if (file)
1083 nlm_release_file(file);
1084 nlmsvc_release_host(host);
1085 return resp->xdrgen.stat == nlm__int__drop_reply ?
1086 rpc_drop_reply : rpc_success;
1087 }
1088
1089 /**
1090 * nlm4svc_proc_nm_lock - NM_LOCK: Establish a non-monitored lock
1091 * @rqstp: RPC transaction context
1092 *
1093 * Returns:
1094 * %rpc_success: RPC executed successfully.
1095 * %rpc_drop_reply: Do not send an RPC reply.
1096 *
1097 * RPC synopsis:
1098 * nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22;
1099 *
1100 * Permissible procedure status codes:
1101 * %NLM4_GRANTED: The requested lock was granted.
1102 * %NLM4_DENIED: The requested lock conflicted with existing
1103 * lock reservations for the file.
1104 * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
1105 * needed to process the request.
1106 * %NLM4_BLOCKED: The blocking request cannot be granted
1107 * immediately. The server will send an
1108 * NLMPROC4_GRANTED callback to the client when
1109 * the lock can be granted.
1110 * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
1111 * re-establishing existing locks, and is not
1112 * yet ready to accept normal service requests.
1113 *
1114 * The Linux NLM server implementation also returns:
1115 * %NLM4_DEADLCK: The request could not be granted and
1116 * blocking would cause a deadlock.
1117 * %NLM4_STALE_FH: The request specified an invalid file handle.
1118 * %NLM4_FBIG: The request specified a length or offset
1119 * that exceeds the range supported by the
1120 * server.
1121 * %NLM4_FAILED: The request failed for an unspecified reason.
1122 */
nlm4svc_proc_nm_lock(struct svc_rqst * rqstp)1123 static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
1124 {
1125 return nlm4svc_do_lock(rqstp, false);
1126 }
1127
1128 /**
1129 * nlm4svc_proc_free_all - FREE_ALL: Discard client's lock and share state
1130 * @rqstp: RPC transaction context
1131 *
1132 * Returns:
1133 * %rpc_success: RPC executed successfully.
1134 *
1135 * RPC synopsis:
1136 * void NLMPROC4_FREE_ALL(nlm4_notify) = 23;
1137 */
nlm4svc_proc_free_all(struct svc_rqst * rqstp)1138 static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp)
1139 {
1140 struct nlm4_notify_wrapper *argp = rqstp->rq_argp;
1141 struct nlm_host *host;
1142
1143 host = nlm4svc_lookup_host(rqstp, argp->xdrgen.name, false);
1144 if (!host)
1145 goto out;
1146
1147 nlmsvc_free_host_resources(host);
1148
1149 nlmsvc_release_host(host);
1150
1151 out:
1152 return rpc_success;
1153 }
1154
1155
1156 /*
1157 * NLMv4 Server procedures.
1158 */
1159
1160 static const struct svc_procedure nlm4svc_procedures[24] = {
1161 [NLMPROC4_NULL] = {
1162 .pc_func = nlm4svc_proc_null,
1163 .pc_decode = nlm4_svc_decode_void,
1164 .pc_encode = nlm4_svc_encode_void,
1165 .pc_argsize = XDR_void,
1166 .pc_argzero = 0,
1167 .pc_ressize = 0,
1168 .pc_xdrressize = XDR_void,
1169 .pc_name = "NULL",
1170 },
1171 [NLMPROC4_TEST] = {
1172 .pc_func = nlm4svc_proc_test,
1173 .pc_decode = nlm4_svc_decode_nlm4_testargs,
1174 .pc_encode = nlm4_svc_encode_nlm4_testres,
1175 .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
1176 .pc_argzero = 0,
1177 .pc_ressize = sizeof(struct nlm4_testres_wrapper),
1178 .pc_xdrressize = NLM4_nlm4_testres_sz,
1179 .pc_name = "TEST",
1180 },
1181 [NLMPROC4_LOCK] = {
1182 .pc_func = nlm4svc_proc_lock,
1183 .pc_decode = nlm4_svc_decode_nlm4_lockargs,
1184 .pc_encode = nlm4_svc_encode_nlm4_res,
1185 .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
1186 .pc_argzero = 0,
1187 .pc_ressize = sizeof(struct nlm4_res_wrapper),
1188 .pc_xdrressize = NLM4_nlm4_res_sz,
1189 .pc_name = "LOCK",
1190 },
1191 [NLMPROC4_CANCEL] = {
1192 .pc_func = nlm4svc_proc_cancel,
1193 .pc_decode = nlm4_svc_decode_nlm4_cancargs,
1194 .pc_encode = nlm4_svc_encode_nlm4_res,
1195 .pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
1196 .pc_argzero = 0,
1197 .pc_ressize = sizeof(struct nlm4_res_wrapper),
1198 .pc_xdrressize = NLM4_nlm4_res_sz,
1199 .pc_name = "CANCEL",
1200 },
1201 [NLMPROC4_UNLOCK] = {
1202 .pc_func = nlm4svc_proc_unlock,
1203 .pc_decode = nlm4_svc_decode_nlm4_unlockargs,
1204 .pc_encode = nlm4_svc_encode_nlm4_res,
1205 .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
1206 .pc_argzero = 0,
1207 .pc_ressize = sizeof(struct nlm4_res_wrapper),
1208 .pc_xdrressize = NLM4_nlm4_res_sz,
1209 .pc_name = "UNLOCK",
1210 },
1211 [NLMPROC4_GRANTED] = {
1212 .pc_func = nlm4svc_proc_granted,
1213 .pc_decode = nlm4_svc_decode_nlm4_testargs,
1214 .pc_encode = nlm4_svc_encode_nlm4_res,
1215 .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
1216 .pc_argzero = 0,
1217 .pc_ressize = sizeof(struct nlm4_res_wrapper),
1218 .pc_xdrressize = NLM4_nlm4_res_sz,
1219 .pc_name = "GRANTED",
1220 },
1221 [NLMPROC4_TEST_MSG] = {
1222 .pc_func = nlm4svc_proc_test_msg,
1223 .pc_decode = nlm4_svc_decode_nlm4_testargs,
1224 .pc_encode = nlm4_svc_encode_void,
1225 .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
1226 .pc_argzero = 0,
1227 .pc_ressize = 0,
1228 .pc_xdrressize = XDR_void,
1229 .pc_name = "TEST_MSG",
1230 },
1231 [NLMPROC4_LOCK_MSG] = {
1232 .pc_func = nlm4svc_proc_lock_msg,
1233 .pc_decode = nlm4_svc_decode_nlm4_lockargs,
1234 .pc_encode = nlm4_svc_encode_void,
1235 .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
1236 .pc_argzero = 0,
1237 .pc_ressize = 0,
1238 .pc_xdrressize = XDR_void,
1239 .pc_name = "LOCK_MSG",
1240 },
1241 [NLMPROC4_CANCEL_MSG] = {
1242 .pc_func = nlm4svc_proc_cancel_msg,
1243 .pc_decode = nlm4_svc_decode_nlm4_cancargs,
1244 .pc_encode = nlm4_svc_encode_void,
1245 .pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
1246 .pc_argzero = 0,
1247 .pc_ressize = 0,
1248 .pc_xdrressize = XDR_void,
1249 .pc_name = "CANCEL_MSG",
1250 },
1251 [NLMPROC4_UNLOCK_MSG] = {
1252 .pc_func = nlm4svc_proc_unlock_msg,
1253 .pc_decode = nlm4_svc_decode_nlm4_unlockargs,
1254 .pc_encode = nlm4_svc_encode_void,
1255 .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
1256 .pc_argzero = 0,
1257 .pc_ressize = 0,
1258 .pc_xdrressize = XDR_void,
1259 .pc_name = "UNLOCK_MSG",
1260 },
1261 [NLMPROC4_GRANTED_MSG] = {
1262 .pc_func = nlm4svc_proc_granted_msg,
1263 .pc_decode = nlm4_svc_decode_nlm4_testargs,
1264 .pc_encode = nlm4_svc_encode_void,
1265 .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
1266 .pc_argzero = 0,
1267 .pc_ressize = 0,
1268 .pc_xdrressize = XDR_void,
1269 .pc_name = "GRANTED_MSG",
1270 },
1271 [NLMPROC4_TEST_RES] = {
1272 .pc_func = nlm4svc_proc_null,
1273 .pc_decode = nlm4_svc_decode_nlm4_testres,
1274 .pc_encode = nlm4_svc_encode_void,
1275 .pc_argsize = sizeof(struct nlm4_testres),
1276 .pc_argzero = 0,
1277 .pc_ressize = 0,
1278 .pc_xdrressize = XDR_void,
1279 .pc_name = "TEST_RES",
1280 },
1281 [NLMPROC4_LOCK_RES] = {
1282 .pc_func = nlm4svc_proc_null,
1283 .pc_decode = nlm4_svc_decode_nlm4_res,
1284 .pc_encode = nlm4_svc_encode_void,
1285 .pc_argsize = sizeof(struct nlm4_res),
1286 .pc_argzero = 0,
1287 .pc_ressize = 0,
1288 .pc_xdrressize = XDR_void,
1289 .pc_name = "LOCK_RES",
1290 },
1291 [NLMPROC4_CANCEL_RES] = {
1292 .pc_func = nlm4svc_proc_null,
1293 .pc_decode = nlm4_svc_decode_nlm4_res,
1294 .pc_encode = nlm4_svc_encode_void,
1295 .pc_argsize = sizeof(struct nlm4_res),
1296 .pc_argzero = 0,
1297 .pc_ressize = 0,
1298 .pc_xdrressize = XDR_void,
1299 .pc_name = "CANCEL_RES",
1300 },
1301 [NLMPROC4_UNLOCK_RES] = {
1302 .pc_func = nlm4svc_proc_null,
1303 .pc_decode = nlm4_svc_decode_nlm4_res,
1304 .pc_encode = nlm4_svc_encode_void,
1305 .pc_argsize = sizeof(struct nlm4_res),
1306 .pc_argzero = 0,
1307 .pc_ressize = 0,
1308 .pc_xdrressize = XDR_void,
1309 .pc_name = "UNLOCK_RES",
1310 },
1311 [NLMPROC4_GRANTED_RES] = {
1312 .pc_func = nlm4svc_proc_granted_res,
1313 .pc_decode = nlm4_svc_decode_nlm4_res,
1314 .pc_encode = nlm4_svc_encode_void,
1315 .pc_argsize = sizeof(struct nlm4_res_wrapper),
1316 .pc_argzero = 0,
1317 .pc_ressize = 0,
1318 .pc_xdrressize = XDR_void,
1319 .pc_name = "GRANTED_RES",
1320 },
1321 [NLMPROC4_SM_NOTIFY] = {
1322 .pc_func = nlm4svc_proc_sm_notify,
1323 .pc_decode = nlm4_svc_decode_nlm4_notifyargs,
1324 .pc_encode = nlm4_svc_encode_void,
1325 .pc_argsize = sizeof(struct nlm4_notifyargs_wrapper),
1326 .pc_argzero = 0,
1327 .pc_ressize = 0,
1328 .pc_xdrressize = XDR_void,
1329 .pc_name = "SM_NOTIFY",
1330 },
1331 [17] = {
1332 .pc_func = nlm4svc_proc_unused,
1333 .pc_decode = nlm4_svc_decode_void,
1334 .pc_encode = nlm4_svc_encode_void,
1335 .pc_argsize = 0,
1336 .pc_argzero = 0,
1337 .pc_ressize = 0,
1338 .pc_xdrressize = XDR_void,
1339 .pc_name = "UNUSED",
1340 },
1341 [18] = {
1342 .pc_func = nlm4svc_proc_unused,
1343 .pc_decode = nlm4_svc_decode_void,
1344 .pc_encode = nlm4_svc_encode_void,
1345 .pc_argsize = 0,
1346 .pc_argzero = 0,
1347 .pc_ressize = 0,
1348 .pc_xdrressize = XDR_void,
1349 .pc_name = "UNUSED",
1350 },
1351 [19] = {
1352 .pc_func = nlm4svc_proc_unused,
1353 .pc_decode = nlm4_svc_decode_void,
1354 .pc_encode = nlm4_svc_encode_void,
1355 .pc_argsize = 0,
1356 .pc_argzero = 0,
1357 .pc_ressize = 0,
1358 .pc_xdrressize = XDR_void,
1359 .pc_name = "UNUSED",
1360 },
1361 [NLMPROC4_SHARE] = {
1362 .pc_func = nlm4svc_proc_share,
1363 .pc_decode = nlm4_svc_decode_nlm4_shareargs,
1364 .pc_encode = nlm4_svc_encode_nlm4_shareres,
1365 .pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
1366 .pc_argzero = 0,
1367 .pc_ressize = sizeof(struct nlm4_shareres_wrapper),
1368 .pc_xdrressize = NLM4_nlm4_shareres_sz,
1369 .pc_name = "SHARE",
1370 },
1371 [NLMPROC4_UNSHARE] = {
1372 .pc_func = nlm4svc_proc_unshare,
1373 .pc_decode = nlm4_svc_decode_nlm4_shareargs,
1374 .pc_encode = nlm4_svc_encode_nlm4_shareres,
1375 .pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
1376 .pc_argzero = 0,
1377 .pc_ressize = sizeof(struct nlm4_shareres_wrapper),
1378 .pc_xdrressize = NLM4_nlm4_shareres_sz,
1379 .pc_name = "UNSHARE",
1380 },
1381 [NLMPROC4_NM_LOCK] = {
1382 .pc_func = nlm4svc_proc_nm_lock,
1383 .pc_decode = nlm4_svc_decode_nlm4_lockargs,
1384 .pc_encode = nlm4_svc_encode_nlm4_res,
1385 .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
1386 .pc_argzero = 0,
1387 .pc_ressize = sizeof(struct nlm4_res_wrapper),
1388 .pc_xdrressize = NLM4_nlm4_res_sz,
1389 .pc_name = "NM_LOCK",
1390 },
1391 [NLMPROC4_FREE_ALL] = {
1392 .pc_func = nlm4svc_proc_free_all,
1393 .pc_decode = nlm4_svc_decode_nlm4_notify,
1394 .pc_encode = nlm4_svc_encode_void,
1395 .pc_argsize = sizeof(struct nlm4_notify_wrapper),
1396 .pc_argzero = 0,
1397 .pc_ressize = 0,
1398 .pc_xdrressize = XDR_void,
1399 .pc_name = "FREE_ALL",
1400 },
1401 };
1402
1403 /*
1404 * Storage requirements for XDR arguments and results
1405 */
1406 union nlm4svc_xdrstore {
1407 struct nlm4_testargs_wrapper testargs;
1408 struct nlm4_lockargs_wrapper lockargs;
1409 struct nlm4_cancargs_wrapper cancargs;
1410 struct nlm4_unlockargs_wrapper unlockargs;
1411 struct nlm4_notifyargs_wrapper notifyargs;
1412 struct nlm4_shareargs_wrapper shareargs;
1413 struct nlm4_notify_wrapper notify;
1414 struct nlm4_testres_wrapper testres;
1415 struct nlm4_res_wrapper res;
1416 struct nlm4_shareres_wrapper shareres;
1417 };
1418
1419 static DEFINE_PER_CPU_ALIGNED(unsigned long,
1420 nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]);
1421
1422 const struct svc_version nlmsvc_version4 = {
1423 .vs_vers = 4,
1424 .vs_nproc = ARRAY_SIZE(nlm4svc_procedures),
1425 .vs_proc = nlm4svc_procedures,
1426 .vs_count = nlm4svc_call_counters,
1427 .vs_dispatch = nlmsvc_dispatch,
1428 .vs_xdrsize = sizeof(union nlm4svc_xdrstore),
1429 };
1430