Import 2.3.26pre2
[davej-history.git] / fs / lockd / svcproc.c
blob0e59754f351d6eca49ac7064bc4703c3845bdd33
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/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 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
25 static void nlmsvc_callback_exit(struct rpc_task *);
28 * Obtain client and file from arguments
30 static u32
31 nlmsvc_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;
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 (%08lx:%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 return nlm_lck_denied_nolocks;
78 * NULL: Test for presence of service
80 static int
81 nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
83 dprintk("lockd: NULL called\n");
84 return rpc_success;
88 * TEST: Check for conflicting lock
90 static int
91 nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
92 struct nlm_res *resp)
94 struct nlm_host *host;
95 struct nlm_file *file;
97 dprintk("lockd: TEST called\n");
98 resp->cookie = argp->cookie;
100 /* Don't accept test requests during grace period */
101 if (nlmsvc_grace_period) {
102 resp->status = nlm_lck_denied_grace_period;
103 return rpc_success;
106 /* Obtain client and file */
107 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
108 return rpc_success;
110 /* Now check for conflicting locks */
111 resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
113 dprintk("lockd: TEST status %ld\n", ntohl(resp->status));
114 nlm_release_host(host);
115 nlm_release_file(file);
116 return rpc_success;
119 static int
120 nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
121 struct nlm_res *resp)
123 struct nlm_host *host;
124 struct nlm_file *file;
126 dprintk("lockd: LOCK called\n");
128 resp->cookie = argp->cookie;
130 /* Don't accept new lock requests during grace period */
131 if (nlmsvc_grace_period && !argp->reclaim) {
132 resp->status = nlm_lck_denied_grace_period;
133 return rpc_success;
136 /* Obtain client and file */
137 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
138 return rpc_success;
140 #if 0
141 /* If supplied state doesn't match current state, we assume it's
142 * an old request that time-warped somehow. Any error return would
143 * do in this case because it's irrelevant anyway.
145 * NB: We don't retrieve the remote host's state yet.
147 if (host->h_nsmstate && host->h_nsmstate != argp->state) {
148 resp->status = nlm_lck_denied_nolocks;
149 } else
150 #endif
152 /* Now try to lock the file */
153 resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
154 argp->block, &argp->cookie);
156 dprintk("lockd: LOCK status %ld\n", ntohl(resp->status));
157 nlm_release_host(host);
158 nlm_release_file(file);
159 return rpc_success;
162 static int
163 nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
164 struct nlm_res *resp)
166 struct nlm_host *host;
167 struct nlm_file *file;
169 dprintk("lockd: CANCEL called\n");
171 resp->cookie = argp->cookie;
173 /* Don't accept requests during grace period */
174 if (nlmsvc_grace_period) {
175 resp->status = nlm_lck_denied_grace_period;
176 return rpc_success;
179 /* Obtain client and file */
180 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
181 return rpc_success;
183 /* Try to cancel request. */
184 resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
186 dprintk("lockd: CANCEL status %ld\n", ntohl(resp->status));
187 nlm_release_host(host);
188 nlm_release_file(file);
189 return rpc_success;
193 * UNLOCK: release a lock
195 static int
196 nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
197 struct nlm_res *resp)
199 struct nlm_host *host;
200 struct nlm_file *file;
202 dprintk("lockd: UNLOCK called\n");
204 resp->cookie = argp->cookie;
206 /* Don't accept new lock requests during grace period */
207 if (nlmsvc_grace_period) {
208 resp->status = nlm_lck_denied_grace_period;
209 return rpc_success;
212 /* Obtain client and file */
213 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
214 return rpc_success;
216 /* Now try to remove the lock */
217 resp->status = nlmsvc_unlock(file, &argp->lock);
219 dprintk("lockd: UNLOCK status %ld\n", ntohl(resp->status));
220 nlm_release_host(host);
221 nlm_release_file(file);
222 return rpc_success;
226 * GRANTED: A server calls us to tell that a process' lock request
227 * was granted
229 static int
230 nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
231 struct nlm_res *resp)
233 resp->cookie = argp->cookie;
235 dprintk("lockd: GRANTED called\n");
236 resp->status = nlmclnt_grant(&argp->lock);
237 dprintk("lockd: GRANTED status %ld\n", ntohl(resp->status));
238 return rpc_success;
242 * `Async' versions of the above service routines. They aren't really,
243 * because we send the callback before the reply proper. I hope this
244 * doesn't break any clients.
246 static int
247 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
248 void *resp)
250 struct nlm_res res;
251 u32 stat;
253 dprintk("lockd: TEST_MSG called\n");
255 if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0)
256 stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res);
257 return stat;
260 static int
261 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
262 void *resp)
264 struct nlm_res res;
265 u32 stat;
267 dprintk("lockd: LOCK_MSG called\n");
269 if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0)
270 stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res);
271 return stat;
274 static int
275 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
276 void *resp)
278 struct nlm_res res;
279 u32 stat;
281 dprintk("lockd: CANCEL_MSG called\n");
283 if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0)
284 stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
285 return stat;
288 static int
289 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
290 void *resp)
292 struct nlm_res res;
293 u32 stat;
295 dprintk("lockd: UNLOCK_MSG called\n");
297 if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0)
298 stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
299 return stat;
302 static int
303 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
304 void *resp)
306 struct nlm_res res;
307 u32 stat;
309 dprintk("lockd: GRANTED_MSG called\n");
311 if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0)
312 stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
313 return stat;
317 * SHARE: create a DOS share or alter existing share.
319 static int
320 nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
321 struct nlm_res *resp)
323 struct nlm_host *host;
324 struct nlm_file *file;
326 dprintk("lockd: SHARE called\n");
328 resp->cookie = argp->cookie;
330 /* Don't accept new lock requests during grace period */
331 if (nlmsvc_grace_period && !argp->reclaim) {
332 resp->status = nlm_lck_denied_grace_period;
333 return rpc_success;
336 /* Obtain client and file */
337 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
338 return rpc_success;
340 /* Now try to create the share */
341 resp->status = nlmsvc_share_file(host, file, argp);
343 dprintk("lockd: SHARE status %ld\n", ntohl(resp->status));
344 nlm_release_host(host);
345 nlm_release_file(file);
346 return rpc_success;
350 * UNSHARE: Release a DOS share.
352 static int
353 nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
354 struct nlm_res *resp)
356 struct nlm_host *host;
357 struct nlm_file *file;
359 dprintk("lockd: UNSHARE called\n");
361 resp->cookie = argp->cookie;
363 /* Don't accept requests during grace period */
364 if (nlmsvc_grace_period) {
365 resp->status = nlm_lck_denied_grace_period;
366 return rpc_success;
369 /* Obtain client and file */
370 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
371 return rpc_success;
373 /* Now try to lock the file */
374 resp->status = nlmsvc_unshare_file(host, file, argp);
376 dprintk("lockd: UNSHARE status %ld\n", ntohl(resp->status));
377 nlm_release_host(host);
378 nlm_release_file(file);
379 return rpc_success;
383 * NM_LOCK: Create an unmonitored lock
385 static int
386 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
387 struct nlm_res *resp)
389 dprintk("lockd: NM_LOCK called\n");
391 argp->monitor = 0; /* just clean the monitor flag */
392 return nlmsvc_proc_lock(rqstp, argp, resp);
396 * FREE_ALL: Release all locks and shares held by client
398 static int
399 nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
400 void *resp)
402 struct nlm_host *host;
404 /* Obtain client */
405 if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL))
406 return rpc_success;
408 nlmsvc_free_host_resources(host);
409 nlm_release_host(host);
410 return rpc_success;
414 * SM_NOTIFY: private callback from statd (not part of official NLM proto)
416 static int
417 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
418 void *resp)
420 struct sockaddr_in saddr = rqstp->rq_addr;
421 struct nlm_host *host;
423 dprintk("lockd: SM_NOTIFY called\n");
424 if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
425 || ntohs(saddr.sin_port) >= 1024) {
426 printk(KERN_WARNING
427 "lockd: rejected NSM callback from %08lx:%d\n",
428 ntohl(rqstp->rq_addr.sin_addr.s_addr),
429 ntohs(rqstp->rq_addr.sin_port));
430 return rpc_system_err;
433 /* Obtain the host pointer for this NFS server and try to
434 * reclaim all locks we hold on this server.
436 saddr.sin_addr.s_addr = argp->addr;
437 if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
438 nlmclnt_recovery(host, argp->state);
439 nlm_release_host(host);
442 /* If we run on an NFS server, delete all locks held by the client */
443 if (nlmsvc_ops != NULL) {
444 struct svc_client *clnt;
445 saddr.sin_addr.s_addr = argp->addr;
446 if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
447 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
448 nlmsvc_free_host_resources(host);
450 nlm_release_host(host);
453 return rpc_success;
457 * This is the generic lockd callback for async RPC calls
459 static u32
460 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
462 struct nlm_host *host;
463 struct nlm_rqst *call;
465 if (!(call = nlmclnt_alloc_call()))
466 return rpc_system_err;
468 host = nlmclnt_lookup_host(&rqstp->rq_addr,
469 rqstp->rq_prot, rqstp->rq_vers);
470 if (!host) {
471 kfree(call);
472 return rpc_system_err;
475 call->a_flags = RPC_TASK_ASYNC;
476 call->a_host = host;
477 memcpy(&call->a_args, resp, sizeof(*resp));
479 if (nlmclnt_async_call(call, proc, nlmsvc_callback_exit) < 0)
480 return rpc_system_err;
482 return rpc_success;
485 static void
486 nlmsvc_callback_exit(struct rpc_task *task)
488 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
490 if (task->tk_status < 0) {
491 dprintk("lockd: %4d callback failed (errno = %d)\n",
492 task->tk_pid, -task->tk_status);
494 nlm_release_host(call->a_host);
495 rpc_release_task(task);
496 kfree(call);
500 * NLM Server procedures.
503 #define nlmsvc_encode_norep nlmsvc_encode_void
504 #define nlmsvc_decode_norep nlmsvc_decode_void
505 #define nlmsvc_decode_testres nlmsvc_decode_void
506 #define nlmsvc_decode_lockres nlmsvc_decode_void
507 #define nlmsvc_decode_unlockres nlmsvc_decode_void
508 #define nlmsvc_decode_cancelres nlmsvc_decode_void
509 #define nlmsvc_decode_grantedres nlmsvc_decode_void
511 #define nlmsvc_proc_none nlmsvc_proc_null
512 #define nlmsvc_proc_test_res nlmsvc_proc_null
513 #define nlmsvc_proc_lock_res nlmsvc_proc_null
514 #define nlmsvc_proc_cancel_res nlmsvc_proc_null
515 #define nlmsvc_proc_unlock_res nlmsvc_proc_null
516 #define nlmsvc_proc_granted_res nlmsvc_proc_null
518 struct nlm_void { int dummy; };
520 #define PROC(name, xargt, xrest, argt, rest) \
521 { (svc_procfunc) nlmsvc_proc_##name, \
522 (kxdrproc_t) nlmsvc_decode_##xargt, \
523 (kxdrproc_t) nlmsvc_encode_##xrest, \
524 NULL, \
525 sizeof(struct nlm_##argt), \
526 sizeof(struct nlm_##rest), \
527 0, \
530 struct svc_procedure nlmsvc_procedures[] = {
531 PROC(null, void, void, void, void),
532 PROC(test, testargs, testres, args, res),
533 PROC(lock, lockargs, res, args, res),
534 PROC(cancel, cancargs, res, args, res),
535 PROC(unlock, unlockargs, res, args, res),
536 PROC(granted, testargs, res, args, res),
537 PROC(test_msg, testargs, norep, args, void),
538 PROC(lock_msg, lockargs, norep, args, void),
539 PROC(cancel_msg, cancargs, norep, args, void),
540 PROC(unlock_msg, unlockargs, norep, args, void),
541 PROC(granted_msg, testargs, norep, args, void),
542 PROC(test_res, testres, norep, res, void),
543 PROC(lock_res, lockres, norep, res, void),
544 PROC(cancel_res, cancelres, norep, res, void),
545 PROC(unlock_res, unlockres, norep, res, void),
546 PROC(granted_res, grantedres, norep, res, void),
547 PROC(none, void, void, void, void),
548 PROC(none, void, void, void, void),
549 PROC(none, void, void, void, void),
550 PROC(none, void, void, void, void),
551 PROC(share, shareargs, shareres, args, res),
552 PROC(unshare, shareargs, shareres, args, res),
553 PROC(nm_lock, lockargs, res, args, res),
554 PROC(free_all, notify, void, args, void),
556 /* statd callback */
557 PROC(sm_notify, reboot, void, reboot, void),