Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / lockd / svc4proc.c
bloba1e30454eed2c010c1b56c010de977e136f450ba
1 /*
2 * linux/fs/lockd/svc4proc.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/types.h>
11 #include <linux/sched.h>
12 #include <linux/malloc.h>
13 #include <linux/in.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/nfsd/nfsd.h>
17 #include <linux/lockd/lockd.h>
18 #include <linux/lockd/share.h>
19 #include <linux/lockd/sm_inter.h>
22 #define NLMDBG_FACILITY NLMDBG_CLIENT
24 static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
25 static void nlm4svc_callback_exit(struct rpc_task *);
28 * Obtain client and file from arguments
30 static u32
31 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
32 struct nlm_host **hostp, struct nlm_file **filp)
34 struct nlm_host *host = NULL;
35 struct nlm_file *file = NULL;
36 struct nlm_lock *lock = &argp->lock;
37 u32 error = 0;
39 /* nfsd callbacks must have been installed for this procedure */
40 if (!nlmsvc_ops)
41 return nlm_lck_denied_nolocks;
43 /* Obtain handle for client host */
44 if (rqstp->rq_client == NULL) {
45 printk(KERN_NOTICE
46 "lockd: unauthenticated request from (%08x:%d)\n",
47 ntohl(rqstp->rq_addr.sin_addr.s_addr),
48 ntohs(rqstp->rq_addr.sin_port));
49 return nlm_lck_denied_nolocks;
52 /* Obtain host handle */
53 if (!(host = nlmsvc_lookup_host(rqstp))
54 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
55 goto no_locks;
56 *hostp = host;
58 /* Obtain file pointer. Not used by FREE_ALL call. */
59 if (filp != NULL) {
60 if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
61 goto no_locks;
62 *filp = file;
64 /* Set up the missing parts of the file_lock structure */
65 lock->fl.fl_file = &file->f_file;
66 lock->fl.fl_owner = (fl_owner_t) host;
69 return 0;
71 no_locks:
72 if (host)
73 nlm_release_host(host);
74 if (error)
75 return error;
76 return nlm_lck_denied_nolocks;
80 * NULL: Test for presence of service
82 static int
83 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
85 dprintk("lockd: NULL called\n");
86 return rpc_success;
90 * TEST: Check for conflicting lock
92 static int
93 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
94 struct nlm_res *resp)
96 struct nlm_host *host;
97 struct nlm_file *file;
99 dprintk("lockd: TEST4 called\n");
100 resp->cookie = argp->cookie;
102 /* Don't accept test requests during grace period */
103 if (nlmsvc_grace_period) {
104 resp->status = nlm_lck_denied_grace_period;
105 return rpc_success;
108 /* Obtain client and file */
109 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
110 return rpc_success;
112 /* Now check for conflicting locks */
113 resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
115 dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
116 nlm_release_host(host);
117 nlm_release_file(file);
118 return rpc_success;
121 static int
122 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
123 struct nlm_res *resp)
125 struct nlm_host *host;
126 struct nlm_file *file;
128 dprintk("lockd: LOCK called\n");
130 resp->cookie = argp->cookie;
132 /* Don't accept new lock requests during grace period */
133 if (nlmsvc_grace_period && !argp->reclaim) {
134 resp->status = nlm_lck_denied_grace_period;
135 return rpc_success;
138 /* Obtain client and file */
139 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
140 return rpc_success;
142 #if 0
143 /* If supplied state doesn't match current state, we assume it's
144 * an old request that time-warped somehow. Any error return would
145 * do in this case because it's irrelevant anyway.
147 * NB: We don't retrieve the remote host's state yet.
149 if (host->h_nsmstate && host->h_nsmstate != argp->state) {
150 resp->status = nlm_lck_denied_nolocks;
151 } else
152 #endif
154 /* Now try to lock the file */
155 resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
156 argp->block, &argp->cookie);
158 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
159 nlm_release_host(host);
160 nlm_release_file(file);
161 return rpc_success;
164 static int
165 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
166 struct nlm_res *resp)
168 struct nlm_host *host;
169 struct nlm_file *file;
171 dprintk("lockd: CANCEL called\n");
173 resp->cookie = argp->cookie;
175 /* Don't accept requests during grace period */
176 if (nlmsvc_grace_period) {
177 resp->status = nlm_lck_denied_grace_period;
178 return rpc_success;
181 /* Obtain client and file */
182 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
183 return rpc_success;
185 /* Try to cancel request. */
186 resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
188 dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
189 nlm_release_host(host);
190 nlm_release_file(file);
191 return rpc_success;
195 * UNLOCK: release a lock
197 static int
198 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
199 struct nlm_res *resp)
201 struct nlm_host *host;
202 struct nlm_file *file;
204 dprintk("lockd: UNLOCK called\n");
206 resp->cookie = argp->cookie;
208 /* Don't accept new lock requests during grace period */
209 if (nlmsvc_grace_period) {
210 resp->status = nlm_lck_denied_grace_period;
211 return rpc_success;
214 /* Obtain client and file */
215 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
216 return rpc_success;
218 /* Now try to remove the lock */
219 resp->status = nlmsvc_unlock(file, &argp->lock);
221 dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
222 nlm_release_host(host);
223 nlm_release_file(file);
224 return rpc_success;
228 * GRANTED: A server calls us to tell that a process' lock request
229 * was granted
231 static int
232 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
233 struct nlm_res *resp)
235 resp->cookie = argp->cookie;
237 dprintk("lockd: GRANTED called\n");
238 resp->status = nlmclnt_grant(&argp->lock);
239 dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
240 return rpc_success;
244 * `Async' versions of the above service routines. They aren't really,
245 * because we send the callback before the reply proper. I hope this
246 * doesn't break any clients.
248 static int
249 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
250 void *resp)
252 struct nlm_res res;
253 u32 stat;
255 dprintk("lockd: TEST_MSG called\n");
257 if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
258 stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
259 return stat;
262 static int
263 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
264 void *resp)
266 struct nlm_res res;
267 u32 stat;
269 dprintk("lockd: LOCK_MSG called\n");
271 if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
272 stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
273 return stat;
276 static int
277 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
278 void *resp)
280 struct nlm_res res;
281 u32 stat;
283 dprintk("lockd: CANCEL_MSG called\n");
285 if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
286 stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
287 return stat;
290 static int
291 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
292 void *resp)
294 struct nlm_res res;
295 u32 stat;
297 dprintk("lockd: UNLOCK_MSG called\n");
299 if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
300 stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
301 return stat;
304 static int
305 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
306 void *resp)
308 struct nlm_res res;
309 u32 stat;
311 dprintk("lockd: GRANTED_MSG called\n");
313 if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
314 stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
315 return stat;
319 * SHARE: create a DOS share or alter existing share.
321 static int
322 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
323 struct nlm_res *resp)
325 struct nlm_host *host;
326 struct nlm_file *file;
328 dprintk("lockd: SHARE called\n");
330 resp->cookie = argp->cookie;
332 /* Don't accept new lock requests during grace period */
333 if (nlmsvc_grace_period && !argp->reclaim) {
334 resp->status = nlm_lck_denied_grace_period;
335 return rpc_success;
338 /* Obtain client and file */
339 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
340 return rpc_success;
342 /* Now try to create the share */
343 resp->status = nlmsvc_share_file(host, file, argp);
345 dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
346 nlm_release_host(host);
347 nlm_release_file(file);
348 return rpc_success;
352 * UNSHARE: Release a DOS share.
354 static int
355 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
356 struct nlm_res *resp)
358 struct nlm_host *host;
359 struct nlm_file *file;
361 dprintk("lockd: UNSHARE called\n");
363 resp->cookie = argp->cookie;
365 /* Don't accept requests during grace period */
366 if (nlmsvc_grace_period) {
367 resp->status = nlm_lck_denied_grace_period;
368 return rpc_success;
371 /* Obtain client and file */
372 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
373 return rpc_success;
375 /* Now try to lock the file */
376 resp->status = nlmsvc_unshare_file(host, file, argp);
378 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
379 nlm_release_host(host);
380 nlm_release_file(file);
381 return rpc_success;
385 * NM_LOCK: Create an unmonitored lock
387 static int
388 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
389 struct nlm_res *resp)
391 dprintk("lockd: NM_LOCK called\n");
393 argp->monitor = 0; /* just clean the monitor flag */
394 return nlm4svc_proc_lock(rqstp, argp, resp);
398 * FREE_ALL: Release all locks and shares held by client
400 static int
401 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
402 void *resp)
404 struct nlm_host *host;
406 /* Obtain client */
407 if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
408 return rpc_success;
410 nlmsvc_free_host_resources(host);
411 nlm_release_host(host);
412 return rpc_success;
416 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
418 static int
419 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
420 void *resp)
422 struct sockaddr_in saddr = rqstp->rq_addr;
423 struct nlm_host *host;
425 dprintk("lockd: SM_NOTIFY called\n");
426 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
427 || ntohs(saddr.sin_port) >= 1024) {
428 printk(KERN_WARNING
429 "lockd: rejected NSM callback from %08x:%d\n",
430 ntohl(rqstp->rq_addr.sin_addr.s_addr),
431 ntohs(rqstp->rq_addr.sin_port));
432 return rpc_system_err;
435 /* Obtain the host pointer for this NFS server and try to
436 * reclaim all locks we hold on this server.
438 saddr.sin_addr.s_addr = argp->addr;
439 if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
440 nlmclnt_recovery(host, argp->state);
441 nlm_release_host(host);
444 /* If we run on an NFS server, delete all locks held by the client */
445 if (nlmsvc_ops != NULL) {
446 struct svc_client *clnt;
447 saddr.sin_addr.s_addr = argp->addr;
448 if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
449 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
450 nlmsvc_free_host_resources(host);
452 nlm_release_host(host);
455 return rpc_success;
459 * This is the generic lockd callback for async RPC calls
461 static u32
462 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
464 struct nlm_host *host;
465 struct nlm_rqst *call;
467 if (!(call = nlmclnt_alloc_call()))
468 return rpc_system_err;
470 host = nlmclnt_lookup_host(&rqstp->rq_addr,
471 rqstp->rq_prot, rqstp->rq_vers);
472 if (!host) {
473 kfree(call);
474 return rpc_system_err;
477 call->a_flags = RPC_TASK_ASYNC;
478 call->a_host = host;
479 memcpy(&call->a_args, resp, sizeof(*resp));
481 if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
482 goto error;
484 return rpc_success;
485 error:
486 kfree(call);
487 nlm_release_host(host);
488 return rpc_system_err;
491 static void
492 nlm4svc_callback_exit(struct rpc_task *task)
494 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
496 if (task->tk_status < 0) {
497 dprintk("lockd: %4d callback failed (errno = %d)\n",
498 task->tk_pid, -task->tk_status);
500 nlm_release_host(call->a_host);
501 kfree(call);
505 * NLM Server procedures.
508 #define nlm4svc_encode_norep nlm4svc_encode_void
509 #define nlm4svc_decode_norep nlm4svc_decode_void
510 #define nlm4svc_decode_testres nlm4svc_decode_void
511 #define nlm4svc_decode_lockres nlm4svc_decode_void
512 #define nlm4svc_decode_unlockres nlm4svc_decode_void
513 #define nlm4svc_decode_cancelres nlm4svc_decode_void
514 #define nlm4svc_decode_grantedres nlm4svc_decode_void
516 #define nlm4svc_proc_none nlm4svc_proc_null
517 #define nlm4svc_proc_test_res nlm4svc_proc_null
518 #define nlm4svc_proc_lock_res nlm4svc_proc_null
519 #define nlm4svc_proc_cancel_res nlm4svc_proc_null
520 #define nlm4svc_proc_unlock_res nlm4svc_proc_null
521 #define nlm4svc_proc_granted_res nlm4svc_proc_null
523 struct nlm_void { int dummy; };
525 #define PROC(name, xargt, xrest, argt, rest) \
526 { (svc_procfunc) nlm4svc_proc_##name, \
527 (kxdrproc_t) nlm4svc_decode_##xargt, \
528 (kxdrproc_t) nlm4svc_encode_##xrest, \
529 NULL, \
530 sizeof(struct nlm_##argt), \
531 sizeof(struct nlm_##rest), \
532 0, \
535 struct svc_procedure nlmsvc_procedures4[] = {
536 PROC(null, void, void, void, void),
537 PROC(test, testargs, testres, args, res),
538 PROC(lock, lockargs, res, args, res),
539 PROC(cancel, cancargs, res, args, res),
540 PROC(unlock, unlockargs, res, args, res),
541 PROC(granted, testargs, res, args, res),
542 PROC(test_msg, testargs, norep, args, void),
543 PROC(lock_msg, lockargs, norep, args, void),
544 PROC(cancel_msg, cancargs, norep, args, void),
545 PROC(unlock_msg, unlockargs, norep, args, void),
546 PROC(granted_msg, testargs, norep, args, void),
547 PROC(test_res, testres, norep, res, void),
548 PROC(lock_res, lockres, norep, res, void),
549 PROC(cancel_res, cancelres, norep, res, void),
550 PROC(unlock_res, unlockres, norep, res, void),
551 PROC(granted_res, grantedres, norep, res, void),
552 PROC(none, void, void, void, void),
553 PROC(none, void, void, void, void),
554 PROC(none, void, void, void, void),
555 PROC(none, void, void, void, void),
556 PROC(share, shareargs, shareres, args, res),
557 PROC(unshare, shareargs, shareres, args, res),
558 PROC(nm_lock, lockargs, res, args, res),
559 PROC(free_all, notify, void, args, void),
561 /* statd callback */
562 PROC(sm_notify, reboot, void, reboot, void),