Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / fs / lockd / xdr4.c
1 /*
2  * linux/fs/lockd/xdr4.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
8  */
9
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/nfs.h>
13
14 #include <linux/sunrpc/xdr.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/sunrpc/svc.h>
17 #include <linux/sunrpc/stats.h>
18 #include <linux/lockd/lockd.h>
19
20 #define NLMDBG_FACILITY         NLMDBG_XDR
21
22 static inline loff_t
23 s64_to_loff_t(__s64 offset)
24 {
25         return (loff_t)offset;
26 }
27
28
29 static inline s64
30 loff_t_to_s64(loff_t offset)
31 {
32         s64 res;
33         if (offset > NLM4_OFFSET_MAX)
34                 res = NLM4_OFFSET_MAX;
35         else if (offset < -NLM4_OFFSET_MAX)
36                 res = -NLM4_OFFSET_MAX;
37         else
38                 res = offset;
39         return res;
40 }
41
42 /*
43  * XDR functions for basic NLM types
44  */
45 static __be32 *
46 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
47 {
48         unsigned int    len;
49
50         len = ntohl(*p++);
51         
52         if(len==0)
53         {
54                 c->len=4;
55                 memset(c->data, 0, 4);  /* hockeypux brain damage */
56         }
57         else if(len<=NLM_MAXCOOKIELEN)
58         {
59                 c->len=len;
60                 memcpy(c->data, p, len);
61                 p+=XDR_QUADLEN(len);
62         }
63         else 
64         {
65                 dprintk("lockd: bad cookie size %d (only cookies under "
66                         "%d bytes are supported.)\n",
67                                 len, NLM_MAXCOOKIELEN);
68                 return NULL;
69         }
70         return p;
71 }
72
73 static __be32 *
74 nlm4_encode_cookie(__be32 *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 __be32 *
83 nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
84 {
85         memset(f->data, 0, sizeof(f->data));
86         f->size = ntohl(*p++);
87         if (f->size > NFS_MAXFHSIZE) {
88                 dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
89                         f->size, NFS_MAXFHSIZE);
90                 return NULL;
91         }
92         memcpy(f->data, p, f->size);
93         return p + XDR_QUADLEN(f->size);
94 }
95
96 static __be32 *
97 nlm4_encode_fh(__be32 *p, struct nfs_fh *f)
98 {
99         *p++ = htonl(f->size);
100         if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
101         memcpy(p, f->data, f->size);
102         return p + XDR_QUADLEN(f->size);
103 }
104
105 /*
106  * Encode and decode owner handle
107  */
108 static __be32 *
109 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
110 {
111         return xdr_decode_netobj(p, oh);
112 }
113
114 static __be32 *
115 nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh)
116 {
117         return xdr_encode_netobj(p, oh);
118 }
119
120 static __be32 *
121 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
122 {
123         struct file_lock        *fl = &lock->fl;
124         __u64                   len, start;
125         __s64                   end;
126
127         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
128                                             &lock->len, NLM_MAXSTRLEN))
129          || !(p = nlm4_decode_fh(p, &lock->fh))
130          || !(p = nlm4_decode_oh(p, &lock->oh)))
131                 return NULL;
132         lock->svid  = ntohl(*p++);
133
134         locks_init_lock(fl);
135         fl->fl_owner = current->files;
136         fl->fl_pid   = (pid_t)lock->svid;
137         fl->fl_flags = FL_POSIX;
138         fl->fl_type  = F_RDLCK;         /* as good as anything else */
139         p = xdr_decode_hyper(p, &start);
140         p = xdr_decode_hyper(p, &len);
141         end = start + len - 1;
142
143         fl->fl_start = s64_to_loff_t(start);
144
145         if (len == 0 || end < 0)
146                 fl->fl_end = OFFSET_MAX;
147         else
148                 fl->fl_end = s64_to_loff_t(end);
149         return p;
150 }
151
152 /*
153  * Encode a lock as part of an NLM call
154  */
155 static __be32 *
156 nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
157 {
158         struct file_lock        *fl = &lock->fl;
159         __s64                   start, len;
160
161         if (!(p = xdr_encode_string(p, lock->caller))
162          || !(p = nlm4_encode_fh(p, &lock->fh))
163          || !(p = nlm4_encode_oh(p, &lock->oh)))
164                 return NULL;
165
166         if (fl->fl_start > NLM4_OFFSET_MAX
167          || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
168                 return NULL;
169
170         *p++ = htonl(lock->svid);
171
172         start = loff_t_to_s64(fl->fl_start);
173         if (fl->fl_end == OFFSET_MAX)
174                 len = 0;
175         else
176                 len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
177
178         p = xdr_encode_hyper(p, start);
179         p = xdr_encode_hyper(p, len);
180
181         return p;
182 }
183
184 /*
185  * Encode result of a TEST/TEST_MSG call
186  */
187 static __be32 *
188 nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
189 {
190         s64             start, len;
191
192         dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
193         if (!(p = nlm4_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_s64(fl->fl_start);
208                 if (fl->fl_end == OFFSET_MAX)
209                         len = 0;
210                 else
211                         len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
212                 
213                 p = xdr_encode_hyper(p, start);
214                 p = xdr_encode_hyper(p, len);
215                 dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
216                         resp->status, (int)resp->lock.svid, fl->fl_type,
217                         (long long)fl->fl_start,  (long long)fl->fl_end);
218         }
219
220         dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
221         return p;
222 }
223
224
225 /*
226  * First, the server side XDR functions
227  */
228 int
229 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
230 {
231         u32     exclusive;
232
233         if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
234                 return 0;
235
236         exclusive = ntohl(*p++);
237         if (!(p = nlm4_decode_lock(p, &argp->lock)))
238                 return 0;
239         if (exclusive)
240                 argp->lock.fl.fl_type = F_WRLCK;
241
242         return xdr_argsize_check(rqstp, p);
243 }
244
245 int
246 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
247 {
248         if (!(p = nlm4_encode_testres(p, resp)))
249                 return 0;
250         return xdr_ressize_check(rqstp, p);
251 }
252
253 int
254 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
255 {
256         u32     exclusive;
257
258         if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
259                 return 0;
260         argp->block  = ntohl(*p++);
261         exclusive    = ntohl(*p++);
262         if (!(p = nlm4_decode_lock(p, &argp->lock)))
263                 return 0;
264         if (exclusive)
265                 argp->lock.fl.fl_type = F_WRLCK;
266         argp->reclaim = ntohl(*p++);
267         argp->state   = ntohl(*p++);
268         argp->monitor = 1;              /* monitor client by default */
269
270         return xdr_argsize_check(rqstp, p);
271 }
272
273 int
274 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
275 {
276         u32     exclusive;
277
278         if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
279                 return 0;
280         argp->block = ntohl(*p++);
281         exclusive = ntohl(*p++);
282         if (!(p = nlm4_decode_lock(p, &argp->lock)))
283                 return 0;
284         if (exclusive)
285                 argp->lock.fl.fl_type = F_WRLCK;
286         return xdr_argsize_check(rqstp, p);
287 }
288
289 int
290 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
291 {
292         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
293          || !(p = nlm4_decode_lock(p, &argp->lock)))
294                 return 0;
295         argp->lock.fl.fl_type = F_UNLCK;
296         return xdr_argsize_check(rqstp, p);
297 }
298
299 int
300 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
301 {
302         struct nlm_lock *lock = &argp->lock;
303
304         memset(lock, 0, sizeof(*lock));
305         locks_init_lock(&lock->fl);
306         lock->svid = ~(u32) 0;
307         lock->fl.fl_pid = (pid_t)lock->svid;
308
309         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
310          || !(p = xdr_decode_string_inplace(p, &lock->caller,
311                                             &lock->len, NLM_MAXSTRLEN))
312          || !(p = nlm4_decode_fh(p, &lock->fh))
313          || !(p = nlm4_decode_oh(p, &lock->oh)))
314                 return 0;
315         argp->fsm_mode = ntohl(*p++);
316         argp->fsm_access = ntohl(*p++);
317         return xdr_argsize_check(rqstp, p);
318 }
319
320 int
321 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
322 {
323         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
324                 return 0;
325         *p++ = resp->status;
326         *p++ = xdr_zero;                /* sequence argument */
327         return xdr_ressize_check(rqstp, p);
328 }
329
330 int
331 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
332 {
333         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
334                 return 0;
335         *p++ = resp->status;
336         return xdr_ressize_check(rqstp, p);
337 }
338
339 int
340 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
341 {
342         struct nlm_lock *lock = &argp->lock;
343
344         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
345                                             &lock->len, NLM_MAXSTRLEN)))
346                 return 0;
347         argp->state = ntohl(*p++);
348         return xdr_argsize_check(rqstp, p);
349 }
350
351 int
352 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
353 {
354         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
355                 return 0;
356         argp->state = ntohl(*p++);
357         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
358         p += XDR_QUADLEN(SM_PRIV_SIZE);
359         return xdr_argsize_check(rqstp, p);
360 }
361
362 int
363 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
364 {
365         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
366                 return 0;
367         resp->status = *p++;
368         return xdr_argsize_check(rqstp, p);
369 }
370
371 int
372 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
373 {
374         return xdr_argsize_check(rqstp, p);
375 }
376
377 int
378 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
379 {
380         return xdr_ressize_check(rqstp, p);
381 }
382
383 /*
384  * Now, the client side XDR functions
385  */
386 #ifdef NLMCLNT_SUPPORT_SHARES
387 static int
388 nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr)
389 {
390         return 0;
391 }
392 #endif
393
394 static int
395 nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
396 {
397         struct nlm_lock *lock = &argp->lock;
398
399         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
400                 return -EIO;
401         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
402         if (!(p = nlm4_encode_lock(p, lock)))
403                 return -EIO;
404         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
405         return 0;
406 }
407
408 static int
409 nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
410 {
411         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
412                 return -EIO;
413         resp->status = *p++;
414         if (resp->status == nlm_lck_denied) {
415                 struct file_lock        *fl = &resp->lock.fl;
416                 u32                     excl;
417                 __u64                   start, len;
418                 __s64                   end;
419
420                 memset(&resp->lock, 0, sizeof(resp->lock));
421                 locks_init_lock(fl);
422                 excl = ntohl(*p++);
423                 resp->lock.svid = ntohl(*p++);
424                 fl->fl_pid = (pid_t)resp->lock.svid;
425                 if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
426                         return -EIO;
427
428                 fl->fl_flags = FL_POSIX;
429                 fl->fl_type  = excl? F_WRLCK : F_RDLCK;
430                 p = xdr_decode_hyper(p, &start);
431                 p = xdr_decode_hyper(p, &len);
432                 end = start + len - 1;
433
434                 fl->fl_start = s64_to_loff_t(start);
435                 if (len == 0 || end < 0)
436                         fl->fl_end = OFFSET_MAX;
437                 else
438                         fl->fl_end = s64_to_loff_t(end);
439         }
440         return 0;
441 }
442
443
444 static int
445 nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
446 {
447         struct nlm_lock *lock = &argp->lock;
448
449         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
450                 return -EIO;
451         *p++ = argp->block? xdr_one : xdr_zero;
452         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
453         if (!(p = nlm4_encode_lock(p, lock)))
454                 return -EIO;
455         *p++ = argp->reclaim? xdr_one : xdr_zero;
456         *p++ = htonl(argp->state);
457         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
458         return 0;
459 }
460
461 static int
462 nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
463 {
464         struct nlm_lock *lock = &argp->lock;
465
466         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
467                 return -EIO;
468         *p++ = argp->block? xdr_one : xdr_zero;
469         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
470         if (!(p = nlm4_encode_lock(p, lock)))
471                 return -EIO;
472         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
473         return 0;
474 }
475
476 static int
477 nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
478 {
479         struct nlm_lock *lock = &argp->lock;
480
481         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
482                 return -EIO;
483         if (!(p = nlm4_encode_lock(p, lock)))
484                 return -EIO;
485         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
486         return 0;
487 }
488
489 static int
490 nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
491 {
492         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
493                 return -EIO;
494         *p++ = resp->status;
495         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
496         return 0;
497 }
498
499 static int
500 nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
501 {
502         if (!(p = nlm4_encode_testres(p, resp)))
503                 return -EIO;
504         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
505         return 0;
506 }
507
508 static int
509 nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
510 {
511         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
512                 return -EIO;
513         resp->status = *p++;
514         return 0;
515 }
516
517 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
518 #  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
519 #endif
520
521 #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
522 #  error "NLM host name cannot be larger than NLM's maximum string length!"
523 #endif
524
525 /*
526  * Buffer requirements for NLM
527  */
528 #define NLM4_void_sz            0
529 #define NLM4_cookie_sz          1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
530 #define NLM4_caller_sz          1+XDR_QUADLEN(NLMCLNT_OHSIZE)
531 #define NLM4_owner_sz           1+XDR_QUADLEN(NLMCLNT_OHSIZE)
532 #define NLM4_fhandle_sz         1+XDR_QUADLEN(NFS3_FHSIZE)
533 #define NLM4_lock_sz            5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz
534 #define NLM4_holder_sz          6+NLM4_owner_sz
535
536 #define NLM4_testargs_sz        NLM4_cookie_sz+1+NLM4_lock_sz
537 #define NLM4_lockargs_sz        NLM4_cookie_sz+4+NLM4_lock_sz
538 #define NLM4_cancargs_sz        NLM4_cookie_sz+2+NLM4_lock_sz
539 #define NLM4_unlockargs_sz      NLM4_cookie_sz+NLM4_lock_sz
540
541 #define NLM4_testres_sz         NLM4_cookie_sz+1+NLM4_holder_sz
542 #define NLM4_res_sz             NLM4_cookie_sz+1
543 #define NLM4_norep_sz           0
544
545 /*
546  * For NLM, a void procedure really returns nothing
547  */
548 #define nlm4clt_decode_norep    NULL
549
550 #define PROC(proc, argtype, restype)                                    \
551 [NLMPROC_##proc] = {                                                    \
552         .p_proc      = NLMPROC_##proc,                                  \
553         .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,           \
554         .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,           \
555         .p_arglen    = NLM4_##argtype##_sz,                             \
556         .p_replen    = NLM4_##restype##_sz,                             \
557         .p_statidx   = NLMPROC_##proc,                                  \
558         .p_name      = #proc,                                           \
559         }
560
561 static struct rpc_procinfo      nlm4_procedures[] = {
562     PROC(TEST,          testargs,       testres),
563     PROC(LOCK,          lockargs,       res),
564     PROC(CANCEL,        cancargs,       res),
565     PROC(UNLOCK,        unlockargs,     res),
566     PROC(GRANTED,       testargs,       res),
567     PROC(TEST_MSG,      testargs,       norep),
568     PROC(LOCK_MSG,      lockargs,       norep),
569     PROC(CANCEL_MSG,    cancargs,       norep),
570     PROC(UNLOCK_MSG,    unlockargs,     norep),
571     PROC(GRANTED_MSG,   testargs,       norep),
572     PROC(TEST_RES,      testres,        norep),
573     PROC(LOCK_RES,      res,            norep),
574     PROC(CANCEL_RES,    res,            norep),
575     PROC(UNLOCK_RES,    res,            norep),
576     PROC(GRANTED_RES,   res,            norep),
577 #ifdef NLMCLNT_SUPPORT_SHARES
578     PROC(SHARE,         shareargs,      shareres),
579     PROC(UNSHARE,       shareargs,      shareres),
580     PROC(NM_LOCK,       lockargs,       res),
581     PROC(FREE_ALL,      notify,         void),
582 #endif
583 };
584
585 struct rpc_version      nlm_version4 = {
586         .number         = 4,
587         .nrprocs        = 24,
588         .procs          = nlm4_procedures,
589 };