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