11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/net/sunrpc/xdr.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generic XDR support.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9a246b0105bbd9a70a698f69baae2042996f2a0e9Chuck Lever#include <linux/module.h>
105a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/xdr.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sunrpc/msg_prot.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XDR functions for basic NFS types
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *
23d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanxdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	quadlen = XDR_QUADLEN(obj->len);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p[quadlen] = 0;		/* zero trailing bytes */
289f162d2a810b4db48f7b8d7e734d0932c81ec2a1Benny Halevy	*p++ = cpu_to_be32(obj->len);
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(p, obj->data, obj->len);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p + XDR_QUADLEN(obj->len);
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
32468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_netobj);
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *
35d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanxdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int	len;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3998866b5abe1513cdacc011874ca045d40002eccdBenny Halevy	if ((len = be32_to_cpu(*p++)) > XDR_MAX_NETOBJ)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->len  = len;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->data = (u8 *) p;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p + XDR_QUADLEN(len);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
45468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_netobj);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_encode_opaque_fixed - Encode fixed length opaque data
494dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @p: pointer to current position in XDR buffer.
504dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @ptr: pointer to data to encode (or NULL)
514dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @nbytes: size of data.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy the array of data of length nbytes at ptr to the XDR buffer
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at position p, then align to the next 32-bit boundary by padding
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with zero bytes (see RFC1832).
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: if ptr is NULL, only the padding is performed.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the updated current XDR buffer position
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
61d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(nbytes != 0)) {
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int quadlen = XDR_QUADLEN(nbytes);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int padding = (quadlen << 2) - nbytes;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ptr != NULL)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(p, ptr, nbytes);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (padding != 0)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset((char *)p + nbytes, 0, padding);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += quadlen;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
75468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_opaque_fixed);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_encode_opaque - Encode variable length opaque data
794dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @p: pointer to current position in XDR buffer.
804dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @ptr: pointer to data to encode (or NULL)
814dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @nbytes: size of data.
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the updated current XDR buffer position
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
85d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
879f162d2a810b4db48f7b8d7e734d0932c81ec2a1Benny Halevy	*p++ = cpu_to_be32(nbytes);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return xdr_encode_opaque_fixed(p, ptr, nbytes);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
90468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_opaque);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *
93d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanxdr_encode_string(__be32 *p, const char *string)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return xdr_encode_array(p, string, strlen(string));
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
97468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_string);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
99d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 *
100e5cff482c78a35b9f149a06aa777a1bd693864fbChuck Leverxdr_decode_string_inplace(__be32 *p, char **sp,
101e5cff482c78a35b9f149a06aa777a1bd693864fbChuck Lever			  unsigned int *lenp, unsigned int maxlen)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
103e5cff482c78a35b9f149a06aa777a1bd693864fbChuck Lever	u32 len;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10598866b5abe1513cdacc011874ca045d40002eccdBenny Halevy	len = be32_to_cpu(*p++);
106e5cff482c78a35b9f149a06aa777a1bd693864fbChuck Lever	if (len > maxlen)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*lenp = len;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*sp = (char *) p;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p + XDR_QUADLEN(len);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
112468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_string_inplace);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever/**
115b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever * xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
116b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever * @buf: XDR buffer where string resides
117b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever * @len: length of string, in bytes
118b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever *
119b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever */
120b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Levervoid
121b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Leverxdr_terminate_string(struct xdr_buf *buf, const u32 len)
122b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever{
123b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever	char *kaddr;
124b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever
125b85417860172ff693dc115d7999805fc240cec1cCong Wang	kaddr = kmap_atomic(buf->pages[0]);
126b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever	kaddr[buf->page_base + len] = '\0';
127b85417860172ff693dc115d7999805fc240cec1cCong Wang	kunmap_atomic(kaddr);
128b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever}
1290d961aa934b799ca7369db582e52952cc50c656dTrond MyklebustEXPORT_SYMBOL_GPL(xdr_terminate_string);
130b4687da7fc5f741af7fee9b0248a2cf2ad9c4478Chuck Lever
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct page **pages, unsigned int base, unsigned int len)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *head = xdr->head;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *tail = xdr->tail;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *buf = (char *)head->iov_base;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int buflen = head->iov_len;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->iov_len  = offset;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->pages = pages;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_base = base;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_len = len;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_base = buf + offset;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_len = buflen - offset;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buflen += len;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
151468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_inline_pages);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Helper routines for doing 'memmove' like operations on a struct xdr_buf
1552c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings */
1562c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings
1572c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings/**
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _shift_data_right_pages
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: vector of pages containing both the source and dest memory area.
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgto_base: page vector address of destination
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgfrom_base: page vector address of source
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: number of bytes to copy
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: the addresses pgto_base and pgfrom_base are both calculated in
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       the same way:
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            if a memory area starts at byte 'base' in page 'pages[i]',
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            then its address is given as (i << PAGE_CACHE_SHIFT) + base
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also note: pgfrom_base must be < pgto_base, but the memory areas
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	they point to may overlap.
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_shift_data_right_pages(struct page **pages, size_t pgto_base,
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t pgfrom_base, size_t len)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgfrom, **pgto;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vfrom, *vto;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(pgto_base <= pgfrom_base);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto_base += len;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom_base += len;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto = pages + (pgto_base >> PAGE_CACHE_SHIFT);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom = pages + (pgfrom_base >> PAGE_CACHE_SHIFT);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto_base &= ~PAGE_CACHE_MASK;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom_base &= ~PAGE_CACHE_MASK;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Are any pointers crossing a page boundary? */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgto_base == 0) {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto_base = PAGE_CACHE_SIZE;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto--;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgfrom_base == 0) {
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom_base = PAGE_CACHE_SIZE;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom--;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pgto_base)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pgto_base;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pgfrom_base)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pgfrom_base;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgto_base -= copy;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgfrom_base -= copy;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
209b85417860172ff693dc115d7999805fc240cec1cCong Wang		vto = kmap_atomic(*pgto);
210347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust		if (*pgto != *pgfrom) {
211347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust			vfrom = kmap_atomic(*pgfrom);
212347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust			memcpy(vto + pgto_base, vfrom + pgfrom_base, copy);
213347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust			kunmap_atomic(vfrom);
214347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust		} else
215347e2233b7667e336d9f671f1a52dfa3f0416e2cTrond Myklebust			memmove(vto + pgto_base, vto + pgfrom_base, copy);
216bce3481c91801665e17f8daf59ede946129f3d3fTrond Myklebust		flush_dcache_page(*pgto);
217b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vto);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((len -= copy) != 0);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2222c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings/**
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _copy_to_pages
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: array of pages
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgbase: page vector address of destination
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: pointer to source data
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies data from an arbitrary memory location into an array of pages
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The copy is assumed to be non-overlapping.
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgto;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vto;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto = pages + (pgbase >> PAGE_CACHE_SHIFT);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgbase &= ~PAGE_CACHE_MASK;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust	for (;;) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = PAGE_CACHE_SIZE - pgbase;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
247b85417860172ff693dc115d7999805fc240cec1cCong Wang		vto = kmap_atomic(*pgto);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(vto + pgbase, p, copy);
249b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vto);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust		len -= copy;
252daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust		if (len == 0)
253daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust			break;
254daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgbase += copy;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgbase == PAGE_CACHE_SIZE) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flush_dcache_page(*pgto);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgbase = 0;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto++;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += copy;
262daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust	}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_dcache_page(*pgto);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2662c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings/**
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _copy_from_pages
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: pointer to destination
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: array of pages
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgbase: offset of source data
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies data into an arbitrary memory location from an array of pages
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The copy is assumed to be non-overlapping.
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
276bf118a342f10dafe44b14451a1392c3254629a1fAndy Adamsonvoid
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgfrom;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vfrom;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom = pages + (pgbase >> PAGE_CACHE_SHIFT);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgbase &= ~PAGE_CACHE_MASK;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = PAGE_CACHE_SIZE - pgbase;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291b85417860172ff693dc115d7999805fc240cec1cCong Wang		vfrom = kmap_atomic(*pgfrom);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(p, vfrom + pgbase, copy);
293b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vfrom);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgbase += copy;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgbase == PAGE_CACHE_SIZE) {
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgbase = 0;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom++;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += copy;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((len -= copy) != 0);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
304bf118a342f10dafe44b14451a1392c3254629a1fAndy AdamsonEXPORT_SYMBOL_GPL(_copy_from_pages);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3062c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings/**
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_shrink_bufhead
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: xdr_buf
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: bytes to remove from buf->head[0]
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki * Shrinks XDR buffer's header kvec buf->head[0] by
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'len' bytes. The extra data is not lost, but is instead
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved into the inlined pages and/or the tail.
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *head, *tail;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy, offs;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pglen = buf->page_len;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = buf->tail;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = buf->head;
32418e624ad0374f3b1092530f978301611f88e45b3Weston Andros Adamson
32518e624ad0374f3b1092530f978301611f88e45b3Weston Andros Adamson	WARN_ON_ONCE(len > head->iov_len);
32618e624ad0374f3b1092530f978301611f88e45b3Weston Andros Adamson	if (len > head->iov_len)
32718e624ad0374f3b1092530f978301611f88e45b3Weston Andros Adamson		len = head->iov_len;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the tail first */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tail->iov_len != 0) {
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tail->iov_len > len) {
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len - len;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove((char *)tail->iov_base + len,
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tail->iov_base, copy);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy from the inlined pages into the tail */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pglen)
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pglen;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offs = len - copy;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (offs >= tail->iov_len)
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = 0;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (copy > tail->iov_len - offs)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len - offs;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy != 0)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_copy_from_pages((char *)tail->iov_base + offs,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->pages,
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base + pglen + offs - len,
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Do we also need to copy data from the head into the tail ? */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > pglen) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = copy = len - pglen;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy > tail->iov_len)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy = tail->iov_len;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(tail->iov_base,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(char *)head->iov_base +
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->iov_len - offs,
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now handle pages */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pglen != 0) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pglen > len)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_shift_data_right_pages(buf->pages,
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base + len,
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pglen - len);
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > pglen)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pglen;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_copy_to_pages(buf->pages, buf->page_base,
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(char *)head->iov_base + head->iov_len - len,
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->iov_len -= len;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen -= len;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Have we truncated the message? */
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf->len > buf->buflen)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf->len = buf->buflen;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3822c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings/**
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_shrink_pagelen
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: xdr_buf
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: bytes to remove from buf->pages
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
387cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki * Shrinks XDR buffer's page array buf->pages by
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'len' bytes. The extra data is not lost, but is instead
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved into the tail.
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *tail;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pglen = buf->page_len;
397cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	unsigned int tailbuf_len;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = buf->tail;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON (len > pglen);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
402cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len;
403cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the tail first */
405cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	if (tailbuf_len != 0) {
406cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		unsigned int free_space = tailbuf_len - tail->iov_len;
407cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
408cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		if (len < free_space)
409cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust			free_space = len;
410cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		tail->iov_len += free_space;
411cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
41242d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		copy = len;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tail->iov_len > len) {
4140fe62a35903e11fb41b492bd5b0e8e4c751d5c94Benny Halevy			char *p = (char *)tail->iov_base + len;
4152e29ebb8119e6037133921fac09cc5f9d625b511Benny Halevy			memmove(p, tail->iov_base, tail->iov_len - len);
41642d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		} else
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len;
41842d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		/* Copy from the inlined pages into the tail */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_copy_from_pages((char *)tail->iov_base,
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				buf->pages, buf->page_base + pglen - len,
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len -= len;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen -= len;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Have we truncated the message? */
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf->len > buf->buflen)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf->len = buf->buflen;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shift_buf(struct xdr_buf *buf, size_t len)
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr_shrink_bufhead(buf, len);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
435468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_shift_buf);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4384517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust * xdr_stream_pos - Return the current offset from the start of the xdr_stream
4394517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust * @xdr: pointer to struct xdr_stream
4404517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust */
4414517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebustunsigned int xdr_stream_pos(const struct xdr_stream *xdr)
4424517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust{
4434517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust	return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
4444517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust}
4454517d526c8aa31b5c14165ef180cc19518ff0a35Trond MyklebustEXPORT_SYMBOL_GPL(xdr_stream_pos);
4464517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust
4474517d526c8aa31b5c14165ef180cc19518ff0a35Trond Myklebust/**
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_init_encode - Initialize a struct xdr_stream for sending data.
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: pointer to XDR buffer in which to encode data
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: current pointer inside XDR buffer
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: at the moment the RPC client only passes the length of our
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 scratch buffer in the xdr_buf's header kvec. Previously this
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 meant we needed to call xdr_adjust_iovec() after encoding the
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 data. With the new scheme, the xdr_stream manages the details
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 of the buffer length, and takes care of adjusting the kvec
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 length for us.
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
460d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanvoid xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov = buf->head;
463334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4652825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr_set_scratch_buffer(xdr, NULL, 0);
466334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	BUG_ON(scratch_len < 0);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf = buf;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov;
469d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
470d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
471334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	BUG_ON(iov->iov_len > scratch_len);
472334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust
473334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	if (p != xdr->p && p != NULL) {
474334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		size_t len;
475334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust
476334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		BUG_ON(p < xdr->p || p > xdr->end);
477334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		len = (char *)p - (char *)xdr->p;
478334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		xdr->p = p;
479334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		buf->len += len;
480334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		iov->iov_len += len;
481334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
483468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_init_encode);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4862825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * xdr_commit_encode - Ensure all data is written to buffer
4872825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * @xdr: pointer to xdr_stream
4882825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields *
4892825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * We handle encoding across page boundaries by giving the caller a
4902825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * temporary location to write to, then later copying the data into
4912825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * place; xdr_commit_encode does that copying.
4922825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields *
4932825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * Normally the caller doesn't need to call this directly, as the
4942825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * following xdr_reserve_space will do it.  But an explicit call may be
4952825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * required at the end of encoding, or any other time when the xdr_buf
4962825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields * data might be read.
4972825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields */
4982825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fieldsvoid xdr_commit_encode(struct xdr_stream *xdr)
4992825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields{
5002825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	int shift = xdr->scratch.iov_len;
5012825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	void *page;
5022825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields
5032825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	if (shift == 0)
5042825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		return;
5052825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	page = page_address(*xdr->page_ptr);
5062825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	memcpy(xdr->scratch.iov_base, page, shift);
5072825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	memmove(page, page + shift, (void *)xdr->p - page);
5082825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->scratch.iov_len = 0;
5092825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields}
5102825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce FieldsEXPORT_SYMBOL_GPL(xdr_commit_encode);
5112825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields
51222cb43855dce2cb1b23c5b8c5c83e9baa4cfde6eTrond Myklebuststatic __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
51322cb43855dce2cb1b23c5b8c5c83e9baa4cfde6eTrond Myklebust		size_t nbytes)
5142825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields{
5152825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	static __be32 *p;
5162825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	int space_left;
5172825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	int frag1bytes, frag2bytes;
5182825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields
5192825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	if (nbytes > PAGE_SIZE)
5202825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		return NULL; /* Bigger buffers require special handling */
5212825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	if (xdr->buf->len + nbytes > xdr->buf->buflen)
5222825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		return NULL; /* Sorry, we're totally out of space */
5232825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	frag1bytes = (xdr->end - xdr->p) << 2;
5242825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	frag2bytes = nbytes - frag1bytes;
5252825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	if (xdr->iov)
5262825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		xdr->iov->iov_len += frag1bytes;
52705638dc73af2586517468b1159d4b76e90607359J. Bruce Fields	else
5282825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		xdr->buf->page_len += frag1bytes;
52905638dc73af2586517468b1159d4b76e90607359J. Bruce Fields	xdr->page_ptr++;
5302825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->iov = NULL;
5312825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	/*
5322825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * If the last encode didn't end exactly on a page boundary, the
5332825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * next one will straddle boundaries.  Encode into the next
5342825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * page, then copy it back later in xdr_commit_encode.  We use
5352825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * the "scratch" iov to track any temporarily unused fragment of
5362825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * space at the end of the previous buffer:
5372825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 */
5382825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->scratch.iov_base = xdr->p;
5392825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->scratch.iov_len = frag1bytes;
5402825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	p = page_address(*xdr->page_ptr);
5412825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	/*
5422825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * Note this is where the next encode will start after we've
5432825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 * shifted this one back:
5442825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	 */
5452825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->p = (void *)p + frag2bytes;
5462825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	space_left = xdr->buf->buflen - xdr->buf->len;
5472825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
5482825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->buf->page_len += frag2bytes;
5492825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr->buf->len += nbytes;
5502825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	return p;
5512825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields}
5522825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields
5532825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields/**
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_reserve_space - Reserve buffer space for sending
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @nbytes: number of bytes to reserve
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Checks that we have enough buffer space to encode 'nbytes' more
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes of data. If so, update the total xdr_buf length, and
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adjust the length of the current kvec.
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
562d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
564d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32 *p = xdr->p;
565d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32 *q;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5672825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr_commit_encode(xdr);
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* align nbytes on the next 32-bit boundary */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nbytes += 3;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nbytes &= ~3;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p + (nbytes >> 2);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(q > xdr->end || q < p))
5732825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		return xdr_get_next_encode_buffer(xdr, nbytes);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->p = q;
5752825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	if (xdr->iov)
5762825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		xdr->iov->iov_len += nbytes;
5772825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	else
5782825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields		xdr->buf->page_len += nbytes;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf->len += nbytes;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
582468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_reserve_space);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5853e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * xdr_truncate_encode - truncate an encode buffer
5863e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * @xdr: pointer to xdr_stream
5873e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * @len: new length of buffer
5883e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields *
5893e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * Truncates the xdr stream, so that xdr->buf->len == len,
5903e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * and xdr->p points at offset len from the start of the buffer, and
5913e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * head, tail, and page lengths are adjusted to correspond.
5923e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields *
5933e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * If this means moving xdr->p to a different buffer, we assume that
5943e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * that the end pointer should be set to the end of the current page,
5953e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * except in the case of the head buffer when we assume the head
5963e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * buffer's current length represents the end of the available buffer.
5973e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields *
5983e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * This is *not* safe to use on a buffer that already has inlined page
5993e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * cache pages (as in a zero-copy server read reply), except for the
6003e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields * simple case of truncating from one position in the tail to another.
6013e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields *
6023e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields */
6033e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fieldsvoid xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
6043e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields{
6053e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	struct xdr_buf *buf = xdr->buf;
6063e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	struct kvec *head = buf->head;
6073e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	struct kvec *tail = buf->tail;
6083e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	int fraglen;
6093e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	int new, old;
6103e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields
6113e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	if (len > buf->len) {
6123e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		WARN_ON_ONCE(1);
6133e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		return;
6143e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	}
6152825a7f90753012babe7ee292f4a1eadd3706f92J. Bruce Fields	xdr_commit_encode(xdr);
6163e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields
6173e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	fraglen = min_t(int, buf->len - len, tail->iov_len);
6183e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	tail->iov_len -= fraglen;
6193e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	buf->len -= fraglen;
6203e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	if (tail->iov_len && buf->len == len) {
6213e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		xdr->p = tail->iov_base + tail->iov_len;
6223e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		/* xdr->end, xdr->iov should be set already */
6233e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		return;
6243e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	}
6253e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	WARN_ON_ONCE(fraglen);
6263e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	fraglen = min_t(int, buf->len - len, buf->page_len);
6273e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	buf->page_len -= fraglen;
6283e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	buf->len -= fraglen;
6293e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields
6303e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	new = buf->page_base + buf->page_len;
6313e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	old = new + fraglen;
6323e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	xdr->page_ptr -= (old >> PAGE_SHIFT) - (new >> PAGE_SHIFT);
6333e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields
6343e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	if (buf->page_len && buf->len == len) {
6353e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		xdr->p = page_address(*xdr->page_ptr);
6363e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		xdr->end = (void *)xdr->p + PAGE_SIZE;
6373e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		xdr->p = (void *)xdr->p + (new % PAGE_SIZE);
6383e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		/* xdr->iov should already be NULL */
6393e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		return;
6403e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	}
64105638dc73af2586517468b1159d4b76e90607359J. Bruce Fields	if (fraglen) {
6423e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields		xdr->end = head->iov_base + head->iov_len;
64305638dc73af2586517468b1159d4b76e90607359J. Bruce Fields		xdr->page_ptr--;
64405638dc73af2586517468b1159d4b76e90607359J. Bruce Fields	}
6453e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	/* (otherwise assume xdr->end is already set) */
6463e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	head->iov_len = len;
6473e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	buf->len = len;
6483e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	xdr->p = head->iov_base + head->iov_len;
6493e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields	xdr->iov = buf->head;
6503e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields}
6513e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce FieldsEXPORT_SYMBOL(xdr_truncate_encode);
6523e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields
6533e19ce762b537dd9aeefdd0849ba5f2f01ff83cfJ. Bruce Fields/**
654db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * xdr_restrict_buflen - decrease available buffer space
655db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * @xdr: pointer to xdr_stream
656db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * @newbuflen: new maximum number of bytes available
657db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields *
658db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * Adjust our idea of how much space is available in the buffer.
659db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * If we've already used too much space in the buffer, returns -1.
660db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * If the available space is already smaller than newbuflen, returns 0
661db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * and does nothing.  Otherwise, adjusts xdr->buf->buflen to newbuflen
662db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * and ensures xdr->end is set at most offset newbuflen from the start
663db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields * of the buffer.
664db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields */
665db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fieldsint xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen)
666db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields{
667db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	struct xdr_buf *buf = xdr->buf;
668db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	int left_in_this_buf = (void *)xdr->end - (void *)xdr->p;
669db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	int end_offset = buf->len + left_in_this_buf;
670db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields
671db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	if (newbuflen < 0 || newbuflen < buf->len)
672db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields		return -1;
673db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	if (newbuflen > buf->buflen)
674db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields		return 0;
675db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	if (newbuflen < end_offset)
676db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields		xdr->end = (void *)xdr->end + newbuflen - end_offset;
677db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	buf->buflen = newbuflen;
678db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields	return 0;
679db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields}
680db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce FieldsEXPORT_SYMBOL(xdr_restrict_buflen);
681db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields
682db3f58a95beea6752d90fed03f9f198d282a3913J. Bruce Fields/**
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: list of pages
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @base: offset of first byte
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length of data in bytes
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned int len)
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xdr_buf *buf = xdr->buf;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov = buf->tail;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->pages = pages;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_base = base;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len = len;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov->iov_base = (char *)xdr->p;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov->iov_len  = 0;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len & 3) {
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int pad = 4 - (len & 3);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(xdr->p >= xdr->end);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_base = (char *)xdr->p + (len & 3);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_len  += pad;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len += pad;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*xdr->p++ = 0;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen += len;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->len += len;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
715468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_write_pages);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7176650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
7181537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		unsigned int len)
7196650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
7206650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (len > iov->iov_len)
7216650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		len = iov->iov_len;
7221537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust	xdr->p = (__be32*)iov->iov_base;
7236650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->end = (__be32*)(iov->iov_base + len);
7246650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->iov = iov;
7256650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->page_ptr = NULL;
7266650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
7276650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7286650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic int xdr_set_page_base(struct xdr_stream *xdr,
7296650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		unsigned int base, unsigned int len)
7306650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
7316650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgnr;
7326650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int maxlen;
7336650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgoff;
7346650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgend;
7356650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	void *kaddr;
7366650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7376650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	maxlen = xdr->buf->page_len;
7386650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (base >= maxlen)
7396650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return -EINVAL;
7406650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	maxlen -= base;
7416650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (len > maxlen)
7426650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		len = maxlen;
7436650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7446650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	base += xdr->buf->page_base;
7456650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7466650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgnr = base >> PAGE_SHIFT;
7476650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->page_ptr = &xdr->buf->pages[pgnr];
7486650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	kaddr = page_address(*xdr->page_ptr);
7496650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7506650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgoff = base & ~PAGE_MASK;
7516650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->p = (__be32*)(kaddr + pgoff);
7526650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7536650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgend = pgoff + len;
7546650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (pgend > PAGE_SIZE)
7556650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		pgend = PAGE_SIZE;
7566650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->end = (__be32*)(kaddr + pgend);
7576650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->iov = NULL;
7586650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return 0;
7596650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
7606650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7616650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic void xdr_set_next_page(struct xdr_stream *xdr)
7626650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
7636650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int newbase;
7646650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7656650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
7666650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	newbase -= xdr->buf->page_base;
7676650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7686650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
7691537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
7706650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
7716650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7726650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic bool xdr_set_next_buffer(struct xdr_stream *xdr)
7736650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
7746650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr->page_ptr != NULL)
7756650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		xdr_set_next_page(xdr);
7766650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	else if (xdr->iov == xdr->buf->head) {
7776650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
7781537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust			xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
7796650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	}
7806650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr->p != xdr->end;
7816650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
7826650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_init_decode - Initialize an xdr_stream for decoding data.
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: pointer to XDR buffer from which to decode data
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: current pointer inside XDR buffer
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
789d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanvoid xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf = buf;
7926650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_base = NULL;
7936650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_len = 0;
794bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords = XDR_QUADLEN(buf->len);
7956650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (buf->head[0].iov_len != 0)
7961537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr_set_iov(xdr, buf->head, buf->len);
7976650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	else if (buf->page_len != 0)
7986650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		xdr_set_page_base(xdr, 0, buf->len);
799bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (p != NULL && p > xdr->p && xdr->end >= p) {
800bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust		xdr->nwords -= p - xdr->p;
8011537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr->p = p;
802bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	}
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
804468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_init_decode);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
806f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy/**
807f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * xdr_init_decode - Initialize an xdr_stream for decoding data.
808f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @xdr: pointer to xdr_stream struct
809f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @buf: pointer to XDR buffer from which to decode data
810f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @pages: list of pages to decode into
811f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @len: length in bytes of buffer in pages
812f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy */
813f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevyvoid xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
814f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy			   struct page **pages, unsigned int len)
815f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy{
816f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	memset(buf, 0, sizeof(*buf));
817f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->pages =  pages;
818f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->page_len =  len;
819f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->buflen =  len;
820f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->len = len;
821f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	xdr_init_decode(xdr, buf, NULL);
822f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy}
823f7da7a129d57bfe0f74573dc03531c63e1360faeBenny HalevyEXPORT_SYMBOL_GPL(xdr_init_decode_pages);
824f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy
8256650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
826ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust{
827bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	unsigned int nwords = XDR_QUADLEN(nbytes);
828ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust	__be32 *p = xdr->p;
829bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	__be32 *q = p + nwords;
830ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust
831bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
832ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust		return NULL;
8336650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->p = q;
834bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords -= nwords;
835ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust	return p;
836ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust}
837ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust
838ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust/**
8396650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
8406650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @xdr: pointer to xdr_stream struct
8416650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @buf: pointer to an empty buffer
8426650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @buflen: size of 'buf'
8436650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust *
8446650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * The scratch buffer is used when decoding from an array of pages.
8456650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * If an xdr_inline_decode() call spans across page boundaries, then
8466650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * we copy the data into the scratch buffer in order to allow linear
8476650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * access.
8486650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust */
8496650239a4b01077e80d5a4468562756d77afaa59Trond Myklebustvoid xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
8506650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
8516650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_base = buf;
8526650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_len = buflen;
8536650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
8546650239a4b01077e80d5a4468562756d77afaa59Trond MyklebustEXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
8556650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
8566650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
8576650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
8586650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	__be32 *p;
8596650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	void *cpdest = xdr->scratch.iov_base;
8606650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	size_t cplen = (char *)xdr->end - (char *)xdr->p;
8616650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
8626650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (nbytes > xdr->scratch.iov_len)
8636650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
8646650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	memcpy(cpdest, xdr->p, cplen);
8656650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	cpdest += cplen;
8666650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	nbytes -= cplen;
8676650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (!xdr_set_next_buffer(xdr))
8686650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
8696650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	p = __xdr_inline_decode(xdr, nbytes);
8706650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (p == NULL)
8716650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
8726650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	memcpy(cpdest, p, nbytes);
8736650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr->scratch.iov_base;
8746650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
8756650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
8766650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust/**
8776650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * xdr_inline_decode - Retrieve XDR data to decode
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @nbytes: number of bytes of data to decode
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check if the input buffer is long enough to enable us to decode
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'nbytes' more bytes of data starting at the current position.
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If so return the current pointer, then update the current
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointer position.
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
886d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8886650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	__be32 *p;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8906650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (nbytes == 0)
8916650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return xdr->p;
8926650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
8946650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	p = __xdr_inline_decode(xdr, nbytes);
8956650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (p != NULL)
8966650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return p;
8976650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr_copy_to_scratch(xdr, nbytes);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
899468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_inline_decode);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9013994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebuststatic unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xdr_buf *buf = xdr->buf;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov;
905bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	unsigned int nwords = XDR_QUADLEN(len);
906b760b3131d962dd35925fb65956afe621fa65ec4Trond Myklebust	unsigned int cur = xdr_stream_pos(xdr);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
908bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (xdr->nwords == 0)
909c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust		return 0;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Realign pages to current pointer position */
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov  = buf->head;
912a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	if (iov->iov_len > cur) {
913b760b3131d962dd35925fb65956afe621fa65ec4Trond Myklebust		xdr_shrink_bufhead(buf, iov->iov_len - cur);
914a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		xdr->nwords = XDR_QUADLEN(buf->len - cur);
915a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
917a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	if (nwords > xdr->nwords) {
918a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		nwords = xdr->nwords;
919a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		len = nwords << 2;
920a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	}
921a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	if (buf->page_len <= len)
9228a9a8b8332b92b13316cf49685b5dc5257cfe115Trond Myklebust		len = buf->page_len;
923a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	else if (nwords < xdr->nwords) {
924a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		/* Truncate page data and move it into the tail */
925a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		xdr_shrink_pagelen(buf, buf->page_len - len);
926a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust		xdr->nwords = XDR_QUADLEN(buf->len - cur);
927a11a2bf4de5679fa0b63474c7d39bea2dac7d061Trond Myklebust	}
9283994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	return len;
9293994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust}
930bd00f84bc57f42df32c728e86329a5c30f221657Trond Myklebust
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: number of bytes of page data
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Moves data beyond the current pointer position from the XDR head[] buffer
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into the page list. Any data that lies beyond current position + "len"
9388b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * bytes is moved into the XDR tail[].
9393994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust *
9403994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust * Returns the number of XDR encoded bytes now contained in the pages
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9423994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebustunsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xdr_buf *buf = xdr->buf;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov;
9463994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	unsigned int nwords;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int end;
9483994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	unsigned int padding;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9503994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	len = xdr_align_pages(xdr, len);
9513994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	if (len == 0)
9523994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust		return 0;
9533994ee6fbf5185b3183f4585432226e786bfe86cTrond Myklebust	nwords = XDR_QUADLEN(len);
954bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	padding = (nwords << 2) - len;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov = buf->tail;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compute remaining message length.  */
957bd00f84bc57f42df32c728e86329a5c30f221657Trond Myklebust	end = ((xdr->nwords - nwords) << 2) + padding;
958bd00f84bc57f42df32c728e86329a5c30f221657Trond Myklebust	if (end > iov->iov_len)
959bd00f84bc57f42df32c728e86329a5c30f221657Trond Myklebust		end = iov->iov_len;
960bd00f84bc57f42df32c728e86329a5c30f221657Trond Myklebust
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Position current pointer at beginning of tail, and
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set remaining message length.
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
965d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->p = (__be32 *)((char *)iov->iov_base + padding);
966d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->end = (__be32 *)((char *)iov->iov_base + end);
96776cacaabf15a593833d96a65a1a251002bd88178Trond Myklebust	xdr->page_ptr = NULL;
968bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords = XDR_QUADLEN(end - padding);
969c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust	return len;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
971468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_read_pages);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9738b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust/**
9748b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * xdr_enter_page - decode data from the XDR page
9758b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * @xdr: pointer to xdr_stream struct
9768b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * @len: number of bytes of page data
9778b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust *
9788b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * Moves data beyond the current pointer position from the XDR head[] buffer
9798b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * into the page list. Any data that lies beyond current position + "len"
9808b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * bytes is moved into the XDR tail[]. The current pointer is then
9818b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * repositioned at the beginning of the first XDR page.
9828b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust */
9838b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebustvoid xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
9848b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust{
985f8bb7f08549a1ced9ceb69a9bd5e163122044ab2Trond Myklebust	len = xdr_align_pages(xdr, len);
9868b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	/*
9878b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 * Position current pointer at beginning of tail, and
9888b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 * set remaining message length.
9898b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 */
990f8bb7f08549a1ced9ceb69a9bd5e163122044ab2Trond Myklebust	if (len != 0)
991f8bb7f08549a1ced9ceb69a9bd5e163122044ab2Trond Myklebust		xdr_set_page_base(xdr, 0, len);
9928b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust}
993468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_enter_page);
9948b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->head[0] = *iov;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->tail[0] = empty_iov;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len = 0;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen = buf->len = iov->iov_len;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1005468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_from_iov);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1007de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields/**
1008de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * xdr_buf_subsegment - set subbuf to a portion of buf
1009de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * @buf: an xdr buffer
1010de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * @subbuf: the result buffer
1011de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * @base: beginning of range in bytes
1012de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * @len: length of range in bytes
1013de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields *
1014de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * sets @subbuf to an xdr buffer representing the portion of @buf of
1015de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * length @len starting at offset @base.
1016de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields *
1017de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * @buf and @subbuf may be pointers to the same struct xdr_buf.
1018de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields *
1019de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields * Returns -1 if base of length are out of bounds.
1020de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields */
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
10231e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust			unsigned int base, unsigned int len)
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	subbuf->buflen = subbuf->len = len;
10261e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	if (base < buf->head[0].iov_len) {
10271e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_base = buf->head[0].iov_base + base;
10281e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_len = min_t(unsigned int, len,
10291e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust						buf->head[0].iov_len - base);
10301e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		len -= subbuf->head[0].iov_len;
10311e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base = 0;
10321e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	} else {
10331e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base -= buf->head[0].iov_len;
1034de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields		subbuf->head[0].iov_len = 0;
10351e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (base < buf->page_len) {
10381e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->page_len = min(buf->page_len - base, len);
10391e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base += buf->page_base;
10401e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->page_base = base & ~PAGE_CACHE_MASK;
10411e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->pages = &buf->pages[base >> PAGE_CACHE_SHIFT];
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len -= subbuf->page_len;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		base = 0;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		base -= buf->page_len;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		subbuf->page_len = 0;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	if (base < buf->tail[0].iov_len) {
10501e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_base = buf->tail[0].iov_base + base;
10511e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_len = min_t(unsigned int, len,
10521e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust						buf->tail[0].iov_len - base);
10531e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		len -= subbuf->tail[0].iov_len;
10541e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base = 0;
10551e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	} else {
10561e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base -= buf->tail[0].iov_len;
1057de4aee2e0a376fb272f44139150115a6dec1da95J. Bruce Fields		subbuf->tail[0].iov_len = 0;
10581e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	}
10591e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (base || len)
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1064468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_subsegment);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10664c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton/**
10674c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * xdr_buf_trim - lop at most "len" bytes off the end of "buf"
10684c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * @buf: buf to be trimmed
10694c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * @len: number of bytes to reduce "buf" by
10704c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton *
10714c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * Trim an xdr_buf by the given number of bytes by fixing up the lengths. Note
10724c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * that it's possible that we'll trim less than that amount if the xdr_buf is
10734c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * too small, or if (for instance) it's all in the head and the parser has
10744c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton * already read too far into it.
10754c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton */
10764c190e2f913f038c9c91ee63b59cd037260ba353Jeff Laytonvoid xdr_buf_trim(struct xdr_buf *buf, unsigned int len)
10774c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton{
10784c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	size_t cur;
10794c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	unsigned int trim = len;
10804c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton
10814c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	if (buf->tail[0].iov_len) {
10824c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		cur = min_t(size_t, buf->tail[0].iov_len, trim);
10834c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		buf->tail[0].iov_len -= cur;
10844c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		trim -= cur;
10854c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		if (!trim)
10864c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton			goto fix_len;
10874c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	}
10884c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton
10894c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	if (buf->page_len) {
10904c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		cur = min_t(unsigned int, buf->page_len, trim);
10914c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		buf->page_len -= cur;
10924c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		trim -= cur;
10934c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		if (!trim)
10944c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton			goto fix_len;
10954c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	}
10964c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton
10974c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	if (buf->head[0].iov_len) {
10984c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		cur = min_t(size_t, buf->head[0].iov_len, trim);
10994c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		buf->head[0].iov_len -= cur;
11004c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton		trim -= cur;
11014c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	}
11024c190e2f913f038c9c91ee63b59cd037260ba353Jeff Laytonfix_len:
11034c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton	buf->len -= (len - trim);
11044c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton}
11054c190e2f913f038c9c91ee63b59cd037260ba353Jeff LaytonEXPORT_SYMBOL_GPL(xdr_buf_trim);
11064c190e2f913f038c9c91ee63b59cd037260ba353Jeff Layton
11074e3e43ad14c574281034a27420abf1993694ac11Trond Myklebuststatic void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11091e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	unsigned int this_len;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11114e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
11124e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(obj, subbuf->head[0].iov_base, this_len);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len -= this_len;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj += this_len;
11154e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->page_len);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (this_len)
11174e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		_copy_from_pages(obj, subbuf->pages, subbuf->page_base, this_len);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len -= this_len;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj += this_len;
11204e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
11214e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(obj, subbuf->tail[0].iov_base, this_len);
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1124bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher/* obj is assumed to point to allocated memory of size at least len: */
11254e3e43ad14c574281034a27420abf1993694ac11Trond Myklebustint read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
1126bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1127bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	struct xdr_buf subbuf;
1128bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	int status;
1129bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1130bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	status = xdr_buf_subsegment(buf, &subbuf, base, len);
11314e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	if (status != 0)
11324e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		return status;
11334e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	__read_bytes_from_xdr_buf(&subbuf, obj, len);
11344e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	return 0;
11354e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust}
1136468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(read_bytes_from_xdr_buf);
11374e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
11384e3e43ad14c574281034a27420abf1993694ac11Trond Myklebuststatic void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
11394e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust{
11404e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	unsigned int this_len;
11414e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
11424e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
11434e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(subbuf->head[0].iov_base, obj, this_len);
1144bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	len -= this_len;
1145bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	obj += this_len;
11464e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->page_len);
1147bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (this_len)
11484e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		_copy_to_pages(subbuf->pages, subbuf->page_base, obj, this_len);
1149bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	len -= this_len;
1150bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	obj += this_len;
11514e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
11524e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(subbuf->tail[0].iov_base, obj, this_len);
11534e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust}
11544e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
11554e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust/* obj is assumed to point to allocated memory of size at least len: */
11564e3e43ad14c574281034a27420abf1993694ac11Trond Myklebustint write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
11574e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust{
11584e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	struct xdr_buf subbuf;
11594e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	int status;
11604e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
11614e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	status = xdr_buf_subsegment(buf, &subbuf, base, len);
11624e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	if (status != 0)
11634e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		return status;
11644e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	__write_bytes_to_xdr_buf(&subbuf, obj, len);
11654e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	return 0;
1166bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1167c43abaedaff92a7bcbfe04b593164bb5faba3078Kevin CoffmanEXPORT_SYMBOL_GPL(write_bytes_to_xdr_buf);
1168bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1169bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
11701e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebustxdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1172d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32	raw;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	status;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status)
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return status;
117898866b5abe1513cdacc011874ca045d40002eccdBenny Halevy	*obj = be32_to_cpu(raw);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1181468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_word);
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1183bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
11841e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebustxdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
1185bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
11869f162d2a810b4db48f7b8d7e734d0932c81ec2a1Benny Halevy	__be32	raw = cpu_to_be32(obj);
1187bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1188bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
1189bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1190468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_word);
1191bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the netobj starting offset bytes from the start of xdr_buf is contained
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entirely in the head or the tail, set object to point to it; otherwise
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to find space for it at the end of the tail, copy it there, and
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set obj to point to it. */
1196bee57c99c322d64407b80c8171958b4384902da4Trond Myklebustint xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1198bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	struct xdr_buf subbuf;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1200bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (xdr_decode_word(buf, offset, &obj->len))
1201bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -EFAULT;
1202bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))
1203bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -EFAULT;
1204bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust
1205bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* Is the obj contained entirely in the head? */
1206bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	obj->data = subbuf.head[0].iov_base;
1207bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (subbuf.head[0].iov_len == obj->len)
1208bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return 0;
1209bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* ..or is the obj contained entirely in the tail? */
1210bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	obj->data = subbuf.tail[0].iov_base;
1211bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (subbuf.tail[0].iov_len == obj->len)
1212bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return 0;
1213bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust
1214bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* use end of tail as storage for obj:
1215bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * (We don't copy to the beginning because then we'd have
1216bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * to worry about doing a potentially overlapping copy.
1217bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * This assumes the object is at most half the length of the
1218bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * tail.) */
1219bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (obj->len > buf->buflen - buf->len)
1220bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -ENOMEM;
1221bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (buf->tail[0].iov_len != 0)
1222bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len;
1223bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	else
1224bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		obj->data = buf->head[0].iov_base + buf->head[0].iov_len;
1225bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	__read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1228468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_read_netobj);
1229bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1230bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher/* Returns 0 on success, or else a negative error code. */
1231bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherstatic int
1232bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_xcode_array2(struct xdr_buf *buf, unsigned int base,
1233bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		 struct xdr_array2_desc *desc, int encode)
1234bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1235bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	char *elem = NULL, *c;
1236bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	unsigned int copied = 0, todo, avail_here;
1237bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	struct page **ppages = NULL;
1238bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	int err;
1239bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1240bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (encode) {
1241bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (xdr_encode_word(buf, base, desc->array_len) != 0)
1242bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			return -EINVAL;
1243bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	} else {
1244bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||
124558fcb8df0bf663bb6b8f46cd3010bfe8d13d97cfTrond Myklebust		    desc->array_len > desc->array_maxlen ||
1246bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		    (unsigned long) base + 4 + desc->array_len *
1247bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				    desc->elem_size > buf->len)
1248bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			return -EINVAL;
1249bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1250bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base += 4;
1251bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1252bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (!desc->xcode)
1253bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return 0;
1254bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1255bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	todo = desc->array_len * desc->elem_size;
1256bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1257bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process head */
1258bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo && base < buf->head->iov_len) {
1259bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = buf->head->iov_base + base;
1260bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_here = min_t(unsigned int, todo,
1261bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				   buf->head->iov_len - base);
1262bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		todo -= avail_here;
1263bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1264bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (avail_here >= desc->elem_size) {
1265bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			err = desc->xcode(desc, c);
1266bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (err)
1267bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				goto out;
1268bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += desc->elem_size;
1269bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_here -= desc->elem_size;
1270bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1271bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (avail_here) {
1272bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (!elem) {
1273bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				elem = kmalloc(desc->elem_size, GFP_KERNEL);
1274bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = -ENOMEM;
1275bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem)
1276bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1277bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1278bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (encode) {
1279bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, elem);
1280bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1281bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1282bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(c, elem, avail_here);
1283bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			} else
1284bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(elem, c, avail_here);
1285bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			copied = avail_here;
1286bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1287bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base = buf->head->iov_len;  /* align to start of pages */
1288bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1289bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1290bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process pages array */
1291bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base -= buf->head->iov_len;
1292bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo && base < buf->page_len) {
1293bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		unsigned int avail_page;
1294bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1295bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_here = min(todo, buf->page_len - base);
1296bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		todo -= avail_here;
1297bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1298bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base += buf->page_base;
1299bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		ppages = buf->pages + (base >> PAGE_CACHE_SHIFT);
1300bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base &= ~PAGE_CACHE_MASK;
1301bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base,
1302bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					avail_here);
1303bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = kmap(*ppages) + base;
1304bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1305bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (avail_here) {
1306bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_here -= avail_page;
1307bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (copied || avail_page < desc->elem_size) {
1308bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				unsigned int l = min(avail_page,
1309bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					desc->elem_size - copied);
1310bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem) {
1311bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					elem = kmalloc(desc->elem_size,
1312bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						       GFP_KERNEL);
1313bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					err = -ENOMEM;
1314bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!elem)
1315bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						goto out;
1316bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1317bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (encode) {
1318bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!copied) {
1319bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1320bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1321bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1322bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1323bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(c, elem + copied, l);
1324bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1325bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size)
1326bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1327bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				} else {
1328bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(elem + copied, c, l);
1329bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1330bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size) {
1331bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1332bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1333bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1334bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1335bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1336bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1337bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				avail_page -= l;
1338bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c += l;
1339bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1340bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			while (avail_page >= desc->elem_size) {
1341bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, c);
1342bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1343bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1344bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c += desc->elem_size;
1345bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				avail_page -= desc->elem_size;
1346bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1347bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (avail_page) {
1348bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				unsigned int l = min(avail_page,
1349bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					    desc->elem_size - copied);
1350bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem) {
1351bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					elem = kmalloc(desc->elem_size,
1352bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						       GFP_KERNEL);
1353bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					err = -ENOMEM;
1354bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!elem)
1355bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						goto out;
1356bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1357bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (encode) {
1358bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!copied) {
1359bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1360bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1361bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1362bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1363bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(c, elem + copied, l);
1364bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1365bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size)
1366bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1367bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				} else {
1368bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(elem + copied, c, l);
1369bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1370bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size) {
1371bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1372bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1373bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1374bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1375bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1376bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1377bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1378bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (avail_here) {
1379bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				kunmap(*ppages);
1380bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				ppages++;
1381bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c = kmap(*ppages);
1382bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1383bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1384bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_page = min(avail_here,
1385bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				 (unsigned int) PAGE_CACHE_SIZE);
1386bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1387bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base = buf->page_len;  /* align to start of tail */
1388bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1389bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1390bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process tail */
1391bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base -= buf->page_len;
1392bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo) {
1393bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = buf->tail->iov_base + base;
1394bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (copied) {
1395bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			unsigned int l = desc->elem_size - copied;
1396bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1397bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (encode)
1398bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(c, elem + copied, l);
1399bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			else {
1400bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(elem + copied, c, l);
1401bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, elem);
1402bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1403bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1404bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1405bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			todo -= l;
1406bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += l;
1407bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1408bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (todo) {
1409bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			err = desc->xcode(desc, c);
1410bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (err)
1411bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				goto out;
1412bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += desc->elem_size;
1413bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			todo -= desc->elem_size;
1414bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1415bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1416bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	err = 0;
1417bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1418bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherout:
1419a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl	kfree(elem);
1420bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (ppages)
1421bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		kunmap(*ppages);
1422bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return err;
1423bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1424bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1425bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
1426bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_decode_array2(struct xdr_buf *buf, unsigned int base,
1427bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		  struct xdr_array2_desc *desc)
1428bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1429bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (base >= buf->len)
1430bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return -EINVAL;
1431bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1432bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return xdr_xcode_array2(buf, base, desc, 0);
1433bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1434468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_array2);
1435bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1436bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
1437bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_encode_array2(struct xdr_buf *buf, unsigned int base,
1438bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		  struct xdr_array2_desc *desc)
1439bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1440bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >
1441bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	    buf->head->iov_len + buf->page_len + buf->tail->iov_len)
1442bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return -EINVAL;
1443bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1444bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return xdr_xcode_array2(buf, base, desc, 1);
1445bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1446468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_array2);
144737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
144837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaint
144937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaxdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,
1450cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki		int (*actor)(struct scatterlist *, void *), void *data)
145137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia{
145237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	int i, ret = 0;
145395c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet	unsigned int page_len, thislen, page_offset;
145437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	struct scatterlist      sg[1];
145537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
145668e3f5dd4db62619fdbe520d36c9ebf62e672256Herbert Xu	sg_init_table(sg, 1);
145768e3f5dd4db62619fdbe520d36c9ebf62e672256Herbert Xu
145837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset >= buf->head[0].iov_len) {
145937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset -= buf->head[0].iov_len;
146037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	} else {
146137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = buf->head[0].iov_len - offset;
146237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (thislen > len)
146337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = len;
146437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		sg_set_buf(sg, buf->head[0].iov_base + offset, thislen);
146537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = actor(sg, data);
146637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (ret)
146737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			goto out;
146837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset = 0;
146937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= thislen;
147037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
147137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len == 0)
147237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		goto out;
147337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
147437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset >= buf->page_len) {
147537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset -= buf->page_len;
147637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	} else {
147737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		page_len = buf->page_len - offset;
147837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (page_len > len)
147937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_len = len;
148037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= page_len;
148137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1);
148237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT;
148337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = PAGE_CACHE_SIZE - page_offset;
148437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		do {
148537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			if (thislen > page_len)
148637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia				thislen = page_len;
1487642f149031d70415d9318b919d50b71e4724adbdJens Axboe			sg_set_page(sg, buf->pages[i], thislen, page_offset);
148837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			ret = actor(sg, data);
148937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			if (ret)
149037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia				goto out;
149137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_len -= thislen;
149237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			i++;
149337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_offset = 0;
149437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = PAGE_CACHE_SIZE;
149537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		} while (page_len != 0);
149637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset = 0;
149737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
149837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len == 0)
149937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		goto out;
150037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset < buf->tail[0].iov_len) {
150137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = buf->tail[0].iov_len - offset;
150237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (thislen > len)
150337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = len;
150437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen);
150537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = actor(sg, data);
150637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= thislen;
150737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
150837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len != 0)
150937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = -EINVAL;
151037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaout:
151137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	return ret;
151237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia}
1513468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_process_buf);
151437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
1515