Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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         return xdr_argsize_check(rqstp, p);
359 }
360
361 int
362 nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
363 {
364         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
365                 return 0;
366         resp->status = ntohl(*p++);
367         return xdr_argsize_check(rqstp, p);
368 }
369
370 int
371 nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
372 {
373         return xdr_argsize_check(rqstp, p);
374 }
375
376 int
377 nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
378 {
379         return xdr_ressize_check(rqstp, p);
380 }
381
382 /*
383  * Now, the client side XDR functions
384  */
385 #ifdef NLMCLNT_SUPPORT_SHARES
386 static int
387 nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
388 {
389         return 0;
390 }
391 #endif
392
393 static int
394 nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
395 {
396         struct nlm_lock *lock = &argp->lock;
397
398         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
399                 return -EIO;
400         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
401         if (!(p = nlm4_encode_lock(p, lock)))
402                 return -EIO;
403         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
404         return 0;
405 }
406
407 static int
408 nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
409 {
410         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
411                 return -EIO;
412         resp->status = ntohl(*p++);
413         if (resp->status == NLM_LCK_DENIED) {
414                 struct file_lock        *fl = &resp->lock.fl;
415                 u32                     excl;
416                 s64                     start, end, len;
417
418                 memset(&resp->lock, 0, sizeof(resp->lock));
419                 locks_init_lock(fl);
420                 excl = ntohl(*p++);
421                 fl->fl_pid = ntohl(*p++);
422                 if (!(p = nlm4_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                 p = xdr_decode_hyper(p, &start);
428                 p = xdr_decode_hyper(p, &len);
429                 end = start + len - 1;
430
431                 fl->fl_start = s64_to_loff_t(start);
432                 if (len == 0 || end < 0)
433                         fl->fl_end = OFFSET_MAX;
434                 else
435                         fl->fl_end = s64_to_loff_t(end);
436         }
437         return 0;
438 }
439
440
441 static int
442 nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
443 {
444         struct nlm_lock *lock = &argp->lock;
445
446         if (!(p = nlm4_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 = nlm4_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 nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
460 {
461         struct nlm_lock *lock = &argp->lock;
462
463         if (!(p = nlm4_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 = nlm4_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 nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
475 {
476         struct nlm_lock *lock = &argp->lock;
477
478         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
479                 return -EIO;
480         if (!(p = nlm4_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 nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
488 {
489         if (!(p = nlm4_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 nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
498 {
499         if (!(p = nlm4_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 nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
507 {
508         if (!(p = nlm4_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 NLM4_void_sz            0
518 #define NLM4_cookie_sz          1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
519 #define NLM4_caller_sz          1+XDR_QUADLEN(NLM_MAXSTRLEN)
520 #define NLM4_netobj_sz          1+XDR_QUADLEN(XDR_MAX_NETOBJ)
521 /* #define NLM4_owner_sz                1+XDR_QUADLEN(NLM4_MAXOWNER) */
522 #define NLM4_fhandle_sz         1+XDR_QUADLEN(NFS3_FHSIZE)
523 #define NLM4_lock_sz            5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
524 #define NLM4_holder_sz          6+NLM4_netobj_sz
525
526 #define NLM4_testargs_sz        NLM4_cookie_sz+1+NLM4_lock_sz
527 #define NLM4_lockargs_sz        NLM4_cookie_sz+4+NLM4_lock_sz
528 #define NLM4_cancargs_sz        NLM4_cookie_sz+2+NLM4_lock_sz
529 #define NLM4_unlockargs_sz      NLM4_cookie_sz+NLM4_lock_sz
530
531 #define NLM4_testres_sz         NLM4_cookie_sz+1+NLM4_holder_sz
532 #define NLM4_res_sz             NLM4_cookie_sz+1
533 #define NLM4_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 nlm4clt_decode_norep    NULL
543
544 #define PROC(proc, argtype, restype)                                    \
545 [NLMPROC_##proc] = {                                                    \
546         .p_proc      = NLMPROC_##proc,                                  \
547         .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,           \
548         .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,           \
549         .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2       \
550         }
551
552 static struct rpc_procinfo      nlm4_procedures[] = {
553     PROC(TEST,          testargs,       testres),
554     PROC(LOCK,          lockargs,       res),
555     PROC(CANCEL,        cancargs,       res),
556     PROC(UNLOCK,        unlockargs,     res),
557     PROC(GRANTED,       testargs,       res),
558     PROC(TEST_MSG,      testargs,       norep),
559     PROC(LOCK_MSG,      lockargs,       norep),
560     PROC(CANCEL_MSG,    cancargs,       norep),
561     PROC(UNLOCK_MSG,    unlockargs,     norep),
562     PROC(GRANTED_MSG,   testargs,       norep),
563     PROC(TEST_RES,      testres,        norep),
564     PROC(LOCK_RES,      res,            norep),
565     PROC(CANCEL_RES,    res,            norep),
566     PROC(UNLOCK_RES,    res,            norep),
567     PROC(GRANTED_RES,   res,            norep),
568 #ifdef NLMCLNT_SUPPORT_SHARES
569     PROC(SHARE,         shareargs,      shareres),
570     PROC(UNSHARE,       shareargs,      shareres),
571     PROC(NM_LOCK,       lockargs,       res),
572     PROC(FREE_ALL,      notify,         void),
573 #endif
574 };
575
576 struct rpc_version      nlm_version4 = {
577         .number         = 4,
578         .nrprocs        = 24,
579         .procs          = nlm4_procedures,
580 };