linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.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<=NLM_MAXCOOKIELEN)
60         {
61                 c->len=len;
62                 memcpy(c->data, p, len);
63                 p+=XDR_QUADLEN(len);
64         }
65         else 
66         {
67                 printk(KERN_NOTICE
68                         "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
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+=XDR_QUADLEN(c->len);
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 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(fl->fl_pid);
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 %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  * First, the server side XDR functions
227  */
228 int
229 nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *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, u32 *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, u32 *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, 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         return xdr_argsize_check(rqstp, p);
287 }
288
289 int
290 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *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, u32 *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->fl.fl_pid = ~(u32) 0;
307
308         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
309          || !(p = xdr_decode_string_inplace(p, &lock->caller,
310                                             &lock->len, NLM_MAXSTRLEN))
311          || !(p = nlm4_decode_fh(p, &lock->fh))
312          || !(p = nlm4_decode_oh(p, &lock->oh)))
313                 return 0;
314         argp->fsm_mode = ntohl(*p++);
315         argp->fsm_access = ntohl(*p++);
316         return xdr_argsize_check(rqstp, p);
317 }
318
319 int
320 nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
321 {
322         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
323                 return 0;
324         *p++ = resp->status;
325         *p++ = xdr_zero;                /* sequence argument */
326         return xdr_ressize_check(rqstp, p);
327 }
328
329 int
330 nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
331 {
332         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
333                 return 0;
334         *p++ = resp->status;
335         return xdr_ressize_check(rqstp, p);
336 }
337
338 int
339 nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
340 {
341         struct nlm_lock *lock = &argp->lock;
342
343         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
344                                             &lock->len, NLM_MAXSTRLEN)))
345                 return 0;
346         argp->state = ntohl(*p++);
347         return xdr_argsize_check(rqstp, p);
348 }
349
350 int
351 nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
352 {
353         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
354                 return 0;
355         argp->state = ntohl(*p++);
356         /* Preserve the address in network byte order */
357         argp->addr  = *p++;
358         argp->vers  = *p++;
359         argp->proto = *p++;
360         return xdr_argsize_check(rqstp, p);
361 }
362
363 int
364 nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
365 {
366         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
367                 return 0;
368         resp->status = ntohl(*p++);
369         return xdr_argsize_check(rqstp, p);
370 }
371
372 int
373 nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
374 {
375         return xdr_argsize_check(rqstp, p);
376 }
377
378 int
379 nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
380 {
381         return xdr_ressize_check(rqstp, p);
382 }
383
384 /*
385  * Now, the client side XDR functions
386  */
387 #ifdef NLMCLNT_SUPPORT_SHARES
388 static int
389 nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
390 {
391         return 0;
392 }
393 #endif
394
395 static int
396 nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
397 {
398         struct nlm_lock *lock = &argp->lock;
399
400         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
401                 return -EIO;
402         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
403         if (!(p = nlm4_encode_lock(p, lock)))
404                 return -EIO;
405         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
406         return 0;
407 }
408
409 static int
410 nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
411 {
412         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
413                 return -EIO;
414         resp->status = ntohl(*p++);
415         if (resp->status == NLM_LCK_DENIED) {
416                 struct file_lock        *fl = &resp->lock.fl;
417                 u32                     excl;
418                 s64                     start, end, len;
419
420                 memset(&resp->lock, 0, sizeof(resp->lock));
421                 locks_init_lock(fl);
422                 excl = ntohl(*p++);
423                 fl->fl_pid = ntohl(*p++);
424                 if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
425                         return -EIO;
426
427                 fl->fl_flags = FL_POSIX;
428                 fl->fl_type  = excl? F_WRLCK : F_RDLCK;
429                 p = xdr_decode_hyper(p, &start);
430                 p = xdr_decode_hyper(p, &len);
431                 end = start + len - 1;
432
433                 fl->fl_start = s64_to_loff_t(start);
434                 if (len == 0 || end < 0)
435                         fl->fl_end = OFFSET_MAX;
436                 else
437                         fl->fl_end = s64_to_loff_t(end);
438         }
439         return 0;
440 }
441
442
443 static int
444 nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
445 {
446         struct nlm_lock *lock = &argp->lock;
447
448         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
449                 return -EIO;
450         *p++ = argp->block? xdr_one : xdr_zero;
451         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
452         if (!(p = nlm4_encode_lock(p, lock)))
453                 return -EIO;
454         *p++ = argp->reclaim? xdr_one : xdr_zero;
455         *p++ = htonl(argp->state);
456         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
457         return 0;
458 }
459
460 static int
461 nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
462 {
463         struct nlm_lock *lock = &argp->lock;
464
465         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
466                 return -EIO;
467         *p++ = argp->block? xdr_one : xdr_zero;
468         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
469         if (!(p = nlm4_encode_lock(p, lock)))
470                 return -EIO;
471         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
472         return 0;
473 }
474
475 static int
476 nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
477 {
478         struct nlm_lock *lock = &argp->lock;
479
480         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
481                 return -EIO;
482         if (!(p = nlm4_encode_lock(p, lock)))
483                 return -EIO;
484         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
485         return 0;
486 }
487
488 static int
489 nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
490 {
491         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
492                 return -EIO;
493         *p++ = resp->status;
494         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
495         return 0;
496 }
497
498 static int
499 nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
500 {
501         if (!(p = nlm4_encode_testres(p, resp)))
502                 return -EIO;
503         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
504         return 0;
505 }
506
507 static int
508 nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
509 {
510         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
511                 return -EIO;
512         resp->status = ntohl(*p++);
513         return 0;
514 }
515
516 /*
517  * Buffer requirements for NLM
518  */
519 #define NLM4_void_sz            0
520 #define NLM4_cookie_sz          1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
521 #define NLM4_caller_sz          1+XDR_QUADLEN(NLM_MAXSTRLEN)
522 #define NLM4_netobj_sz          1+XDR_QUADLEN(XDR_MAX_NETOBJ)
523 /* #define NLM4_owner_sz                1+XDR_QUADLEN(NLM4_MAXOWNER) */
524 #define NLM4_fhandle_sz         1+XDR_QUADLEN(NFS3_FHSIZE)
525 #define NLM4_lock_sz            5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
526 #define NLM4_holder_sz          6+NLM4_netobj_sz
527
528 #define NLM4_testargs_sz        NLM4_cookie_sz+1+NLM4_lock_sz
529 #define NLM4_lockargs_sz        NLM4_cookie_sz+4+NLM4_lock_sz
530 #define NLM4_cancargs_sz        NLM4_cookie_sz+2+NLM4_lock_sz
531 #define NLM4_unlockargs_sz      NLM4_cookie_sz+NLM4_lock_sz
532
533 #define NLM4_testres_sz         NLM4_cookie_sz+1+NLM4_holder_sz
534 #define NLM4_res_sz             NLM4_cookie_sz+1
535 #define NLM4_norep_sz           0
536
537 #ifndef MAX
538 # define MAX(a,b)               (((a) > (b))? (a) : (b))
539 #endif
540
541 /*
542  * For NLM, a void procedure really returns nothing
543  */
544 #define nlm4clt_decode_norep    NULL
545
546 #define PROC(proc, argtype, restype)                                    \
547 [NLMPROC_##proc] = {                                                    \
548         .p_proc      = NLMPROC_##proc,                                  \
549         .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,           \
550         .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,           \
551         .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2       \
552         }
553
554 static struct rpc_procinfo      nlm4_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 struct rpc_version      nlm_version4 = {
579         .number         = 4,
580         .nrprocs        = 24,
581         .procs          = nlm4_procedures,
582 };