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