1 /*
2 * linux/fs/lockd/svcproc.c
3 *
4 * Lockd server procedures. We don't implement the NLM_*_RES
5 * procedures because we don't use the async procedures.
6 *
7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 */
9
10 #include <linux/config.h>
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/slab.h>
14 #include <linux/in.h>
15 #include <linux/sunrpc/svc.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/nfsd/nfsd.h>
18 #include <linux/lockd/lockd.h>
19 #include <linux/lockd/share.h>
20 #include <linux/lockd/sm_inter.h>
21
22
23 #define NLMDBG_FACILITY NLMDBG_CLIENT
24
25 static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
26 static void nlmsvc_callback_exit(struct rpc_task *);
27
28 #ifdef CONFIG_LOCKD_V4
29 static u32
cast_to_nlm(u32 status,u32 vers)30 cast_to_nlm(u32 status, u32 vers)
31 {
32 /* Note: status is assumed to be in network byte order !!! */
33 if (vers != 4){
34 switch (status) {
35 case nlm_granted:
36 case nlm_lck_denied:
37 case nlm_lck_denied_nolocks:
38 case nlm_lck_blocked:
39 case nlm_lck_denied_grace_period:
40 break;
41 case nlm4_deadlock:
42 status = nlm_lck_denied;
43 break;
44 default:
45 status = nlm_lck_denied_nolocks;
46 }
47 }
48
49 return (status);
50 }
51 #define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
52 #else
53 #define cast_status(status) (status)
54 #endif
55
56 /*
57 * Obtain client and file from arguments
58 */
59 static u32
nlmsvc_retrieve_args(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_host ** hostp,struct nlm_file ** filp)60 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
61 struct nlm_host **hostp, struct nlm_file **filp)
62 {
63 struct nlm_host *host = NULL;
64 struct nlm_file *file = NULL;
65 struct nlm_lock *lock = &argp->lock;
66 u32 error;
67
68 /* nfsd callbacks must have been installed for this procedure */
69 if (!nlmsvc_ops)
70 return nlm_lck_denied_nolocks;
71
72 /* Obtain handle for client host */
73 if (rqstp->rq_client == NULL) {
74 printk(KERN_NOTICE
75 "lockd: unauthenticated request from (%08x:%d)\n",
76 ntohl(rqstp->rq_addr.sin_addr.s_addr),
77 ntohs(rqstp->rq_addr.sin_port));
78 return nlm_lck_denied_nolocks;
79 }
80
81 /* Obtain host handle */
82 if (!(host = nlmsvc_lookup_host(rqstp))
83 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
84 goto no_locks;
85 *hostp = host;
86
87 /* Obtain file pointer. Not used by FREE_ALL call. */
88 if (filp != NULL) {
89 if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
90 goto no_locks;
91 *filp = file;
92
93 /* Set up the missing parts of the file_lock structure */
94 lock->fl.fl_file = &file->f_file;
95 lock->fl.fl_owner = (fl_owner_t) host;
96 }
97
98 return 0;
99
100 no_locks:
101 if (host)
102 nlm_release_host(host);
103 return nlm_lck_denied_nolocks;
104 }
105
106 /*
107 * NULL: Test for presence of service
108 */
109 static int
nlmsvc_proc_null(struct svc_rqst * rqstp,void * argp,void * resp)110 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
111 {
112 dprintk("lockd: NULL called\n");
113 return rpc_success;
114 }
115
116 /*
117 * TEST: Check for conflicting lock
118 */
119 static int
nlmsvc_proc_test(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)120 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
121 struct nlm_res *resp)
122 {
123 struct nlm_host *host;
124 struct nlm_file *file;
125
126 dprintk("lockd: TEST called\n");
127 resp->cookie = argp->cookie;
128
129 /* Don't accept test requests during grace period */
130 if (nlmsvc_grace_period) {
131 resp->status = nlm_lck_denied_grace_period;
132 return rpc_success;
133 }
134
135 /* Obtain client and file */
136 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
137 return rpc_success;
138
139 /* Now check for conflicting locks */
140 resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
141
142 dprintk("lockd: TEST status %d vers %d\n",
143 ntohl(resp->status), rqstp->rq_vers);
144 nlm_release_host(host);
145 nlm_release_file(file);
146 return rpc_success;
147 }
148
149 static int
nlmsvc_proc_lock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)150 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
151 struct nlm_res *resp)
152 {
153 struct nlm_host *host;
154 struct nlm_file *file;
155
156 dprintk("lockd: LOCK called\n");
157
158 resp->cookie = argp->cookie;
159
160 /* Don't accept new lock requests during grace period */
161 if (nlmsvc_grace_period && !argp->reclaim) {
162 resp->status = nlm_lck_denied_grace_period;
163 return rpc_success;
164 }
165
166 /* Obtain client and file */
167 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
168 return rpc_success;
169
170 #if 0
171 /* If supplied state doesn't match current state, we assume it's
172 * an old request that time-warped somehow. Any error return would
173 * do in this case because it's irrelevant anyway.
174 *
175 * NB: We don't retrieve the remote host's state yet.
176 */
177 if (host->h_nsmstate && host->h_nsmstate != argp->state) {
178 resp->status = nlm_lck_denied_nolocks;
179 } else
180 #endif
181
182 /* Now try to lock the file */
183 resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
184 argp->block, &argp->cookie));
185
186 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
187 nlm_release_host(host);
188 nlm_release_file(file);
189 return rpc_success;
190 }
191
192 static int
nlmsvc_proc_cancel(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)193 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
194 struct nlm_res *resp)
195 {
196 struct nlm_host *host;
197 struct nlm_file *file;
198
199 dprintk("lockd: CANCEL called\n");
200
201 resp->cookie = argp->cookie;
202
203 /* Don't accept requests during grace period */
204 if (nlmsvc_grace_period) {
205 resp->status = nlm_lck_denied_grace_period;
206 return rpc_success;
207 }
208
209 /* Obtain client and file */
210 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
211 return rpc_success;
212
213 /* Try to cancel request. */
214 resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
215
216 dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
217 nlm_release_host(host);
218 nlm_release_file(file);
219 return rpc_success;
220 }
221
222 /*
223 * UNLOCK: release a lock
224 */
225 static int
nlmsvc_proc_unlock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)226 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
227 struct nlm_res *resp)
228 {
229 struct nlm_host *host;
230 struct nlm_file *file;
231
232 dprintk("lockd: UNLOCK called\n");
233
234 resp->cookie = argp->cookie;
235
236 /* Don't accept new lock requests during grace period */
237 if (nlmsvc_grace_period) {
238 resp->status = nlm_lck_denied_grace_period;
239 return rpc_success;
240 }
241
242 /* Obtain client and file */
243 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
244 return rpc_success;
245
246 /* Now try to remove the lock */
247 resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
248
249 dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
250 nlm_release_host(host);
251 nlm_release_file(file);
252 return rpc_success;
253 }
254
255 /*
256 * GRANTED: A server calls us to tell that a process' lock request
257 * was granted
258 */
259 static int
nlmsvc_proc_granted(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)260 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
261 struct nlm_res *resp)
262 {
263 resp->cookie = argp->cookie;
264
265 dprintk("lockd: GRANTED called\n");
266 resp->status = nlmclnt_grant(&argp->lock);
267 dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
268 return rpc_success;
269 }
270
271 /*
272 * `Async' versions of the above service routines. They aren't really,
273 * because we send the callback before the reply proper. I hope this
274 * doesn't break any clients.
275 */
276 static int
nlmsvc_proc_test_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)277 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
278 void *resp)
279 {
280 struct nlm_res res;
281 u32 stat;
282
283 dprintk("lockd: TEST_MSG called\n");
284
285 memset(&res, 0, sizeof(res));
286
287 if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0)
288 stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res);
289 return stat;
290 }
291
292 static int
nlmsvc_proc_lock_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)293 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
294 void *resp)
295 {
296 struct nlm_res res;
297 u32 stat;
298
299 dprintk("lockd: LOCK_MSG called\n");
300
301 if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0)
302 stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res);
303 return stat;
304 }
305
306 static int
nlmsvc_proc_cancel_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)307 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
308 void *resp)
309 {
310 struct nlm_res res;
311 u32 stat;
312
313 dprintk("lockd: CANCEL_MSG called\n");
314
315 if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0)
316 stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
317 return stat;
318 }
319
320 static int
nlmsvc_proc_unlock_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)321 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
322 void *resp)
323 {
324 struct nlm_res res;
325 u32 stat;
326
327 dprintk("lockd: UNLOCK_MSG called\n");
328
329 if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0)
330 stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
331 return stat;
332 }
333
334 static int
nlmsvc_proc_granted_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)335 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
336 void *resp)
337 {
338 struct nlm_res res;
339 u32 stat;
340
341 dprintk("lockd: GRANTED_MSG called\n");
342
343 if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0)
344 stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
345 return stat;
346 }
347
348 /*
349 * SHARE: create a DOS share or alter existing share.
350 */
351 static int
nlmsvc_proc_share(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)352 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
353 struct nlm_res *resp)
354 {
355 struct nlm_host *host;
356 struct nlm_file *file;
357
358 dprintk("lockd: SHARE called\n");
359
360 resp->cookie = argp->cookie;
361
362 /* Don't accept new lock requests during grace period */
363 if (nlmsvc_grace_period && !argp->reclaim) {
364 resp->status = nlm_lck_denied_grace_period;
365 return rpc_success;
366 }
367
368 /* Obtain client and file */
369 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
370 return rpc_success;
371
372 /* Now try to create the share */
373 resp->status = cast_status(nlmsvc_share_file(host, file, argp));
374
375 dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
376 nlm_release_host(host);
377 nlm_release_file(file);
378 return rpc_success;
379 }
380
381 /*
382 * UNSHARE: Release a DOS share.
383 */
384 static int
nlmsvc_proc_unshare(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)385 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
386 struct nlm_res *resp)
387 {
388 struct nlm_host *host;
389 struct nlm_file *file;
390
391 dprintk("lockd: UNSHARE called\n");
392
393 resp->cookie = argp->cookie;
394
395 /* Don't accept requests during grace period */
396 if (nlmsvc_grace_period) {
397 resp->status = nlm_lck_denied_grace_period;
398 return rpc_success;
399 }
400
401 /* Obtain client and file */
402 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
403 return rpc_success;
404
405 /* Now try to unshare the file */
406 resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
407
408 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
409 nlm_release_host(host);
410 nlm_release_file(file);
411 return rpc_success;
412 }
413
414 /*
415 * NM_LOCK: Create an unmonitored lock
416 */
417 static int
nlmsvc_proc_nm_lock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)418 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
419 struct nlm_res *resp)
420 {
421 dprintk("lockd: NM_LOCK called\n");
422
423 argp->monitor = 0; /* just clean the monitor flag */
424 return nlmsvc_proc_lock(rqstp, argp, resp);
425 }
426
427 /*
428 * FREE_ALL: Release all locks and shares held by client
429 */
430 static int
nlmsvc_proc_free_all(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)431 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
432 void *resp)
433 {
434 struct nlm_host *host;
435
436 /* Obtain client */
437 if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL))
438 return rpc_success;
439
440 nlmsvc_free_host_resources(host);
441 nlm_release_host(host);
442 return rpc_success;
443 }
444
445 /*
446 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
447 */
448 static int
nlmsvc_proc_sm_notify(struct svc_rqst * rqstp,struct nlm_reboot * argp,void * resp)449 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
450 void *resp)
451 {
452 struct sockaddr_in saddr = rqstp->rq_addr;
453 int vers = rqstp->rq_vers;
454 int prot = rqstp->rq_prot;
455 struct nlm_host *host;
456
457 dprintk("lockd: SM_NOTIFY called\n");
458 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
459 || ntohs(saddr.sin_port) >= 1024) {
460 printk(KERN_WARNING
461 "lockd: rejected NSM callback from %08x:%d\n",
462 ntohl(rqstp->rq_addr.sin_addr.s_addr),
463 ntohs(rqstp->rq_addr.sin_port));
464 return rpc_system_err;
465 }
466
467 /* Obtain the host pointer for this NFS server and try to
468 * reclaim all locks we hold on this server.
469 */
470 saddr.sin_addr.s_addr = argp->addr;
471 if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
472 nlmclnt_recovery(host, argp->state);
473 nlm_release_host(host);
474 }
475
476 /* If we run on an NFS server, delete all locks held by the client */
477 if (nlmsvc_ops != NULL) {
478 struct svc_client *clnt;
479 saddr.sin_addr.s_addr = argp->addr;
480 if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
481 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
482 nlmsvc_free_host_resources(host);
483 }
484 nlm_release_host(host);
485 }
486
487 return rpc_success;
488 }
489
490 /*
491 * client sent a GRANTED_RES, let's remove the associated block
492 */
493 static int
nlmsvc_proc_granted_res(struct svc_rqst * rqstp,struct nlm_res * argp,void * resp)494 nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
495 void *resp)
496 {
497 if (!nlmsvc_ops)
498 return rpc_success;
499
500 dprintk("lockd: GRANTED_RES called\n");
501
502 nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
503 return rpc_success;
504 }
505
506 /*
507 * This is the generic lockd callback for async RPC calls
508 */
509 static u32
nlmsvc_callback(struct svc_rqst * rqstp,u32 proc,struct nlm_res * resp)510 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
511 {
512 struct nlm_host *host;
513 struct nlm_rqst *call;
514
515 if (!(call = nlmclnt_alloc_call()))
516 return rpc_system_err;
517
518 host = nlmclnt_lookup_host(&rqstp->rq_addr,
519 rqstp->rq_prot, rqstp->rq_vers);
520 if (!host) {
521 kfree(call);
522 return rpc_system_err;
523 }
524
525 call->a_flags = RPC_TASK_ASYNC;
526 call->a_host = host;
527 memcpy(&call->a_args, resp, sizeof(*resp));
528
529 if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
530 goto error;
531
532 return rpc_success;
533 error:
534 nlm_release_host(host);
535 kfree(call);
536 return rpc_system_err;
537 }
538
539 static void
nlmsvc_callback_exit(struct rpc_task * task)540 nlmsvc_callback_exit(struct rpc_task *task)
541 {
542 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
543
544 if (task->tk_status < 0) {
545 dprintk("lockd: %4d callback failed (errno = %d)\n",
546 task->tk_pid, -task->tk_status);
547 }
548 nlm_release_host(call->a_host);
549 kfree(call);
550 }
551
552 /*
553 * NLM Server procedures.
554 */
555
556 #define nlmsvc_encode_norep nlmsvc_encode_void
557 #define nlmsvc_decode_norep nlmsvc_decode_void
558 #define nlmsvc_decode_testres nlmsvc_decode_void
559 #define nlmsvc_decode_lockres nlmsvc_decode_void
560 #define nlmsvc_decode_unlockres nlmsvc_decode_void
561 #define nlmsvc_decode_cancelres nlmsvc_decode_void
562 #define nlmsvc_decode_grantedres nlmsvc_decode_void
563
564 #define nlmsvc_proc_none nlmsvc_proc_null
565 #define nlmsvc_proc_test_res nlmsvc_proc_null
566 #define nlmsvc_proc_lock_res nlmsvc_proc_null
567 #define nlmsvc_proc_cancel_res nlmsvc_proc_null
568 #define nlmsvc_proc_unlock_res nlmsvc_proc_null
569
570 struct nlm_void { int dummy; };
571
572 #define PROC(name, xargt, xrest, argt, rest, respsize) \
573 { (svc_procfunc) nlmsvc_proc_##name, \
574 (kxdrproc_t) nlmsvc_decode_##xargt, \
575 (kxdrproc_t) nlmsvc_encode_##xrest, \
576 NULL, \
577 sizeof(struct nlm_##argt), \
578 sizeof(struct nlm_##rest), \
579 0, \
580 0, \
581 respsize, \
582 }
583
584 #define Ck (1+8) /* cookie */
585 #define St 1 /* status */
586 #define No (1+1024/4) /* Net Obj */
587 #define Rg 2 /* range - offset + size */
588
589 struct svc_procedure nlmsvc_procedures[] = {
590 PROC(null, void, void, void, void, 1),
591 PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
592 PROC(lock, lockargs, res, args, res, Ck+St),
593 PROC(cancel, cancargs, res, args, res, Ck+St),
594 PROC(unlock, unlockargs, res, args, res, Ck+St),
595 PROC(granted, testargs, res, args, res, Ck+St),
596 PROC(test_msg, testargs, norep, args, void, 1),
597 PROC(lock_msg, lockargs, norep, args, void, 1),
598 PROC(cancel_msg, cancargs, norep, args, void, 1),
599 PROC(unlock_msg, unlockargs, norep, args, void, 1),
600 PROC(granted_msg, testargs, norep, args, void, 1),
601 PROC(test_res, testres, norep, res, void, 1),
602 PROC(lock_res, lockres, norep, res, void, 1),
603 PROC(cancel_res, cancelres, norep, res, void, 1),
604 PROC(unlock_res, unlockres, norep, res, void, 1),
605 PROC(granted_res, res, norep, res, void, 1),
606 /* statd callback */
607 PROC(sm_notify, reboot, void, reboot, void, 1),
608 PROC(none, void, void, void, void, 1),
609 PROC(none, void, void, void, void, 1),
610 PROC(none, void, void, void, void, 1),
611 PROC(share, shareargs, shareres, args, res, Ck+St+1),
612 PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
613 PROC(nm_lock, lockargs, res, args, res, Ck+St),
614 PROC(free_all, notify, void, args, void, 0),
615
616 };
617