Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / lockd / svcproc.c
blobb0cbd4a5097d7c9009b8ad193b570e0930bbd895
1 /*
2 * linux/fs/lockd/svcproc.c
4 * Lockd server procedures. We don't implement the NLM_*_RES
5 * procedures because we don't use the async procedures.
7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8 */
10 #include <linux/config.h>
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/malloc.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>
23 #define NLMDBG_FACILITY NLMDBG_CLIENT
25 static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
26 static void nlmsvc_callback_exit(struct rpc_task *);
28 #ifdef CONFIG_LOCKD_V4
29 static u32
30 cast_to_nlm(u32 status, u32 vers)
33 if (vers != 4){
34 switch(ntohl(status)){
35 case NLM_LCK_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 default:
42 status = NLM_LCK_DENIED_NOLOCKS;
46 return (status);
48 #define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
49 #else
50 #define cast_status(status) (status)
51 #endif
54 * Obtain client and file from arguments
56 static u32
57 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
58 struct nlm_host **hostp, struct nlm_file **filp)
60 struct nlm_host *host = NULL;
61 struct nlm_file *file = NULL;
62 struct nlm_lock *lock = &argp->lock;
63 u32 error;
65 /* nfsd callbacks must have been installed for this procedure */
66 if (!nlmsvc_ops)
67 return nlm_lck_denied_nolocks;
69 /* Obtain handle for client host */
70 if (rqstp->rq_client == NULL) {
71 printk(KERN_NOTICE
72 "lockd: unauthenticated request from (%08x:%d)\n",
73 ntohl(rqstp->rq_addr.sin_addr.s_addr),
74 ntohs(rqstp->rq_addr.sin_port));
75 return nlm_lck_denied_nolocks;
78 /* Obtain host handle */
79 if (!(host = nlmsvc_lookup_host(rqstp))
80 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
81 goto no_locks;
82 *hostp = host;
84 /* Obtain file pointer. Not used by FREE_ALL call. */
85 if (filp != NULL) {
86 if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
87 goto no_locks;
88 *filp = file;
90 /* Set up the missing parts of the file_lock structure */
91 lock->fl.fl_file = &file->f_file;
92 lock->fl.fl_owner = (fl_owner_t) host;
95 return 0;
97 no_locks:
98 if (host)
99 nlm_release_host(host);
100 return nlm_lck_denied_nolocks;
104 * NULL: Test for presence of service
106 static int
107 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
109 dprintk("lockd: NULL called\n");
110 return rpc_success;
114 * TEST: Check for conflicting lock
116 static int
117 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
118 struct nlm_res *resp)
120 struct nlm_host *host;
121 struct nlm_file *file;
123 dprintk("lockd: TEST called\n");
124 resp->cookie = argp->cookie;
126 /* Don't accept test requests during grace period */
127 if (nlmsvc_grace_period) {
128 resp->status = nlm_lck_denied_grace_period;
129 return rpc_success;
132 /* Obtain client and file */
133 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
134 return rpc_success;
136 /* Now check for conflicting locks */
137 resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
139 dprintk("lockd: TEST status %d vers %d\n",
140 ntohl(resp->status), rqstp->rq_vers);
141 nlm_release_host(host);
142 nlm_release_file(file);
143 return rpc_success;
146 static int
147 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
148 struct nlm_res *resp)
150 struct nlm_host *host;
151 struct nlm_file *file;
153 dprintk("lockd: LOCK called\n");
155 resp->cookie = argp->cookie;
157 /* Don't accept new lock requests during grace period */
158 if (nlmsvc_grace_period && !argp->reclaim) {
159 resp->status = nlm_lck_denied_grace_period;
160 return rpc_success;
163 /* Obtain client and file */
164 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
165 return rpc_success;
167 #if 0
168 /* If supplied state doesn't match current state, we assume it's
169 * an old request that time-warped somehow. Any error return would
170 * do in this case because it's irrelevant anyway.
172 * NB: We don't retrieve the remote host's state yet.
174 if (host->h_nsmstate && host->h_nsmstate != argp->state) {
175 resp->status = nlm_lck_denied_nolocks;
176 } else
177 #endif
179 /* Now try to lock the file */
180 resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
181 argp->block, &argp->cookie));
183 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
184 nlm_release_host(host);
185 nlm_release_file(file);
186 return rpc_success;
189 static int
190 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
191 struct nlm_res *resp)
193 struct nlm_host *host;
194 struct nlm_file *file;
196 dprintk("lockd: CANCEL called\n");
198 resp->cookie = argp->cookie;
200 /* Don't accept requests during grace period */
201 if (nlmsvc_grace_period) {
202 resp->status = nlm_lck_denied_grace_period;
203 return rpc_success;
206 /* Obtain client and file */
207 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
208 return rpc_success;
210 /* Try to cancel request. */
211 resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
213 dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
214 nlm_release_host(host);
215 nlm_release_file(file);
216 return rpc_success;
220 * UNLOCK: release a lock
222 static int
223 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
224 struct nlm_res *resp)
226 struct nlm_host *host;
227 struct nlm_file *file;
229 dprintk("lockd: UNLOCK called\n");
231 resp->cookie = argp->cookie;
233 /* Don't accept new lock requests during grace period */
234 if (nlmsvc_grace_period) {
235 resp->status = nlm_lck_denied_grace_period;
236 return rpc_success;
239 /* Obtain client and file */
240 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
241 return rpc_success;
243 /* Now try to remove the lock */
244 resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
246 dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
247 nlm_release_host(host);
248 nlm_release_file(file);
249 return rpc_success;
253 * GRANTED: A server calls us to tell that a process' lock request
254 * was granted
256 static int
257 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
258 struct nlm_res *resp)
260 resp->cookie = argp->cookie;
262 dprintk("lockd: GRANTED called\n");
263 resp->status = nlmclnt_grant(&argp->lock);
264 dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
265 return rpc_success;
269 * `Async' versions of the above service routines. They aren't really,
270 * because we send the callback before the reply proper. I hope this
271 * doesn't break any clients.
273 static int
274 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
275 void *resp)
277 struct nlm_res res;
278 u32 stat;
280 dprintk("lockd: TEST_MSG called\n");
282 if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0)
283 stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res);
284 return stat;
287 static int
288 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
289 void *resp)
291 struct nlm_res res;
292 u32 stat;
294 dprintk("lockd: LOCK_MSG called\n");
296 if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0)
297 stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res);
298 return stat;
301 static int
302 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
303 void *resp)
305 struct nlm_res res;
306 u32 stat;
308 dprintk("lockd: CANCEL_MSG called\n");
310 if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0)
311 stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
312 return stat;
315 static int
316 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
317 void *resp)
319 struct nlm_res res;
320 u32 stat;
322 dprintk("lockd: UNLOCK_MSG called\n");
324 if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0)
325 stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
326 return stat;
329 static int
330 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
331 void *resp)
333 struct nlm_res res;
334 u32 stat;
336 dprintk("lockd: GRANTED_MSG called\n");
338 if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0)
339 stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
340 return stat;
344 * SHARE: create a DOS share or alter existing share.
346 static int
347 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
348 struct nlm_res *resp)
350 struct nlm_host *host;
351 struct nlm_file *file;
353 dprintk("lockd: SHARE called\n");
355 resp->cookie = argp->cookie;
357 /* Don't accept new lock requests during grace period */
358 if (nlmsvc_grace_period && !argp->reclaim) {
359 resp->status = nlm_lck_denied_grace_period;
360 return rpc_success;
363 /* Obtain client and file */
364 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
365 return rpc_success;
367 /* Now try to create the share */
368 resp->status = cast_status(nlmsvc_share_file(host, file, argp));
370 dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
371 nlm_release_host(host);
372 nlm_release_file(file);
373 return rpc_success;
377 * UNSHARE: Release a DOS share.
379 static int
380 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
381 struct nlm_res *resp)
383 struct nlm_host *host;
384 struct nlm_file *file;
386 dprintk("lockd: UNSHARE called\n");
388 resp->cookie = argp->cookie;
390 /* Don't accept requests during grace period */
391 if (nlmsvc_grace_period) {
392 resp->status = nlm_lck_denied_grace_period;
393 return rpc_success;
396 /* Obtain client and file */
397 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
398 return rpc_success;
400 /* Now try to unshare the file */
401 resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
403 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
404 nlm_release_host(host);
405 nlm_release_file(file);
406 return rpc_success;
410 * NM_LOCK: Create an unmonitored lock
412 static int
413 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
414 struct nlm_res *resp)
416 dprintk("lockd: NM_LOCK called\n");
418 argp->monitor = 0; /* just clean the monitor flag */
419 return nlmsvc_proc_lock(rqstp, argp, resp);
423 * FREE_ALL: Release all locks and shares held by client
425 static int
426 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
427 void *resp)
429 struct nlm_host *host;
431 /* Obtain client */
432 if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL))
433 return rpc_success;
435 nlmsvc_free_host_resources(host);
436 nlm_release_host(host);
437 return rpc_success;
441 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
443 static int
444 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
445 void *resp)
447 struct sockaddr_in saddr = rqstp->rq_addr;
448 struct nlm_host *host;
450 dprintk("lockd: SM_NOTIFY called\n");
451 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
452 || ntohs(saddr.sin_port) >= 1024) {
453 printk(KERN_WARNING
454 "lockd: rejected NSM callback from %08x:%d\n",
455 ntohl(rqstp->rq_addr.sin_addr.s_addr),
456 ntohs(rqstp->rq_addr.sin_port));
457 return rpc_system_err;
460 /* Obtain the host pointer for this NFS server and try to
461 * reclaim all locks we hold on this server.
463 saddr.sin_addr.s_addr = argp->addr;
464 if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
465 nlmclnt_recovery(host, argp->state);
466 nlm_release_host(host);
469 /* If we run on an NFS server, delete all locks held by the client */
470 if (nlmsvc_ops != NULL) {
471 struct svc_client *clnt;
472 saddr.sin_addr.s_addr = argp->addr;
473 if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
474 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
475 nlmsvc_free_host_resources(host);
477 nlm_release_host(host);
480 return rpc_success;
484 * This is the generic lockd callback for async RPC calls
486 static u32
487 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
489 struct nlm_host *host;
490 struct nlm_rqst *call;
492 if (!(call = nlmclnt_alloc_call()))
493 return rpc_system_err;
495 host = nlmclnt_lookup_host(&rqstp->rq_addr,
496 rqstp->rq_prot, rqstp->rq_vers);
497 if (!host) {
498 kfree(call);
499 return rpc_system_err;
502 call->a_flags = RPC_TASK_ASYNC;
503 call->a_host = host;
504 memcpy(&call->a_args, resp, sizeof(*resp));
506 if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
507 goto error;
509 return rpc_success;
510 error:
511 nlm_release_host(host);
512 kfree(call);
513 return rpc_system_err;
516 static void
517 nlmsvc_callback_exit(struct rpc_task *task)
519 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
521 if (task->tk_status < 0) {
522 dprintk("lockd: %4d callback failed (errno = %d)\n",
523 task->tk_pid, -task->tk_status);
525 nlm_release_host(call->a_host);
526 kfree(call);
530 * NLM Server procedures.
533 #define nlmsvc_encode_norep nlmsvc_encode_void
534 #define nlmsvc_decode_norep nlmsvc_decode_void
535 #define nlmsvc_decode_testres nlmsvc_decode_void
536 #define nlmsvc_decode_lockres nlmsvc_decode_void
537 #define nlmsvc_decode_unlockres nlmsvc_decode_void
538 #define nlmsvc_decode_cancelres nlmsvc_decode_void
539 #define nlmsvc_decode_grantedres nlmsvc_decode_void
541 #define nlmsvc_proc_none nlmsvc_proc_null
542 #define nlmsvc_proc_test_res nlmsvc_proc_null
543 #define nlmsvc_proc_lock_res nlmsvc_proc_null
544 #define nlmsvc_proc_cancel_res nlmsvc_proc_null
545 #define nlmsvc_proc_unlock_res nlmsvc_proc_null
546 #define nlmsvc_proc_granted_res nlmsvc_proc_null
548 struct nlm_void { int dummy; };
550 #define PROC(name, xargt, xrest, argt, rest) \
551 { (svc_procfunc) nlmsvc_proc_##name, \
552 (kxdrproc_t) nlmsvc_decode_##xargt, \
553 (kxdrproc_t) nlmsvc_encode_##xrest, \
554 NULL, \
555 sizeof(struct nlm_##argt), \
556 sizeof(struct nlm_##rest), \
557 0, \
560 struct svc_procedure nlmsvc_procedures[] = {
561 PROC(null, void, void, void, void),
562 PROC(test, testargs, testres, args, res),
563 PROC(lock, lockargs, res, args, res),
564 PROC(cancel, cancargs, res, args, res),
565 PROC(unlock, unlockargs, res, args, res),
566 PROC(granted, testargs, res, args, res),
567 PROC(test_msg, testargs, norep, args, void),
568 PROC(lock_msg, lockargs, norep, args, void),
569 PROC(cancel_msg, cancargs, norep, args, void),
570 PROC(unlock_msg, unlockargs, norep, args, void),
571 PROC(granted_msg, testargs, norep, args, void),
572 PROC(test_res, testres, norep, res, void),
573 PROC(lock_res, lockres, norep, res, void),
574 PROC(cancel_res, cancelres, norep, res, void),
575 PROC(unlock_res, unlockres, norep, res, void),
576 PROC(granted_res, grantedres, norep, res, void),
577 PROC(none, void, void, void, void),
578 PROC(none, void, void, void, void),
579 PROC(none, void, void, void, void),
580 PROC(none, void, void, void, void),
581 PROC(share, shareargs, shareres, args, res),
582 PROC(unshare, shareargs, shareres, args, res),
583 PROC(nm_lock, lockargs, res, args, res),
584 PROC(free_all, notify, void, args, void),
586 /* statd callback */
587 PROC(sm_notify, reboot, void, reboot, void),