upgrade to linux 2.6.10-1.12_FC2
[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
361         return xdr_argsize_check(rqstp, p);
362 }
363
364 int
365 nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
366 {
367         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
368                 return 0;
369         resp->status = ntohl(*p++);
370         return xdr_argsize_check(rqstp, p);
371 }
372
373 int
374 nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
375 {
376         return xdr_argsize_check(rqstp, p);
377 }
378
379 int
380 nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
381 {
382         return xdr_ressize_check(rqstp, p);
383 }
384
385 /*
386  * Now, the client side XDR functions
387  */
388 #ifdef NLMCLNT_SUPPORT_SHARES
389 static int
390 nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
391 {
392         return 0;
393 }
394 #endif
395
396 static int
397 nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
398 {
399         struct nlm_lock *lock = &argp->lock;
400
401         if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
402                 return -EIO;
403         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
404         if (!(p = nlm4_encode_lock(p, lock)))
405                 return -EIO;
406         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407         return 0;
408 }
409
410 static int
411 nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
412 {
413         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
414                 return -EIO;
415         resp->status = ntohl(*p++);
416         if (resp->status == NLM_LCK_DENIED) {
417                 struct file_lock        *fl = &resp->lock.fl;
418                 u32                     excl;
419                 s64                     start, end, len;
420
421                 memset(&resp->lock, 0, sizeof(resp->lock));
422                 locks_init_lock(fl);
423                 excl = ntohl(*p++);
424                 fl->fl_pid = ntohl(*p++);
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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *p, struct nlm_res *resp)
510 {
511         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
512                 return -EIO;
513         resp->status = ntohl(*p++);
514         return 0;
515 }
516
517 /*
518  * Buffer requirements for NLM
519  */
520 #define NLM4_void_sz            0
521 #define NLM4_cookie_sz          1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
522 #define NLM4_caller_sz          1+XDR_QUADLEN(NLM_MAXSTRLEN)
523 #define NLM4_netobj_sz          1+XDR_QUADLEN(XDR_MAX_NETOBJ)
524 /* #define NLM4_owner_sz                1+XDR_QUADLEN(NLM4_MAXOWNER) */
525 #define NLM4_fhandle_sz         1+XDR_QUADLEN(NFS3_FHSIZE)
526 #define NLM4_lock_sz            5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
527 #define NLM4_holder_sz          6+NLM4_netobj_sz
528
529 #define NLM4_testargs_sz        NLM4_cookie_sz+1+NLM4_lock_sz
530 #define NLM4_lockargs_sz        NLM4_cookie_sz+4+NLM4_lock_sz
531 #define NLM4_cancargs_sz        NLM4_cookie_sz+2+NLM4_lock_sz
532 #define NLM4_unlockargs_sz      NLM4_cookie_sz+NLM4_lock_sz
533
534 #define NLM4_testres_sz         NLM4_cookie_sz+1+NLM4_holder_sz
535 #define NLM4_res_sz             NLM4_cookie_sz+1
536 #define NLM4_norep_sz           0
537
538 #ifndef MAX
539 # define MAX(a,b)               (((a) > (b))? (a) : (b))
540 #endif
541
542 /*
543  * For NLM, a void procedure really returns nothing
544  */
545 #define nlm4clt_decode_norep    NULL
546
547 #define PROC(proc, argtype, restype)                                    \
548 [NLMPROC_##proc] = {                                                    \
549         .p_proc      = NLMPROC_##proc,                                  \
550         .p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,           \
551         .p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,           \
552         .p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2       \
553         }
554
555 static struct rpc_procinfo      nlm4_procedures[] = {
556     PROC(TEST,          testargs,       testres),
557     PROC(LOCK,          lockargs,       res),
558     PROC(CANCEL,        cancargs,       res),
559     PROC(UNLOCK,        unlockargs,     res),
560     PROC(GRANTED,       testargs,       res),
561     PROC(TEST_MSG,      testargs,       norep),
562     PROC(LOCK_MSG,      lockargs,       norep),
563     PROC(CANCEL_MSG,    cancargs,       norep),
564     PROC(UNLOCK_MSG,    unlockargs,     norep),
565     PROC(GRANTED_MSG,   testargs,       norep),
566     PROC(TEST_RES,      testres,        norep),
567     PROC(LOCK_RES,      res,            norep),
568     PROC(CANCEL_RES,    res,            norep),
569     PROC(UNLOCK_RES,    res,            norep),
570     PROC(GRANTED_RES,   res,            norep),
571 #ifdef NLMCLNT_SUPPORT_SHARES
572     PROC(SHARE,         shareargs,      shareres),
573     PROC(UNSHARE,       shareargs,      shareres),
574     PROC(NM_LOCK,       lockargs,       res),
575     PROC(FREE_ALL,      notify,         void),
576 #endif
577 };
578
579 struct rpc_version      nlm_version4 = {
580         .number         = 4,
581         .nrprocs        = 24,
582         .procs          = nlm4_procedures,
583 };