Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
[pandora-kernel.git] / fs / lockd / xdr.c
1 /*
2  * linux/fs/lockd/xdr.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/config.h>
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/utsname.h>
13 #include <linux/nfs.h>
14
15 #include <linux/sunrpc/xdr.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/sunrpc/svc.h>
18 #include <linux/sunrpc/stats.h>
19 #include <linux/lockd/lockd.h>
20 #include <linux/lockd/sm_inter.h>
21
22 #define NLMDBG_FACILITY         NLMDBG_XDR
23
24
25 static inline loff_t
26 s32_to_loff_t(__s32 offset)
27 {
28         return (loff_t)offset;
29 }
30
31 static inline __s32
32 loff_t_to_s32(loff_t offset)
33 {
34         __s32 res;
35         if (offset >= NLM_OFFSET_MAX)
36                 res = NLM_OFFSET_MAX;
37         else if (offset <= -NLM_OFFSET_MAX)
38                 res = -NLM_OFFSET_MAX;
39         else
40                 res = offset;
41         return res;
42 }
43
44 /*
45  * XDR functions for basic NLM types
46  */
47 static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
48 {
49         unsigned int    len;
50
51         len = ntohl(*p++);
52         
53         if(len==0)
54         {
55                 c->len=4;
56                 memset(c->data, 0, 4);  /* hockeypux brain damage */
57         }
58         else if(len<=NLM_MAXCOOKIELEN)
59         {
60                 c->len=len;
61                 memcpy(c->data, p, len);
62                 p+=XDR_QUADLEN(len);
63         }
64         else 
65         {
66                 printk(KERN_NOTICE
67                         "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
68                 return NULL;
69         }
70         return p;
71 }
72
73 static inline u32 *
74 nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
75 {
76         *p++ = htonl(c->len);
77         memcpy(p, c->data, c->len);
78         p+=XDR_QUADLEN(c->len);
79         return p;
80 }
81
82 static u32 *
83 nlm_decode_fh(u32 *p, struct nfs_fh *f)
84 {
85         unsigned int    len;
86
87         if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
88                 printk(KERN_NOTICE
89                         "lockd: bad fhandle size %d (should be %d)\n",
90                         len, NFS2_FHSIZE);
91                 return NULL;
92         }
93         f->size = NFS2_FHSIZE;
94         memset(f->data, 0, sizeof(f->data));
95         memcpy(f->data, p, NFS2_FHSIZE);
96         return p + XDR_QUADLEN(NFS2_FHSIZE);
97 }
98
99 static inline u32 *
100 nlm_encode_fh(u32 *p, struct nfs_fh *f)
101 {
102         *p++ = htonl(NFS2_FHSIZE);
103         memcpy(p, f->data, NFS2_FHSIZE);
104         return p + XDR_QUADLEN(NFS2_FHSIZE);
105 }
106
107 /*
108  * Encode and decode owner handle
109  */
110 static inline u32 *
111 nlm_decode_oh(u32 *p, struct xdr_netobj *oh)
112 {
113         return xdr_decode_netobj(p, oh);
114 }
115
116 static inline u32 *
117 nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
118 {
119         return xdr_encode_netobj(p, oh);
120 }
121
122 static u32 *
123 nlm_decode_lock(u32 *p, struct nlm_lock *lock)
124 {
125         struct file_lock        *fl = &lock->fl;
126         s32                     start, len, end;
127
128         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
129                                             &lock->len,
130                                             NLM_MAXSTRLEN))
131          || !(p = nlm_decode_fh(p, &lock->fh))
132          || !(p = nlm_decode_oh(p, &lock->oh)))
133                 return NULL;
134         lock->svid  = ntohl(*p++);
135
136         locks_init_lock(fl);
137         fl->fl_owner = current->files;
138         fl->fl_pid   = (pid_t)lock->svid;
139         fl->fl_flags = FL_POSIX;
140         fl->fl_type  = F_RDLCK;         /* as good as anything else */
141         start = ntohl(*p++);
142         len = ntohl(*p++);
143         end = start + len - 1;
144
145         fl->fl_start = s32_to_loff_t(start);
146
147         if (len == 0 || end < 0)
148                 fl->fl_end = OFFSET_MAX;
149         else
150                 fl->fl_end = s32_to_loff_t(end);
151         return p;
152 }
153
154 /*
155  * Encode a lock as part of an NLM call
156  */
157 static u32 *
158 nlm_encode_lock(u32 *p, struct nlm_lock *lock)
159 {
160         struct file_lock        *fl = &lock->fl;
161         __s32                   start, len;
162
163         if (!(p = xdr_encode_string(p, lock->caller))
164          || !(p = nlm_encode_fh(p, &lock->fh))
165          || !(p = nlm_encode_oh(p, &lock->oh)))
166                 return NULL;
167
168         if (fl->fl_start > NLM_OFFSET_MAX
169          || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
170                 return NULL;
171
172         start = loff_t_to_s32(fl->fl_start);
173         if (fl->fl_end == OFFSET_MAX)
174                 len = 0;
175         else
176                 len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
177
178         *p++ = htonl(lock->svid);
179         *p++ = htonl(start);
180         *p++ = htonl(len);
181
182         return p;
183 }
184
185 /*
186  * Encode result of a TEST/TEST_MSG call
187  */
188 static u32 *
189 nlm_encode_testres(u32 *p, struct nlm_res *resp)
190 {
191         s32             start, len;
192
193         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
194                 return NULL;
195         *p++ = resp->status;
196
197         if (resp->status == nlm_lck_denied) {
198                 struct file_lock        *fl = &resp->lock.fl;
199
200                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
201                 *p++ = htonl(resp->lock.svid);
202
203                 /* Encode owner handle. */
204                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
205                         return NULL;
206
207                 start = loff_t_to_s32(fl->fl_start);
208                 if (fl->fl_end == OFFSET_MAX)
209                         len = 0;
210                 else
211                         len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
212
213                 *p++ = htonl(start);
214                 *p++ = htonl(len);
215         }
216
217         return p;
218 }
219
220
221 /*
222  * First, the server side XDR functions
223  */
224 int
225 nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
226 {
227         u32     exclusive;
228
229         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
230                 return 0;
231
232         exclusive = ntohl(*p++);
233         if (!(p = nlm_decode_lock(p, &argp->lock)))
234                 return 0;
235         if (exclusive)
236                 argp->lock.fl.fl_type = F_WRLCK;
237
238         return xdr_argsize_check(rqstp, p);
239 }
240
241 int
242 nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
243 {
244         if (!(p = nlm_encode_testres(p, resp)))
245                 return 0;
246         return xdr_ressize_check(rqstp, p);
247 }
248
249 int
250 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
251 {
252         u32     exclusive;
253
254         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
255                 return 0;
256         argp->block  = ntohl(*p++);
257         exclusive    = ntohl(*p++);
258         if (!(p = nlm_decode_lock(p, &argp->lock)))
259                 return 0;
260         if (exclusive)
261                 argp->lock.fl.fl_type = F_WRLCK;
262         argp->reclaim = ntohl(*p++);
263         argp->state   = ntohl(*p++);
264         argp->monitor = 1;              /* monitor client by default */
265
266         return xdr_argsize_check(rqstp, p);
267 }
268
269 int
270 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
271 {
272         u32     exclusive;
273
274         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
275                 return 0;
276         argp->block = ntohl(*p++);
277         exclusive = ntohl(*p++);
278         if (!(p = nlm_decode_lock(p, &argp->lock)))
279                 return 0;
280         if (exclusive)
281                 argp->lock.fl.fl_type = F_WRLCK;
282         return xdr_argsize_check(rqstp, p);
283 }
284
285 int
286 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
287 {
288         if (!(p = nlm_decode_cookie(p, &argp->cookie))
289          || !(p = nlm_decode_lock(p, &argp->lock)))
290                 return 0;
291         argp->lock.fl.fl_type = F_UNLCK;
292         return xdr_argsize_check(rqstp, p);
293 }
294
295 int
296 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
297 {
298         struct nlm_lock *lock = &argp->lock;
299
300         memset(lock, 0, sizeof(*lock));
301         locks_init_lock(&lock->fl);
302         lock->svid = ~(u32) 0;
303         lock->fl.fl_pid = (pid_t)lock->svid;
304
305         if (!(p = nlm_decode_cookie(p, &argp->cookie))
306          || !(p = xdr_decode_string_inplace(p, &lock->caller,
307                                             &lock->len, NLM_MAXSTRLEN))
308          || !(p = nlm_decode_fh(p, &lock->fh))
309          || !(p = nlm_decode_oh(p, &lock->oh)))
310                 return 0;
311         argp->fsm_mode = ntohl(*p++);
312         argp->fsm_access = ntohl(*p++);
313         return xdr_argsize_check(rqstp, p);
314 }
315
316 int
317 nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
318 {
319         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
320                 return 0;
321         *p++ = resp->status;
322         *p++ = xdr_zero;                /* sequence argument */
323         return xdr_ressize_check(rqstp, p);
324 }
325
326 int
327 nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
328 {
329         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
330                 return 0;
331         *p++ = resp->status;
332         return xdr_ressize_check(rqstp, p);
333 }
334
335 int
336 nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
337 {
338         struct nlm_lock *lock = &argp->lock;
339
340         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
341                                             &lock->len, NLM_MAXSTRLEN)))
342                 return 0;
343         argp->state = ntohl(*p++);
344         return xdr_argsize_check(rqstp, p);
345 }
346
347 int
348 nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
349 {
350         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
351                 return 0;
352         argp->state = ntohl(*p++);
353         /* Preserve the address in network byte order */
354         argp->addr = *p++;
355         argp->vers = *p++;
356         argp->proto = *p++;
357         return xdr_argsize_check(rqstp, p);
358 }
359
360 int
361 nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
362 {
363         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
364                 return 0;
365         resp->status = ntohl(*p++);
366         return xdr_argsize_check(rqstp, p);
367 }
368
369 int
370 nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
371 {
372         return xdr_argsize_check(rqstp, p);
373 }
374
375 int
376 nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
377 {
378         return xdr_ressize_check(rqstp, p);
379 }
380
381 /*
382  * Now, the client side XDR functions
383  */
384 #ifdef NLMCLNT_SUPPORT_SHARES
385 static int
386 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
387 {
388         return 0;
389 }
390 #endif
391
392 static int
393 nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
394 {
395         struct nlm_lock *lock = &argp->lock;
396
397         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
398                 return -EIO;
399         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
400         if (!(p = nlm_encode_lock(p, lock)))
401                 return -EIO;
402         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
403         return 0;
404 }
405
406 static int
407 nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
408 {
409         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
410                 return -EIO;
411         resp->status = ntohl(*p++);
412         if (resp->status == NLM_LCK_DENIED) {
413                 struct file_lock        *fl = &resp->lock.fl;
414                 u32                     excl;
415                 s32                     start, len, end;
416
417                 memset(&resp->lock, 0, sizeof(resp->lock));
418                 locks_init_lock(fl);
419                 excl = ntohl(*p++);
420                 resp->lock.svid = ntohl(*p++);
421                 fl->fl_pid = (pid_t)resp->lock.svid;
422                 if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
423                         return -EIO;
424
425                 fl->fl_flags = FL_POSIX;
426                 fl->fl_type  = excl? F_WRLCK : F_RDLCK;
427                 start = ntohl(*p++);
428                 len = ntohl(*p++);
429                 end = start + len - 1;
430
431                 fl->fl_start = s32_to_loff_t(start);
432                 if (len == 0 || end < 0)
433                         fl->fl_end = OFFSET_MAX;
434                 else
435                         fl->fl_end = s32_to_loff_t(end);
436         }
437         return 0;
438 }
439
440
441 static int
442 nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
443 {
444         struct nlm_lock *lock = &argp->lock;
445
446         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
447                 return -EIO;
448         *p++ = argp->block? xdr_one : xdr_zero;
449         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
450         if (!(p = nlm_encode_lock(p, lock)))
451                 return -EIO;
452         *p++ = argp->reclaim? xdr_one : xdr_zero;
453         *p++ = htonl(argp->state);
454         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
455         return 0;
456 }
457
458 static int
459 nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
460 {
461         struct nlm_lock *lock = &argp->lock;
462
463         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
464                 return -EIO;
465         *p++ = argp->block? xdr_one : xdr_zero;
466         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
467         if (!(p = nlm_encode_lock(p, lock)))
468                 return -EIO;
469         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
470         return 0;
471 }
472
473 static int
474 nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
475 {
476         struct nlm_lock *lock = &argp->lock;
477
478         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
479                 return -EIO;
480         if (!(p = nlm_encode_lock(p, lock)))
481                 return -EIO;
482         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
483         return 0;
484 }
485
486 static int
487 nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
488 {
489         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
490                 return -EIO;
491         *p++ = resp->status;
492         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
493         return 0;
494 }
495
496 static int
497 nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
498 {
499         if (!(p = nlm_encode_testres(p, resp)))
500                 return -EIO;
501         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
502         return 0;
503 }
504
505 static int
506 nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
507 {
508         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
509                 return -EIO;
510         resp->status = ntohl(*p++);
511         return 0;
512 }
513
514 /*
515  * Buffer requirements for NLM
516  */
517 #define NLM_void_sz             0
518 #define NLM_cookie_sz           1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
519 #define NLM_caller_sz           1+XDR_QUADLEN(sizeof(system_utsname.nodename))
520 #define NLM_netobj_sz           1+XDR_QUADLEN(XDR_MAX_NETOBJ)
521 /* #define NLM_owner_sz         1+XDR_QUADLEN(NLM_MAXOWNER) */
522 #define NLM_fhandle_sz          1+XDR_QUADLEN(NFS2_FHSIZE)
523 #define NLM_lock_sz             3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
524 #define NLM_holder_sz           4+NLM_netobj_sz
525
526 #define NLM_testargs_sz         NLM_cookie_sz+1+NLM_lock_sz
527 #define NLM_lockargs_sz         NLM_cookie_sz+4+NLM_lock_sz
528 #define NLM_cancargs_sz         NLM_cookie_sz+2+NLM_lock_sz
529 #define NLM_unlockargs_sz       NLM_cookie_sz+NLM_lock_sz
530
531 #define NLM_testres_sz          NLM_cookie_sz+1+NLM_holder_sz
532 #define NLM_res_sz              NLM_cookie_sz+1
533 #define NLM_norep_sz            0
534
535 #ifndef MAX
536 # define MAX(a, b)              (((a) > (b))? (a) : (b))
537 #endif
538
539 /*
540  * For NLM, a void procedure really returns nothing
541  */
542 #define nlmclt_decode_norep     NULL
543
544 #define PROC(proc, argtype, restype)    \
545 [NLMPROC_##proc] = {                                                    \
546         .p_proc      = NLMPROC_##proc,                                  \
547         .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,            \
548         .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,            \
549         .p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,        \
550         .p_statidx   = NLMPROC_##proc,                                  \
551         .p_name      = #proc,                                           \
552         }
553
554 static struct rpc_procinfo      nlm_procedures[] = {
555     PROC(TEST,          testargs,       testres),
556     PROC(LOCK,          lockargs,       res),
557     PROC(CANCEL,        cancargs,       res),
558     PROC(UNLOCK,        unlockargs,     res),
559     PROC(GRANTED,       testargs,       res),
560     PROC(TEST_MSG,      testargs,       norep),
561     PROC(LOCK_MSG,      lockargs,       norep),
562     PROC(CANCEL_MSG,    cancargs,       norep),
563     PROC(UNLOCK_MSG,    unlockargs,     norep),
564     PROC(GRANTED_MSG,   testargs,       norep),
565     PROC(TEST_RES,      testres,        norep),
566     PROC(LOCK_RES,      res,            norep),
567     PROC(CANCEL_RES,    res,            norep),
568     PROC(UNLOCK_RES,    res,            norep),
569     PROC(GRANTED_RES,   res,            norep),
570 #ifdef NLMCLNT_SUPPORT_SHARES
571     PROC(SHARE,         shareargs,      shareres),
572     PROC(UNSHARE,       shareargs,      shareres),
573     PROC(NM_LOCK,       lockargs,       res),
574     PROC(FREE_ALL,      notify,         void),
575 #endif
576 };
577
578 static struct rpc_version       nlm_version1 = {
579                 .number         = 1,
580                 .nrprocs        = 16,
581                 .procs          = nlm_procedures,
582 };
583
584 static struct rpc_version       nlm_version3 = {
585                 .number         = 3,
586                 .nrprocs        = 24,
587                 .procs          = nlm_procedures,
588 };
589
590 #ifdef  CONFIG_LOCKD_V4
591 extern struct rpc_version nlm_version4;
592 #endif
593
594 static struct rpc_version *     nlm_versions[] = {
595         [1] = &nlm_version1,
596         [3] = &nlm_version3,
597 #ifdef  CONFIG_LOCKD_V4
598         [4] = &nlm_version4,
599 #endif
600 };
601
602 static struct rpc_stat          nlm_stats;
603
604 struct rpc_program              nlm_program = {
605                 .name           = "lockd",
606                 .number         = NLM_PROGRAM,
607                 .nrvers         = ARRAY_SIZE(nlm_versions),
608                 .version        = nlm_versions,
609                 .stats          = &nlm_stats,
610 };
611
612 #ifdef RPC_DEBUG
613 const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
614 {
615         /*
616          * We can get away with a static buffer because we're only
617          * called with BKL held.
618          */
619         static char buf[2*NLM_MAXCOOKIELEN+1];
620         int i;
621         int len = sizeof(buf);
622         char *p = buf;
623
624         len--;  /* allow for trailing \0 */
625         if (len < 3)
626                 return "???";
627         for (i = 0 ; i < cookie->len ; i++) {
628                 if (len < 2) {
629                         strcpy(p-3, "...");
630                         break;
631                 }
632                 sprintf(p, "%02x", cookie->data[i]);
633                 p += 2;
634                 len -= 2;
635         }
636         *p = '\0';
637
638         return buf;
639 }
640 #endif