VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / net / sunrpc / xdr.c
1 /*
2  * linux/net/sunrpc/xdr.c
3  *
4  * Generic XDR support.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/types.h>
10 #include <linux/socket.h>
11 #include <linux/string.h>
12 #include <linux/kernel.h>
13 #include <linux/pagemap.h>
14 #include <linux/errno.h>
15 #include <linux/in.h>
16 #include <linux/net.h>
17 #include <net/sock.h>
18 #include <linux/sunrpc/xdr.h>
19 #include <linux/sunrpc/msg_prot.h>
20
21 /*
22  * XDR functions for basic NFS types
23  */
24 u32 *
25 xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
26 {
27         unsigned int    quadlen = XDR_QUADLEN(obj->len);
28
29         p[quadlen] = 0;         /* zero trailing bytes */
30         *p++ = htonl(obj->len);
31         memcpy(p, obj->data, obj->len);
32         return p + XDR_QUADLEN(obj->len);
33 }
34
35 u32 *
36 xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len)
37 {
38         if (ntohl(*p++) != len)
39                 return NULL;
40         memcpy(obj, p, len);
41         return p + XDR_QUADLEN(len);
42 }
43
44 u32 *
45 xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
46 {
47         unsigned int    len;
48
49         if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ)
50                 return NULL;
51         obj->len  = len;
52         obj->data = (u8 *) p;
53         return p + XDR_QUADLEN(len);
54 }
55
56 /**
57  * xdr_encode_opaque_fixed - Encode fixed length opaque data
58  * @p - pointer to current position in XDR buffer.
59  * @ptr - pointer to data to encode (or NULL)
60  * @nbytes - size of data.
61  *
62  * Copy the array of data of length nbytes at ptr to the XDR buffer
63  * at position p, then align to the next 32-bit boundary by padding
64  * with zero bytes (see RFC1832).
65  * Note: if ptr is NULL, only the padding is performed.
66  *
67  * Returns the updated current XDR buffer position
68  *
69  */
70 u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
71 {
72         if (likely(nbytes != 0)) {
73                 unsigned int quadlen = XDR_QUADLEN(nbytes);
74                 unsigned int padding = (quadlen << 2) - nbytes;
75
76                 if (ptr != NULL)
77                         memcpy(p, ptr, nbytes);
78                 if (padding != 0)
79                         memset((char *)p + nbytes, 0, padding);
80                 p += quadlen;
81         }
82         return p;
83 }
84 EXPORT_SYMBOL(xdr_encode_opaque_fixed);
85
86 /**
87  * xdr_encode_opaque - Encode variable length opaque data
88  * @p - pointer to current position in XDR buffer.
89  * @ptr - pointer to data to encode (or NULL)
90  * @nbytes - size of data.
91  *
92  * Returns the updated current XDR buffer position
93  */
94 u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
95 {
96         *p++ = htonl(nbytes);
97         return xdr_encode_opaque_fixed(p, ptr, nbytes);
98 }
99 EXPORT_SYMBOL(xdr_encode_opaque);
100
101 u32 *
102 xdr_encode_string(u32 *p, const char *string)
103 {
104         return xdr_encode_array(p, string, strlen(string));
105 }
106
107 u32 *
108 xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
109 {
110         unsigned int    len;
111         char            *string;
112
113         if ((len = ntohl(*p++)) > maxlen)
114                 return NULL;
115         if (lenp)
116                 *lenp = len;
117         if ((len % 4) != 0) {
118                 string = (char *) p;
119         } else {
120                 string = (char *) (p - 1);
121                 memmove(string, p, len);
122         }
123         string[len] = '\0';
124         *sp = string;
125         return p + XDR_QUADLEN(len);
126 }
127
128 u32 *
129 xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
130 {
131         unsigned int    len;
132
133         if ((len = ntohl(*p++)) > maxlen)
134                 return NULL;
135         *lenp = len;
136         *sp = (char *) p;
137         return p + XDR_QUADLEN(len);
138 }
139
140 void
141 xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
142                  unsigned int len)
143 {
144         struct kvec *tail = xdr->tail;
145         u32 *p;
146
147         xdr->pages = pages;
148         xdr->page_base = base;
149         xdr->page_len = len;
150
151         p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
152         tail->iov_base = p;
153         tail->iov_len = 0;
154
155         if (len & 3) {
156                 unsigned int pad = 4 - (len & 3);
157
158                 *p = 0;
159                 tail->iov_base = (char *)p + (len & 3);
160                 tail->iov_len  = pad;
161                 len += pad;
162         }
163         xdr->buflen += len;
164         xdr->len += len;
165 }
166
167 void
168 xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
169                  struct page **pages, unsigned int base, unsigned int len)
170 {
171         struct kvec *head = xdr->head;
172         struct kvec *tail = xdr->tail;
173         char *buf = (char *)head->iov_base;
174         unsigned int buflen = head->iov_len;
175
176         head->iov_len  = offset;
177
178         xdr->pages = pages;
179         xdr->page_base = base;
180         xdr->page_len = len;
181
182         tail->iov_base = buf + offset;
183         tail->iov_len = buflen - offset;
184
185         xdr->buflen += len;
186 }
187
188 /*
189  * Realign the kvec if the server missed out some reply elements
190  * (such as post-op attributes,...)
191  * Note: This is a simple implementation that assumes that
192  *            len <= iov->iov_len !!!
193  *       The RPC header (assumed to be the 1st element in the iov array)
194  *            is not shifted.
195  */
196 void xdr_shift_iovec(struct kvec *iov, int nr, size_t len)
197 {
198         struct kvec *pvec;
199
200         for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
201                 struct kvec *svec = pvec - 1;
202
203                 if (len > pvec->iov_len) {
204                         printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
205                         return;
206                 }
207                 memmove((char *)pvec->iov_base + len, pvec->iov_base,
208                         pvec->iov_len - len);
209
210                 if (len > svec->iov_len) {
211                         printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
212                         return;
213                 }
214                 memcpy(pvec->iov_base,
215                        (char *)svec->iov_base + svec->iov_len - len, len);
216         }
217 }
218
219 /*
220  * Map a struct xdr_buf into an kvec array.
221  */
222 int xdr_kmap(struct kvec *iov_base, struct xdr_buf *xdr, size_t base)
223 {
224         struct kvec     *iov = iov_base;
225         struct page     **ppage = xdr->pages;
226         unsigned int    len, pglen = xdr->page_len;
227
228         len = xdr->head[0].iov_len;
229         if (base < len) {
230                 iov->iov_len = len - base;
231                 iov->iov_base = (char *)xdr->head[0].iov_base + base;
232                 iov++;
233                 base = 0;
234         } else
235                 base -= len;
236
237         if (pglen == 0)
238                 goto map_tail;
239         if (base >= pglen) {
240                 base -= pglen;
241                 goto map_tail;
242         }
243         if (base || xdr->page_base) {
244                 pglen -= base;
245                 base  += xdr->page_base;
246                 ppage += base >> PAGE_CACHE_SHIFT;
247                 base &= ~PAGE_CACHE_MASK;
248         }
249         do {
250                 len = PAGE_CACHE_SIZE;
251                 iov->iov_base = kmap(*ppage);
252                 if (base) {
253                         iov->iov_base += base;
254                         len -= base;
255                         base = 0;
256                 }
257                 if (pglen < len)
258                         len = pglen;
259                 iov->iov_len = len;
260                 iov++;
261                 ppage++;
262         } while ((pglen -= len) != 0);
263 map_tail:
264         if (xdr->tail[0].iov_len) {
265                 iov->iov_len = xdr->tail[0].iov_len - base;
266                 iov->iov_base = (char *)xdr->tail[0].iov_base + base;
267                 iov++;
268         }
269         return (iov - iov_base);
270 }
271
272 void xdr_kunmap(struct xdr_buf *xdr, size_t base)
273 {
274         struct page     **ppage = xdr->pages;
275         unsigned int    pglen = xdr->page_len;
276
277         if (!pglen)
278                 return;
279         if (base > xdr->head[0].iov_len)
280                 base -= xdr->head[0].iov_len;
281         else
282                 base = 0;
283
284         if (base >= pglen)
285                 return;
286         if (base || xdr->page_base) {
287                 pglen -= base;
288                 base  += xdr->page_base;
289                 ppage += base >> PAGE_CACHE_SHIFT;
290                 /* Note: The offset means that the length of the first
291                  * page is really (PAGE_CACHE_SIZE - (base & ~PAGE_CACHE_MASK)).
292                  * In order to avoid an extra test inside the loop,
293                  * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */
294                 pglen += base & ~PAGE_CACHE_MASK;
295         }
296         for (;;) {
297                 flush_dcache_page(*ppage);
298                 kunmap(*ppage);
299                 if (pglen <= PAGE_CACHE_SIZE)
300                         break;
301                 pglen -= PAGE_CACHE_SIZE;
302                 ppage++;
303         }
304 }
305
306 void
307 xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
308                           skb_reader_t *desc,
309                           skb_read_actor_t copy_actor)
310 {
311         struct page     **ppage = xdr->pages;
312         unsigned int    len, pglen = xdr->page_len;
313         int             ret;
314
315         len = xdr->head[0].iov_len;
316         if (base < len) {
317                 len -= base;
318                 ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
319                 if (ret != len || !desc->count)
320                         return;
321                 base = 0;
322         } else
323                 base -= len;
324
325         if (pglen == 0)
326                 goto copy_tail;
327         if (base >= pglen) {
328                 base -= pglen;
329                 goto copy_tail;
330         }
331         if (base || xdr->page_base) {
332                 pglen -= base;
333                 base  += xdr->page_base;
334                 ppage += base >> PAGE_CACHE_SHIFT;
335                 base &= ~PAGE_CACHE_MASK;
336         }
337         do {
338                 char *kaddr;
339
340                 len = PAGE_CACHE_SIZE;
341                 kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
342                 if (base) {
343                         len -= base;
344                         if (pglen < len)
345                                 len = pglen;
346                         ret = copy_actor(desc, kaddr + base, len);
347                         base = 0;
348                 } else {
349                         if (pglen < len)
350                                 len = pglen;
351                         ret = copy_actor(desc, kaddr, len);
352                 }
353                 flush_dcache_page(*ppage);
354                 kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
355                 if (ret != len || !desc->count)
356                         return;
357                 ppage++;
358         } while ((pglen -= len) != 0);
359 copy_tail:
360         len = xdr->tail[0].iov_len;
361         if (base < len)
362                 copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);
363 }
364
365
366 int
367 xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
368                 struct xdr_buf *xdr, unsigned int base, int msgflags)
369 {
370         struct page **ppage = xdr->pages;
371         unsigned int len, pglen = xdr->page_len;
372         int err, ret = 0;
373         ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
374
375         len = xdr->head[0].iov_len;
376         if (base < len || (addr != NULL && base == 0)) {
377                 struct kvec iov = {
378                         .iov_base = xdr->head[0].iov_base + base,
379                         .iov_len  = len - base,
380                 };
381                 struct msghdr msg = {
382                         .msg_name    = addr,
383                         .msg_namelen = addrlen,
384                         .msg_flags   = msgflags,
385                 };
386                 if (xdr->len > len)
387                         msg.msg_flags |= MSG_MORE;
388
389                 if (iov.iov_len != 0)
390                         err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
391                 else
392                         err = kernel_sendmsg(sock, &msg, NULL, 0, 0);
393                 if (ret == 0)
394                         ret = err;
395                 else if (err > 0)
396                         ret += err;
397                 if (err != iov.iov_len)
398                         goto out;
399                 base = 0;
400         } else
401                 base -= len;
402
403         if (pglen == 0)
404                 goto copy_tail;
405         if (base >= pglen) {
406                 base -= pglen;
407                 goto copy_tail;
408         }
409         if (base || xdr->page_base) {
410                 pglen -= base;
411                 base  += xdr->page_base;
412                 ppage += base >> PAGE_CACHE_SHIFT;
413                 base &= ~PAGE_CACHE_MASK;
414         }
415
416         sendpage = sock->ops->sendpage ? : sock_no_sendpage;
417         do {
418                 int flags = msgflags;
419
420                 len = PAGE_CACHE_SIZE;
421                 if (base)
422                         len -= base;
423                 if (pglen < len)
424                         len = pglen;
425
426                 if (pglen != len || xdr->tail[0].iov_len != 0)
427                         flags |= MSG_MORE;
428
429                 /* Hmm... We might be dealing with highmem pages */
430                 if (PageHighMem(*ppage))
431                         sendpage = sock_no_sendpage;
432                 err = sendpage(sock, *ppage, base, len, flags);
433                 if (ret == 0)
434                         ret = err;
435                 else if (err > 0)
436                         ret += err;
437                 if (err != len)
438                         goto out;
439                 base = 0;
440                 ppage++;
441         } while ((pglen -= len) != 0);
442 copy_tail:
443         len = xdr->tail[0].iov_len;
444         if (base < len) {
445                 struct kvec iov = {
446                         .iov_base = xdr->tail[0].iov_base + base,
447                         .iov_len  = len - base,
448                 };
449                 struct msghdr msg = {
450                         .msg_flags   = msgflags,
451                 };
452                 err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
453                 if (ret == 0)
454                         ret = err;
455                 else if (err > 0)
456                         ret += err;
457         }
458 out:
459         return ret;
460 }
461
462
463 /*
464  * Helper routines for doing 'memmove' like operations on a struct xdr_buf
465  *
466  * _shift_data_right_pages
467  * @pages: vector of pages containing both the source and dest memory area.
468  * @pgto_base: page vector address of destination
469  * @pgfrom_base: page vector address of source
470  * @len: number of bytes to copy
471  *
472  * Note: the addresses pgto_base and pgfrom_base are both calculated in
473  *       the same way:
474  *            if a memory area starts at byte 'base' in page 'pages[i]',
475  *            then its address is given as (i << PAGE_CACHE_SHIFT) + base
476  * Also note: pgfrom_base must be < pgto_base, but the memory areas
477  *      they point to may overlap.
478  */
479 static void
480 _shift_data_right_pages(struct page **pages, size_t pgto_base,
481                 size_t pgfrom_base, size_t len)
482 {
483         struct page **pgfrom, **pgto;
484         char *vfrom, *vto;
485         size_t copy;
486
487         BUG_ON(pgto_base <= pgfrom_base);
488
489         pgto_base += len;
490         pgfrom_base += len;
491
492         pgto = pages + (pgto_base >> PAGE_CACHE_SHIFT);
493         pgfrom = pages + (pgfrom_base >> PAGE_CACHE_SHIFT);
494
495         pgto_base &= ~PAGE_CACHE_MASK;
496         pgfrom_base &= ~PAGE_CACHE_MASK;
497
498         do {
499                 /* Are any pointers crossing a page boundary? */
500                 if (pgto_base == 0) {
501                         pgto_base = PAGE_CACHE_SIZE;
502                         pgto--;
503                 }
504                 if (pgfrom_base == 0) {
505                         pgfrom_base = PAGE_CACHE_SIZE;
506                         pgfrom--;
507                 }
508
509                 copy = len;
510                 if (copy > pgto_base)
511                         copy = pgto_base;
512                 if (copy > pgfrom_base)
513                         copy = pgfrom_base;
514                 pgto_base -= copy;
515                 pgfrom_base -= copy;
516
517                 vto = kmap_atomic(*pgto, KM_USER0);
518                 vfrom = kmap_atomic(*pgfrom, KM_USER1);
519                 memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
520                 kunmap_atomic(vfrom, KM_USER1);
521                 kunmap_atomic(vto, KM_USER0);
522
523         } while ((len -= copy) != 0);
524 }
525
526 /*
527  * _copy_to_pages
528  * @pages: array of pages
529  * @pgbase: page vector address of destination
530  * @p: pointer to source data
531  * @len: length
532  *
533  * Copies data from an arbitrary memory location into an array of pages
534  * The copy is assumed to be non-overlapping.
535  */
536 static void
537 _copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len)
538 {
539         struct page **pgto;
540         char *vto;
541         size_t copy;
542
543         pgto = pages + (pgbase >> PAGE_CACHE_SHIFT);
544         pgbase &= ~PAGE_CACHE_MASK;
545
546         do {
547                 copy = PAGE_CACHE_SIZE - pgbase;
548                 if (copy > len)
549                         copy = len;
550
551                 vto = kmap_atomic(*pgto, KM_USER0);
552                 memcpy(vto + pgbase, p, copy);
553                 kunmap_atomic(vto, KM_USER0);
554
555                 pgbase += copy;
556                 if (pgbase == PAGE_CACHE_SIZE) {
557                         pgbase = 0;
558                         pgto++;
559                 }
560                 p += copy;
561
562         } while ((len -= copy) != 0);
563 }
564
565 /*
566  * _copy_from_pages
567  * @p: pointer to destination
568  * @pages: array of pages
569  * @pgbase: offset of source data
570  * @len: length
571  *
572  * Copies data into an arbitrary memory location from an array of pages
573  * The copy is assumed to be non-overlapping.
574  */
575 void
576 _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
577 {
578         struct page **pgfrom;
579         char *vfrom;
580         size_t copy;
581
582         pgfrom = pages + (pgbase >> PAGE_CACHE_SHIFT);
583         pgbase &= ~PAGE_CACHE_MASK;
584
585         do {
586                 copy = PAGE_CACHE_SIZE - pgbase;
587                 if (copy > len)
588                         copy = len;
589
590                 vfrom = kmap_atomic(*pgfrom, KM_USER0);
591                 memcpy(p, vfrom + pgbase, copy);
592                 kunmap_atomic(vfrom, KM_USER0);
593
594                 pgbase += copy;
595                 if (pgbase == PAGE_CACHE_SIZE) {
596                         pgbase = 0;
597                         pgfrom++;
598                 }
599                 p += copy;
600
601         } while ((len -= copy) != 0);
602 }
603
604 /*
605  * xdr_shrink_bufhead
606  * @buf: xdr_buf
607  * @len: bytes to remove from buf->head[0]
608  *
609  * Shrinks XDR buffer's header kvec buf->head[0] by 
610  * 'len' bytes. The extra data is not lost, but is instead
611  * moved into the inlined pages and/or the tail.
612  */
613 void
614 xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
615 {
616         struct kvec *head, *tail;
617         size_t copy, offs;
618         unsigned int pglen = buf->page_len;
619
620         tail = buf->tail;
621         head = buf->head;
622         BUG_ON (len > head->iov_len);
623
624         /* Shift the tail first */
625         if (tail->iov_len != 0) {
626                 if (tail->iov_len > len) {
627                         copy = tail->iov_len - len;
628                         memmove((char *)tail->iov_base + len,
629                                         tail->iov_base, copy);
630                 }
631                 /* Copy from the inlined pages into the tail */
632                 copy = len;
633                 if (copy > pglen)
634                         copy = pglen;
635                 offs = len - copy;
636                 if (offs >= tail->iov_len)
637                         copy = 0;
638                 else if (copy > tail->iov_len - offs)
639                         copy = tail->iov_len - offs;
640                 if (copy != 0)
641                         _copy_from_pages((char *)tail->iov_base + offs,
642                                         buf->pages,
643                                         buf->page_base + pglen + offs - len,
644                                         copy);
645                 /* Do we also need to copy data from the head into the tail ? */
646                 if (len > pglen) {
647                         offs = copy = len - pglen;
648                         if (copy > tail->iov_len)
649                                 copy = tail->iov_len;
650                         memcpy(tail->iov_base,
651                                         (char *)head->iov_base +
652                                         head->iov_len - offs,
653                                         copy);
654                 }
655         }
656         /* Now handle pages */
657         if (pglen != 0) {
658                 if (pglen > len)
659                         _shift_data_right_pages(buf->pages,
660                                         buf->page_base + len,
661                                         buf->page_base,
662                                         pglen - len);
663                 copy = len;
664                 if (len > pglen)
665                         copy = pglen;
666                 _copy_to_pages(buf->pages, buf->page_base,
667                                 (char *)head->iov_base + head->iov_len - len,
668                                 copy);
669         }
670         head->iov_len -= len;
671         buf->buflen -= len;
672         /* Have we truncated the message? */
673         if (buf->len > buf->buflen)
674                 buf->len = buf->buflen;
675 }
676
677 /*
678  * xdr_shrink_pagelen
679  * @buf: xdr_buf
680  * @len: bytes to remove from buf->pages
681  *
682  * Shrinks XDR buffer's page array buf->pages by 
683  * 'len' bytes. The extra data is not lost, but is instead
684  * moved into the tail.
685  */
686 void
687 xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
688 {
689         struct kvec *tail;
690         size_t copy;
691         char *p;
692         unsigned int pglen = buf->page_len;
693
694         tail = buf->tail;
695         BUG_ON (len > pglen);
696
697         /* Shift the tail first */
698         if (tail->iov_len != 0) {
699                 p = (char *)tail->iov_base + len;
700                 if (tail->iov_len > len) {
701                         copy = tail->iov_len - len;
702                         memmove(p, tail->iov_base, copy);
703                 } else
704                         buf->buflen -= len;
705                 /* Copy from the inlined pages into the tail */
706                 copy = len;
707                 if (copy > tail->iov_len)
708                         copy = tail->iov_len;
709                 _copy_from_pages((char *)tail->iov_base,
710                                 buf->pages, buf->page_base + pglen - len,
711                                 copy);
712         }
713         buf->page_len -= len;
714         buf->buflen -= len;
715         /* Have we truncated the message? */
716         if (buf->len > buf->buflen)
717                 buf->len = buf->buflen;
718 }
719
720 void
721 xdr_shift_buf(struct xdr_buf *buf, size_t len)
722 {
723         xdr_shrink_bufhead(buf, len);
724 }
725
726 /**
727  * xdr_init_encode - Initialize a struct xdr_stream for sending data.
728  * @xdr: pointer to xdr_stream struct
729  * @buf: pointer to XDR buffer in which to encode data
730  * @p: current pointer inside XDR buffer
731  *
732  * Note: at the moment the RPC client only passes the length of our
733  *       scratch buffer in the xdr_buf's header kvec. Previously this
734  *       meant we needed to call xdr_adjust_iovec() after encoding the
735  *       data. With the new scheme, the xdr_stream manages the details
736  *       of the buffer length, and takes care of adjusting the kvec
737  *       length for us.
738  */
739 void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
740 {
741         struct kvec *iov = buf->head;
742
743         xdr->buf = buf;
744         xdr->iov = iov;
745         xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
746         buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;
747         xdr->p = p;
748 }
749 EXPORT_SYMBOL(xdr_init_encode);
750
751 /**
752  * xdr_reserve_space - Reserve buffer space for sending
753  * @xdr: pointer to xdr_stream
754  * @nbytes: number of bytes to reserve
755  *
756  * Checks that we have enough buffer space to encode 'nbytes' more
757  * bytes of data. If so, update the total xdr_buf length, and
758  * adjust the length of the current kvec.
759  */
760 uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
761 {
762         uint32_t *p = xdr->p;
763         uint32_t *q;
764
765         /* align nbytes on the next 32-bit boundary */
766         nbytes += 3;
767         nbytes &= ~3;
768         q = p + (nbytes >> 2);
769         if (unlikely(q > xdr->end || q < p))
770                 return NULL;
771         xdr->p = q;
772         xdr->iov->iov_len += nbytes;
773         xdr->buf->len += nbytes;
774         return p;
775 }
776 EXPORT_SYMBOL(xdr_reserve_space);
777
778 /**
779  * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
780  * @xdr: pointer to xdr_stream
781  * @pages: list of pages
782  * @base: offset of first byte
783  * @len: length of data in bytes
784  *
785  */
786 void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
787                  unsigned int len)
788 {
789         struct xdr_buf *buf = xdr->buf;
790         struct kvec *iov = buf->tail;
791         buf->pages = pages;
792         buf->page_base = base;
793         buf->page_len = len;
794
795         iov->iov_base = (char *)xdr->p;
796         iov->iov_len  = 0;
797         xdr->iov = iov;
798
799         if (len & 3) {
800                 unsigned int pad = 4 - (len & 3);
801
802                 BUG_ON(xdr->p >= xdr->end);
803                 iov->iov_base = (char *)xdr->p + (len & 3);
804                 iov->iov_len  += pad;
805                 len += pad;
806                 *xdr->p++ = 0;
807         }
808         buf->buflen += len;
809         buf->len += len;
810 }
811 EXPORT_SYMBOL(xdr_write_pages);
812
813 /**
814  * xdr_init_decode - Initialize an xdr_stream for decoding data.
815  * @xdr: pointer to xdr_stream struct
816  * @buf: pointer to XDR buffer from which to decode data
817  * @p: current pointer inside XDR buffer
818  */
819 void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
820 {
821         struct kvec *iov = buf->head;
822         unsigned int len = iov->iov_len;
823
824         if (len > buf->len)
825                 len = buf->len;
826         xdr->buf = buf;
827         xdr->iov = iov;
828         xdr->p = p;
829         xdr->end = (uint32_t *)((char *)iov->iov_base + len);
830 }
831 EXPORT_SYMBOL(xdr_init_decode);
832
833 /**
834  * xdr_inline_decode - Retrieve non-page XDR data to decode
835  * @xdr: pointer to xdr_stream struct
836  * @nbytes: number of bytes of data to decode
837  *
838  * Check if the input buffer is long enough to enable us to decode
839  * 'nbytes' more bytes of data starting at the current position.
840  * If so return the current pointer, then update the current
841  * pointer position.
842  */
843 uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
844 {
845         uint32_t *p = xdr->p;
846         uint32_t *q = p + XDR_QUADLEN(nbytes);
847
848         if (unlikely(q > xdr->end || q < p))
849                 return NULL;
850         xdr->p = q;
851         return p;
852 }
853 EXPORT_SYMBOL(xdr_inline_decode);
854
855 /**
856  * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
857  * @xdr: pointer to xdr_stream struct
858  * @len: number of bytes of page data
859  *
860  * Moves data beyond the current pointer position from the XDR head[] buffer
861  * into the page list. Any data that lies beyond current position + "len"
862  * bytes is moved into the XDR tail[]. The current pointer is then
863  * repositioned at the beginning of the XDR tail.
864  */
865 void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
866 {
867         struct xdr_buf *buf = xdr->buf;
868         struct kvec *iov;
869         ssize_t shift;
870         unsigned int end;
871         int padding;
872
873         /* Realign pages to current pointer position */
874         iov  = buf->head;
875         shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;
876         if (shift > 0)
877                 xdr_shrink_bufhead(buf, shift);
878
879         /* Truncate page data and move it into the tail */
880         if (buf->page_len > len)
881                 xdr_shrink_pagelen(buf, buf->page_len - len);
882         padding = (XDR_QUADLEN(len) << 2) - len;
883         xdr->iov = iov = buf->tail;
884         /* Compute remaining message length.  */
885         end = iov->iov_len;
886         shift = buf->buflen - buf->len;
887         if (shift < end)
888                 end -= shift;
889         else if (shift > 0)
890                 end = 0;
891         /*
892          * Position current pointer at beginning of tail, and
893          * set remaining message length.
894          */
895         xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
896         xdr->end = (uint32_t *)((char *)iov->iov_base + end);
897 }
898 EXPORT_SYMBOL(xdr_read_pages);
899
900 static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
901
902 void
903 xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
904 {
905         buf->head[0] = *iov;
906         buf->tail[0] = empty_iov;
907         buf->page_len = 0;
908         buf->buflen = buf->len = iov->iov_len;
909 }
910
911 /* Sets subiov to the intersection of iov with the buffer of length len
912  * starting base bytes after iov.  Indicates empty intersection by setting
913  * length of subiov to zero.  Decrements len by length of subiov, sets base
914  * to zero (or decrements it by length of iov if subiov is empty). */
915 static void
916 iov_subsegment(struct kvec *iov, struct kvec *subiov, int *base, int *len)
917 {
918         if (*base > iov->iov_len) {
919                 subiov->iov_base = NULL;
920                 subiov->iov_len = 0;
921                 *base -= iov->iov_len;
922         } else {
923                 subiov->iov_base = iov->iov_base + *base;
924                 subiov->iov_len = min(*len, (int)iov->iov_len - *base);
925                 *base = 0;
926         }
927         *len -= subiov->iov_len; 
928 }
929
930 /* Sets subbuf to the portion of buf of length len beginning base bytes
931  * from the start of buf. Returns -1 if base of length are out of bounds. */
932 int
933 xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
934                         int base, int len)
935 {
936         int i;
937
938         subbuf->buflen = subbuf->len = len;
939         iov_subsegment(buf->head, subbuf->head, &base, &len);
940
941         if (base < buf->page_len) {
942                 i = (base + buf->page_base) >> PAGE_CACHE_SHIFT;
943                 subbuf->pages = &buf->pages[i];
944                 subbuf->page_base = (base + buf->page_base) & ~PAGE_CACHE_MASK;
945                 subbuf->page_len = min((int)buf->page_len - base, len);
946                 len -= subbuf->page_len;
947                 base = 0;
948         } else {
949                 base -= buf->page_len;
950                 subbuf->page_len = 0;
951         }
952
953         iov_subsegment(buf->tail, subbuf->tail, &base, &len);
954         if (base || len)
955                 return -1;
956         return 0;
957 }
958
959 /* obj is assumed to point to allocated memory of size at least len: */
960 int
961 read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)
962 {
963         struct xdr_buf subbuf;
964         int this_len;
965         int status;
966
967         status = xdr_buf_subsegment(buf, &subbuf, base, len);
968         if (status)
969                 goto out;
970         this_len = min(len, (int)subbuf.head[0].iov_len);
971         memcpy(obj, subbuf.head[0].iov_base, this_len);
972         len -= this_len;
973         obj += this_len;
974         this_len = min(len, (int)subbuf.page_len);
975         if (this_len)
976                 _copy_from_pages(obj, subbuf.pages, subbuf.page_base, this_len);
977         len -= this_len;
978         obj += this_len;
979         this_len = min(len, (int)subbuf.tail[0].iov_len);
980         memcpy(obj, subbuf.tail[0].iov_base, this_len);
981 out:
982         return status;
983 }
984
985 static int
986 read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
987 {
988         u32     raw;
989         int     status;
990
991         status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
992         if (status)
993                 return status;
994         *obj = ntohl(raw);
995         return 0;
996 }
997
998 /* If the netobj starting offset bytes from the start of xdr_buf is contained
999  * entirely in the head or the tail, set object to point to it; otherwise
1000  * try to find space for it at the end of the tail, copy it there, and
1001  * set obj to point to it. */
1002 int
1003 xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset)
1004 {
1005         u32     tail_offset = buf->head[0].iov_len + buf->page_len;
1006         u32     obj_end_offset;
1007
1008         if (read_u32_from_xdr_buf(buf, offset, &obj->len))
1009                 goto out;
1010         obj_end_offset = offset + 4 + obj->len;
1011
1012         if (obj_end_offset <= buf->head[0].iov_len) {
1013                 /* The obj is contained entirely in the head: */
1014                 obj->data = buf->head[0].iov_base + offset + 4;
1015         } else if (offset + 4 >= tail_offset) {
1016                 if (obj_end_offset - tail_offset
1017                                 > buf->tail[0].iov_len)
1018                         goto out;
1019                 /* The obj is contained entirely in the tail: */
1020                 obj->data = buf->tail[0].iov_base
1021                         + offset - tail_offset + 4;
1022         } else {
1023                 /* use end of tail as storage for obj:
1024                  * (We don't copy to the beginning because then we'd have
1025                  * to worry about doing a potentially overlapping copy.
1026                  * This assumes the object is at most half the length of the
1027                  * tail.) */
1028                 if (obj->len > buf->tail[0].iov_len)
1029                         goto out;
1030                 obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len - 
1031                                 obj->len;
1032                 if (read_bytes_from_xdr_buf(buf, offset + 4,
1033                                         obj->data, obj->len))
1034                         goto out;
1035
1036         }
1037         return 0;
1038 out:
1039         return -1;
1040 }