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