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