headers: utsname.h redux
[linux-2.6.git] / fs / lockd / xdr.c
1 /*
2  * linux/fs/lockd/xdr.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs.h>
12
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/svc.h>
16 #include <linux/sunrpc/stats.h>
17 #include <linux/lockd/lockd.h>
18
19 #define NLMDBG_FACILITY         NLMDBG_XDR
20
21
22 static inline loff_t
23 s32_to_loff_t(__s32 offset)
24 {
25         return (loff_t)offset;
26 }
27
28 static inline __s32
29 loff_t_to_s32(loff_t offset)
30 {
31         __s32 res;
32         if (offset >= NLM_OFFSET_MAX)
33                 res = NLM_OFFSET_MAX;
34         else if (offset <= -NLM_OFFSET_MAX)
35                 res = -NLM_OFFSET_MAX;
36         else
37                 res = offset;
38         return res;
39 }
40
41 /*
42  * XDR functions for basic NLM types
43  */
44 static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
45 {
46         unsigned int    len;
47
48         len = ntohl(*p++);
49         
50         if(len==0)
51         {
52                 c->len=4;
53                 memset(c->data, 0, 4);  /* hockeypux brain damage */
54         }
55         else if(len<=NLM_MAXCOOKIELEN)
56         {
57                 c->len=len;
58                 memcpy(c->data, p, len);
59                 p+=XDR_QUADLEN(len);
60         }
61         else 
62         {
63                 dprintk("lockd: bad cookie size %d (only cookies under "
64                         "%d bytes are supported.)\n",
65                                 len, NLM_MAXCOOKIELEN);
66                 return NULL;
67         }
68         return p;
69 }
70
71 static inline __be32 *
72 nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
73 {
74         *p++ = htonl(c->len);
75         memcpy(p, c->data, c->len);
76         p+=XDR_QUADLEN(c->len);
77         return p;
78 }
79
80 static __be32 *
81 nlm_decode_fh(__be32 *p, struct nfs_fh *f)
82 {
83         unsigned int    len;
84
85         if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
86                 dprintk("lockd: bad fhandle size %d (should be %d)\n",
87                         len, NFS2_FHSIZE);
88                 return NULL;
89         }
90         f->size = NFS2_FHSIZE;
91         memset(f->data, 0, sizeof(f->data));
92         memcpy(f->data, p, NFS2_FHSIZE);
93         return p + XDR_QUADLEN(NFS2_FHSIZE);
94 }
95
96 static inline __be32 *
97 nlm_encode_fh(__be32 *p, struct nfs_fh *f)
98 {
99         *p++ = htonl(NFS2_FHSIZE);
100         memcpy(p, f->data, NFS2_FHSIZE);
101         return p + XDR_QUADLEN(NFS2_FHSIZE);
102 }
103
104 /*
105  * Encode and decode owner handle
106  */
107 static inline __be32 *
108 nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
109 {
110         return xdr_decode_netobj(p, oh);
111 }
112
113 static inline __be32 *
114 nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
115 {
116         return xdr_encode_netobj(p, oh);
117 }
118
119 static __be32 *
120 nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
121 {
122         struct file_lock        *fl = &lock->fl;
123         s32                     start, len, end;
124
125         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
126                                             &lock->len,
127                                             NLM_MAXSTRLEN))
128          || !(p = nlm_decode_fh(p, &lock->fh))
129          || !(p = nlm_decode_oh(p, &lock->oh)))
130                 return NULL;
131         lock->svid  = ntohl(*p++);
132
133         locks_init_lock(fl);
134         fl->fl_owner = current->files;
135         fl->fl_pid   = (pid_t)lock->svid;
136         fl->fl_flags = FL_POSIX;
137         fl->fl_type  = F_RDLCK;         /* as good as anything else */
138         start = ntohl(*p++);
139         len = ntohl(*p++);
140         end = start + len - 1;
141
142         fl->fl_start = s32_to_loff_t(start);
143
144         if (len == 0 || end < 0)
145                 fl->fl_end = OFFSET_MAX;
146         else
147                 fl->fl_end = s32_to_loff_t(end);
148         return p;
149 }
150
151 /*
152  * Encode a lock as part of an NLM call
153  */
154 static __be32 *
155 nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
156 {
157         struct file_lock        *fl = &lock->fl;
158         __s32                   start, len;
159
160         if (!(p = xdr_encode_string(p, lock->caller))
161          || !(p = nlm_encode_fh(p, &lock->fh))
162          || !(p = nlm_encode_oh(p, &lock->oh)))
163                 return NULL;
164
165         if (fl->fl_start > NLM_OFFSET_MAX
166          || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
167                 return NULL;
168
169         start = loff_t_to_s32(fl->fl_start);
170         if (fl->fl_end == OFFSET_MAX)
171                 len = 0;
172         else
173                 len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
174
175         *p++ = htonl(lock->svid);
176         *p++ = htonl(start);
177         *p++ = htonl(len);
178
179         return p;
180 }
181
182 /*
183  * Encode result of a TEST/TEST_MSG call
184  */
185 static __be32 *
186 nlm_encode_testres(__be32 *p, struct nlm_res *resp)
187 {
188         s32             start, len;
189
190         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
191                 return NULL;
192         *p++ = resp->status;
193
194         if (resp->status == nlm_lck_denied) {
195                 struct file_lock        *fl = &resp->lock.fl;
196
197                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
198                 *p++ = htonl(resp->lock.svid);
199
200                 /* Encode owner handle. */
201                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
202                         return NULL;
203
204                 start = loff_t_to_s32(fl->fl_start);
205                 if (fl->fl_end == OFFSET_MAX)
206                         len = 0;
207                 else
208                         len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
209
210                 *p++ = htonl(start);
211                 *p++ = htonl(len);
212         }
213
214         return p;
215 }
216
217
218 /*
219  * First, the server side XDR functions
220  */
221 int
222 nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
223 {
224         u32     exclusive;
225
226         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
227                 return 0;
228
229         exclusive = ntohl(*p++);
230         if (!(p = nlm_decode_lock(p, &argp->lock)))
231                 return 0;
232         if (exclusive)
233                 argp->lock.fl.fl_type = F_WRLCK;
234
235         return xdr_argsize_check(rqstp, p);
236 }
237
238 int
239 nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
240 {
241         if (!(p = nlm_encode_testres(p, resp)))
242                 return 0;
243         return xdr_ressize_check(rqstp, p);
244 }
245
246 int
247 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
248 {
249         u32     exclusive;
250
251         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
252                 return 0;
253         argp->block  = ntohl(*p++);
254         exclusive    = ntohl(*p++);
255         if (!(p = nlm_decode_lock(p, &argp->lock)))
256                 return 0;
257         if (exclusive)
258                 argp->lock.fl.fl_type = F_WRLCK;
259         argp->reclaim = ntohl(*p++);
260         argp->state   = ntohl(*p++);
261         argp->monitor = 1;              /* monitor client by default */
262
263         return xdr_argsize_check(rqstp, p);
264 }
265
266 int
267 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
268 {
269         u32     exclusive;
270
271         if (!(p = nlm_decode_cookie(p, &argp->cookie)))
272                 return 0;
273         argp->block = ntohl(*p++);
274         exclusive = ntohl(*p++);
275         if (!(p = nlm_decode_lock(p, &argp->lock)))
276                 return 0;
277         if (exclusive)
278                 argp->lock.fl.fl_type = F_WRLCK;
279         return xdr_argsize_check(rqstp, p);
280 }
281
282 int
283 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
284 {
285         if (!(p = nlm_decode_cookie(p, &argp->cookie))
286          || !(p = nlm_decode_lock(p, &argp->lock)))
287                 return 0;
288         argp->lock.fl.fl_type = F_UNLCK;
289         return xdr_argsize_check(rqstp, p);
290 }
291
292 int
293 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
294 {
295         struct nlm_lock *lock = &argp->lock;
296
297         memset(lock, 0, sizeof(*lock));
298         locks_init_lock(&lock->fl);
299         lock->svid = ~(u32) 0;
300         lock->fl.fl_pid = (pid_t)lock->svid;
301
302         if (!(p = nlm_decode_cookie(p, &argp->cookie))
303          || !(p = xdr_decode_string_inplace(p, &lock->caller,
304                                             &lock->len, NLM_MAXSTRLEN))
305          || !(p = nlm_decode_fh(p, &lock->fh))
306          || !(p = nlm_decode_oh(p, &lock->oh)))
307                 return 0;
308         argp->fsm_mode = ntohl(*p++);
309         argp->fsm_access = ntohl(*p++);
310         return xdr_argsize_check(rqstp, p);
311 }
312
313 int
314 nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
315 {
316         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
317                 return 0;
318         *p++ = resp->status;
319         *p++ = xdr_zero;                /* sequence argument */
320         return xdr_ressize_check(rqstp, p);
321 }
322
323 int
324 nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
325 {
326         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
327                 return 0;
328         *p++ = resp->status;
329         return xdr_ressize_check(rqstp, p);
330 }
331
332 int
333 nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
334 {
335         struct nlm_lock *lock = &argp->lock;
336
337         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
338                                             &lock->len, NLM_MAXSTRLEN)))
339                 return 0;
340         argp->state = ntohl(*p++);
341         return xdr_argsize_check(rqstp, p);
342 }
343
344 int
345 nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
346 {
347         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
348                 return 0;
349         argp->state = ntohl(*p++);
350         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
351         p += XDR_QUADLEN(SM_PRIV_SIZE);
352         return xdr_argsize_check(rqstp, p);
353 }
354
355 int
356 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
357 {
358         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
359                 return 0;
360         resp->status = *p++;
361         return xdr_argsize_check(rqstp, p);
362 }
363
364 int
365 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
366 {
367         return xdr_argsize_check(rqstp, p);
368 }
369
370 int
371 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
372 {
373         return xdr_ressize_check(rqstp, p);
374 }
375
376 /*
377  * Now, the client side XDR functions
378  */
379 #ifdef NLMCLNT_SUPPORT_SHARES
380 static int
381 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
382 {
383         return 0;
384 }
385 #endif
386
387 static int
388 nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
389 {
390         struct nlm_lock *lock = &argp->lock;
391
392         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
393                 return -EIO;
394         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
395         if (!(p = nlm_encode_lock(p, lock)))
396                 return -EIO;
397         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
398         return 0;
399 }
400
401 static int
402 nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
403 {
404         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
405                 return -EIO;
406         resp->status = *p++;
407         if (resp->status == nlm_lck_denied) {
408                 struct file_lock        *fl = &resp->lock.fl;
409                 u32                     excl;
410                 s32                     start, len, end;
411
412                 memset(&resp->lock, 0, sizeof(resp->lock));
413                 locks_init_lock(fl);
414                 excl = ntohl(*p++);
415                 resp->lock.svid = ntohl(*p++);
416                 fl->fl_pid = (pid_t)resp->lock.svid;
417                 if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
418                         return -EIO;
419
420                 fl->fl_flags = FL_POSIX;
421                 fl->fl_type  = excl? F_WRLCK : F_RDLCK;
422                 start = ntohl(*p++);
423                 len = ntohl(*p++);
424                 end = start + len - 1;
425
426                 fl->fl_start = s32_to_loff_t(start);
427                 if (len == 0 || end < 0)
428                         fl->fl_end = OFFSET_MAX;
429                 else
430                         fl->fl_end = s32_to_loff_t(end);
431         }
432         return 0;
433 }
434
435
436 static int
437 nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
438 {
439         struct nlm_lock *lock = &argp->lock;
440
441         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
442                 return -EIO;
443         *p++ = argp->block? xdr_one : xdr_zero;
444         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
445         if (!(p = nlm_encode_lock(p, lock)))
446                 return -EIO;
447         *p++ = argp->reclaim? xdr_one : xdr_zero;
448         *p++ = htonl(argp->state);
449         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
450         return 0;
451 }
452
453 static int
454 nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
455 {
456         struct nlm_lock *lock = &argp->lock;
457
458         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
459                 return -EIO;
460         *p++ = argp->block? xdr_one : xdr_zero;
461         *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
462         if (!(p = nlm_encode_lock(p, lock)))
463                 return -EIO;
464         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
465         return 0;
466 }
467
468 static int
469 nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
470 {
471         struct nlm_lock *lock = &argp->lock;
472
473         if (!(p = nlm_encode_cookie(p, &argp->cookie)))
474                 return -EIO;
475         if (!(p = nlm_encode_lock(p, lock)))
476                 return -EIO;
477         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
478         return 0;
479 }
480
481 static int
482 nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
483 {
484         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
485                 return -EIO;
486         *p++ = resp->status;
487         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
488         return 0;
489 }
490
491 static int
492 nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
493 {
494         if (!(p = nlm_encode_testres(p, resp)))
495                 return -EIO;
496         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
497         return 0;
498 }
499
500 static int
501 nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
502 {
503         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
504                 return -EIO;
505         resp->status = *p++;
506         return 0;
507 }
508
509 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
510 #  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
511 #endif
512
513 /*
514  * Buffer requirements for NLM
515  */
516 #define NLM_void_sz             0
517 #define NLM_cookie_sz           1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
518 #define NLM_caller_sz           1+XDR_QUADLEN(NLMCLNT_OHSIZE)
519 #define NLM_owner_sz            1+XDR_QUADLEN(NLMCLNT_OHSIZE)
520 #define NLM_fhandle_sz          1+XDR_QUADLEN(NFS2_FHSIZE)
521 #define NLM_lock_sz             3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
522 #define NLM_holder_sz           4+NLM_owner_sz
523
524 #define NLM_testargs_sz         NLM_cookie_sz+1+NLM_lock_sz
525 #define NLM_lockargs_sz         NLM_cookie_sz+4+NLM_lock_sz
526 #define NLM_cancargs_sz         NLM_cookie_sz+2+NLM_lock_sz
527 #define NLM_unlockargs_sz       NLM_cookie_sz+NLM_lock_sz
528
529 #define NLM_testres_sz          NLM_cookie_sz+1+NLM_holder_sz
530 #define NLM_res_sz              NLM_cookie_sz+1
531 #define NLM_norep_sz            0
532
533 /*
534  * For NLM, a void procedure really returns nothing
535  */
536 #define nlmclt_decode_norep     NULL
537
538 #define PROC(proc, argtype, restype)    \
539 [NLMPROC_##proc] = {                                                    \
540         .p_proc      = NLMPROC_##proc,                                  \
541         .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,            \
542         .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,            \
543         .p_arglen    = NLM_##argtype##_sz,                              \
544         .p_replen    = NLM_##restype##_sz,                              \
545         .p_statidx   = NLMPROC_##proc,                                  \
546         .p_name      = #proc,                                           \
547         }
548
549 static struct rpc_procinfo      nlm_procedures[] = {
550     PROC(TEST,          testargs,       testres),
551     PROC(LOCK,          lockargs,       res),
552     PROC(CANCEL,        cancargs,       res),
553     PROC(UNLOCK,        unlockargs,     res),
554     PROC(GRANTED,       testargs,       res),
555     PROC(TEST_MSG,      testargs,       norep),
556     PROC(LOCK_MSG,      lockargs,       norep),
557     PROC(CANCEL_MSG,    cancargs,       norep),
558     PROC(UNLOCK_MSG,    unlockargs,     norep),
559     PROC(GRANTED_MSG,   testargs,       norep),
560     PROC(TEST_RES,      testres,        norep),
561     PROC(LOCK_RES,      res,            norep),
562     PROC(CANCEL_RES,    res,            norep),
563     PROC(UNLOCK_RES,    res,            norep),
564     PROC(GRANTED_RES,   res,            norep),
565 #ifdef NLMCLNT_SUPPORT_SHARES
566     PROC(SHARE,         shareargs,      shareres),
567     PROC(UNSHARE,       shareargs,      shareres),
568     PROC(NM_LOCK,       lockargs,       res),
569     PROC(FREE_ALL,      notify,         void),
570 #endif
571 };
572
573 static struct rpc_version       nlm_version1 = {
574                 .number         = 1,
575                 .nrprocs        = 16,
576                 .procs          = nlm_procedures,
577 };
578
579 static struct rpc_version       nlm_version3 = {
580                 .number         = 3,
581                 .nrprocs        = 24,
582                 .procs          = nlm_procedures,
583 };
584
585 static struct rpc_version *     nlm_versions[] = {
586         [1] = &nlm_version1,
587         [3] = &nlm_version3,
588 #ifdef  CONFIG_LOCKD_V4
589         [4] = &nlm_version4,
590 #endif
591 };
592
593 static struct rpc_stat          nlm_stats;
594
595 struct rpc_program              nlm_program = {
596                 .name           = "lockd",
597                 .number         = NLM_PROGRAM,
598                 .nrvers         = ARRAY_SIZE(nlm_versions),
599                 .version        = nlm_versions,
600                 .stats          = &nlm_stats,
601 };
602
603 #ifdef RPC_DEBUG
604 const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
605 {
606         /*
607          * We can get away with a static buffer because we're only
608          * called with BKL held.
609          */
610         static char buf[2*NLM_MAXCOOKIELEN+1];
611         unsigned int i, len = sizeof(buf);
612         char *p = buf;
613
614         len--;  /* allow for trailing \0 */
615         if (len < 3)
616                 return "???";
617         for (i = 0 ; i < cookie->len ; i++) {
618                 if (len < 2) {
619                         strcpy(p-3, "...");
620                         break;
621                 }
622                 sprintf(p, "%02x", cookie->data[i]);
623                 p += 2;
624                 len -= 2;
625         }
626         *p = '\0';
627
628         return buf;
629 }
630 #endif