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