import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.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/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 static inline loff_t
25 s64_to_loff_t(__s64 offset)
26 {
27         return (loff_t)offset;
28 }
29
30
31 static inline s64
32 loff_t_to_s64(loff_t offset)
33 {
34         s64 res;
35         if (offset > NLM4_OFFSET_MAX)
36                 res = NLM4_OFFSET_MAX;
37         else if (offset < -NLM4_OFFSET_MAX)
38                 res = -NLM4_OFFSET_MAX;
39         else
40                 res = offset;
41         return res;
42 }
43
44 /*
45  * XDR functions for basic NLM types
46  */
47 static u32 *
48 nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
49 {
50         unsigned int    len;
51
52         len = ntohl(*p++);
53         
54         if(len==0)
55         {
56                 c->len=4;
57                 memset(c->data, 0, 4);  /* hockeypux brain damage */
58         }
59         else if(len<=8)
60         {
61                 c->len=len;
62                 memcpy(c->data, p, len);
63                 p+=(len+3)>>2;
64         }
65         else 
66         {
67                 printk(KERN_NOTICE
68                         "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len);
69                 return NULL;
70         }
71         return p;
72 }
73
74 static u32 *
75 nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
76 {
77         *p++ = htonl(c->len);
78         memcpy(p, c->data, c->len);
79         p+=(c->len+3)>>2;
80         return p;
81 }
82
83 static u32 *
84 nlm4_decode_fh(u32 *p, struct nfs_fh *f)
85 {
86         memset(f->data, 0, sizeof(f->data));
87         f->size = ntohl(*p++);
88         if (f->size > NFS_MAXFHSIZE) {
89                 printk(KERN_NOTICE
90                         "lockd: bad fhandle size %d (should be <=%d)\n",
91                         f->size, NFS_MAXFHSIZE);
92                 return NULL;
93         }
94         memcpy(f->data, p, f->size);
95         return p + XDR_QUADLEN(f->size);
96 }
97
98 static u32 *
99 nlm4_encode_fh(u32 *p, struct nfs_fh *f)
100 {
101         *p++ = htonl(f->size);
102         if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
103         memcpy(p, f->data, f->size);
104         return p + XDR_QUADLEN(f->size);
105 }
106
107 /*
108  * Encode and decode owner handle
109  */
110 static u32 *
111 nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
112 {
113         return xdr_decode_netobj(p, oh);
114 }
115
116 static u32 *
117 nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
118 {
119         return xdr_encode_netobj(p, oh);
120 }
121
122 static u32 *
123 nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
124 {
125         struct file_lock        *fl = &lock->fl;
126         __s64                   len, start, end;
127
128         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
129                                             &lock->len, NLM_MAXSTRLEN))
130          || !(p = nlm4_decode_fh(p, &lock->fh))
131          || !(p = nlm4_decode_oh(p, &lock->oh)))
132                 return NULL;
133
134         locks_init_lock(fl);
135         fl->fl_owner = current->files;
136         fl->fl_pid   = ntohl(*p++);
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 u32 *
156 nlm4_encode_lock(u32 *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(fl->fl_pid);
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 u32 *
188 nlm4_encode_testres(u32 *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 0;
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(fl->fl_pid);
202
203                 /* Encode owner handle. */
204                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
205                         return 0;
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 %d pid %d type %d start %Ld end %Ld)\n",
216                         resp->status, fl->fl_pid, 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  * Check buffer bounds after decoding arguments
227  */
228 static int
229 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
230 {
231         struct svc_buf  *buf = &rqstp->rq_argbuf;
232
233         return p - buf->base <= buf->buflen;
234 }
235
236 static int
237 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
238 {
239         struct svc_buf  *buf = &rqstp->rq_resbuf;
240
241         buf->len = p - buf->base;
242         return (buf->len <= buf->buflen);
243 }
244
245 /*
246  * First, the server side XDR functions
247  */
248 int
249 nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
250 {
251         u32     exclusive;
252
253         if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
254                 return 0;
255
256         exclusive = ntohl(*p++);
257         if (!(p = nlm4_decode_lock(p, &argp->lock)))
258                 return 0;
259         if (exclusive)
260                 argp->lock.fl.fl_type = F_WRLCK;
261
262         return xdr_argsize_check(rqstp, p);
263 }
264
265 int
266 nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
267 {
268         if (!(p = nlm4_encode_testres(p, resp)))
269                 return 0;
270         return xdr_ressize_check(rqstp, p);
271 }
272
273 int
274 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *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         argp->reclaim = ntohl(*p++);
287         argp->state   = ntohl(*p++);
288         argp->monitor = 1;              /* monitor client by default */
289
290         return xdr_argsize_check(rqstp, p);
291 }
292
293 int
294 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
295 {
296         u32     exclusive;
297
298         if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
299                 return 0;
300         argp->block = ntohl(*p++);
301         exclusive = ntohl(*p++);
302         if (!(p = nlm4_decode_lock(p, &argp->lock)))
303                 return 0;
304         if (exclusive)
305                 argp->lock.fl.fl_type = F_WRLCK;
306         return xdr_argsize_check(rqstp, p);
307 }
308
309 int
310 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
311 {
312         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
313          || !(p = nlm4_decode_lock(p, &argp->lock)))
314                 return 0;
315         argp->lock.fl.fl_type = F_UNLCK;
316         return xdr_argsize_check(rqstp, p);
317 }
318
319 int
320 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
321 {
322         struct nlm_lock *lock = &argp->lock;
323
324         memset(lock, 0, sizeof(*lock));
325         locks_init_lock(&lock->fl);
326         lock->fl.fl_pid = ~(u32) 0;
327
328         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
329          || !(p = xdr_decode_string_inplace(p, &lock->caller,
330                                             &lock->len, NLM_MAXSTRLEN))
331          || !(p = nlm4_decode_fh(p, &lock->fh))
332          || !(p = nlm4_decode_oh(p, &lock->oh)))
333                 return 0;
334         argp->fsm_mode = ntohl(*p++);
335         argp->fsm_access = ntohl(*p++);
336         return xdr_argsize_check(rqstp, p);
337 }
338
339 int
340 nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
341 {
342         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
343                 return 0;
344         *p++ = resp->status;
345         *p++ = xdr_zero;                /* sequence argument */
346         return xdr_ressize_check(rqstp, p);
347 }
348
349 int
350 nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
351 {
352         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
353                 return 0;
354         *p++ = resp->status;
355         return xdr_ressize_check(rqstp, p);
356 }
357
358 int
359 nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
360 {
361         struct nlm_lock *lock = &argp->lock;
362
363         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
364                                             &lock->len, NLM_MAXSTRLEN)))
365                 return 0;
366         argp->state = ntohl(*p++);
367         return xdr_argsize_check(rqstp, p);
368 }
369
370 int
371 nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
372 {
373         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
374                 return 0;
375         argp->state = ntohl(*p++);
376         /* Preserve the address in network byte order */
377         argp->addr = *p++;
378         return xdr_argsize_check(rqstp, p);
379 }
380
381 int
382 nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
383 {
384         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
385                 return 0;
386         resp->status = ntohl(*p++);
387         return xdr_argsize_check(rqstp, p);
388 }
389
390 int
391 nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
392 {
393         return xdr_argsize_check(rqstp, p);
394 }
395
396 int
397 nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
398 {
399         return xdr_ressize_check(rqstp, p);
400 }
401
402 /*
403  * Now, the client side XDR functions
404  */
405 static int
406 nlm4clt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr)
407 {
408         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
409         return 0;
410 }
411
412 static int
413 nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
414 {
415         return 0;
416 }
417
418 static int
419 nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
420 {
421         struct nlm_lock *lock = &argp->lock;
422
423         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
424                 return -EIO;
425         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
426         if (!(p = nlm4_encode_lock(p, lock)))
427                 return -EIO;
428         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
429         return 0;
430 }
431
432 static int
433 nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
434 {
435         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
436                 return -EIO;
437         resp->status = ntohl(*p++);
438         if (resp->status == NLM_LCK_DENIED) {
439                 struct file_lock        *fl = &resp->lock.fl;
440                 u32                     excl;
441                 s64                     start, end, len;
442
443                 memset(&resp->lock, 0, sizeof(resp->lock));
444                 locks_init_lock(fl);
445                 excl = ntohl(*p++);
446                 fl->fl_pid = ntohl(*p++);
447                 if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
448                         return -EIO;
449
450                 fl->fl_flags = FL_POSIX;
451                 fl->fl_type  = excl? F_WRLCK : F_RDLCK;
452                 p = xdr_decode_hyper(p, &start);
453                 p = xdr_decode_hyper(p, &len);
454                 end = start + len - 1;
455
456                 fl->fl_start = s64_to_loff_t(start);
457                 if (len == 0 || end < 0)
458                         fl->fl_end = OFFSET_MAX;
459                 else
460                         fl->fl_end = s64_to_loff_t(end);
461         }
462         return 0;
463 }
464
465
466 static int
467 nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
468 {
469         struct nlm_lock *lock = &argp->lock;
470
471         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
472                 return -EIO;
473         *p++ = argp->block? xdr_one : xdr_zero;
474         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
475         if (!(p = nlm4_encode_lock(p, lock)))
476                 return -EIO;
477         *p++ = argp->reclaim? xdr_one : xdr_zero;
478         *p++ = htonl(argp->state);
479         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
480         return 0;
481 }
482
483 static int
484 nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
485 {
486         struct nlm_lock *lock = &argp->lock;
487
488         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
489                 return -EIO;
490         *p++ = argp->block? xdr_one : xdr_zero;
491         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
492         if (!(p = nlm4_encode_lock(p, lock)))
493                 return -EIO;
494         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
495         return 0;
496 }
497
498 static int
499 nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
500 {
501         struct nlm_lock *lock = &argp->lock;
502
503         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
504                 return -EIO;
505         if (!(p = nlm4_encode_lock(p, lock)))
506                 return -EIO;
507         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
508         return 0;
509 }
510
511 static int
512 nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
513 {
514         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
515                 return -EIO;
516         *p++ = resp->status;
517         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
518         return 0;
519 }
520
521 static int
522 nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
523 {
524         if (!(p = nlm4_encode_testres(p, resp)))
525                 return -EIO;
526         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
527         return 0;
528 }
529
530 static int
531 nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
532 {
533         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
534                 return -EIO;
535         resp->status = ntohl(*p++);
536         return 0;
537 }
538
539 /*
540  * Buffer requirements for NLM
541  */
542 #define NLM4_void_sz            0
543 #define NLM4_cookie_sz          3       /* 1 len , 2 data */
544 #define NLM4_caller_sz          1+XDR_QUADLEN(NLM_MAXSTRLEN)
545 #define NLM4_netobj_sz          1+XDR_QUADLEN(XDR_MAX_NETOBJ)
546 /* #define NLM4_owner_sz                1+XDR_QUADLEN(NLM4_MAXOWNER) */
547 #define NLM4_fhandle_sz         1+XDR_QUADLEN(NFS3_FHSIZE)
548 #define NLM4_lock_sz            5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
549 #define NLM4_holder_sz          6+NLM4_netobj_sz
550
551 #define NLM4_testargs_sz        NLM4_cookie_sz+1+NLM4_lock_sz
552 #define NLM4_lockargs_sz        NLM4_cookie_sz+4+NLM4_lock_sz
553 #define NLM4_cancargs_sz        NLM4_cookie_sz+2+NLM4_lock_sz
554 #define NLM4_unlockargs_sz      NLM4_cookie_sz+NLM4_lock_sz
555
556 #define NLM4_testres_sz         NLM4_cookie_sz+1+NLM4_holder_sz
557 #define NLM4_res_sz             NLM4_cookie_sz+1
558 #define NLM4_norep_sz           0
559
560 #ifndef MAX
561 # define MAX(a,b)               (((a) > (b))? (a) : (b))
562 #endif
563
564 /*
565  * For NLM, a void procedure really returns nothing
566  */
567 #define nlm4clt_decode_norep    NULL
568
569 #define PROC(proc, argtype, restype)                                    \
570     { .p_procname  = "nlm4_" #proc,                                     \
571       .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,             \
572       .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,             \
573       .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2 \
574     }
575
576 static struct rpc_procinfo      nlm4_procedures[] = {
577     PROC(null,          void,           void),
578     PROC(test,          testargs,       testres),
579     PROC(lock,          lockargs,       res),
580     PROC(canc,          cancargs,       res),
581     PROC(unlock,        unlockargs,     res),
582     PROC(granted,       testargs,       res),
583     PROC(test_msg,      testargs,       norep),
584     PROC(lock_msg,      lockargs,       norep),
585     PROC(canc_msg,      cancargs,       norep),
586     PROC(unlock_msg,    unlockargs,     norep),
587     PROC(granted_msg,   testargs,       norep),
588     PROC(test_res,      testres,        norep),
589     PROC(lock_res,      res,            norep),
590     PROC(canc_res,      res,            norep),
591     PROC(unlock_res,    res,            norep),
592     PROC(granted_res,   res,            norep),
593     PROC(undef,         void,           void),
594     PROC(undef,         void,           void),
595     PROC(undef,         void,           void),
596     PROC(undef,         void,           void),
597 #ifdef NLMCLNT_SUPPORT_SHARES
598     PROC(share,         shareargs,      shareres),
599     PROC(unshare,       shareargs,      shareres),
600     PROC(nm_lock,       lockargs,       res),
601     PROC(free_all,      notify,         void),
602 #else
603     PROC(undef,         void,           void),
604     PROC(undef,         void,           void),
605     PROC(undef,         void,           void),
606     PROC(undef,         void,           void),
607 #endif
608 };
609
610 struct rpc_version      nlm_version4 = {
611         4, 24, nlm4_procedures,
612 };