xdr.c revision c337d3655ce85e12c7c476cb81406521926cacd2
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_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned int len)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *tail = xdr->tail;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *p;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->pages = pages;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_base = base;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_len = len;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_base = p;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_len = 0;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len & 3) {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int pad = 4 - (len & 3);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*p = 0;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tail->iov_base = (char *)p + (len & 3);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tail->iov_len  = pad;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len += pad;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buflen += len;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->len += len;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
157468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_pages);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct page **pages, unsigned int base, unsigned int len)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *head = xdr->head;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *tail = xdr->tail;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *buf = (char *)head->iov_base;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int buflen = head->iov_len;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->iov_len  = offset;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->pages = pages;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_base = base;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->page_len = len;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_base = buf + offset;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail->iov_len = buflen - offset;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buflen += len;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
179468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_inline_pages);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Helper routines for doing 'memmove' like operations on a struct xdr_buf
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _shift_data_right_pages
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: vector of pages containing both the source and dest memory area.
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgto_base: page vector address of destination
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgfrom_base: page vector address of source
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: number of bytes to copy
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: the addresses pgto_base and pgfrom_base are both calculated in
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *       the same way:
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            if a memory area starts at byte 'base' in page 'pages[i]',
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            then its address is given as (i << PAGE_CACHE_SHIFT) + base
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also note: pgfrom_base must be < pgto_base, but the memory areas
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	they point to may overlap.
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_shift_data_right_pages(struct page **pages, size_t pgto_base,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t pgfrom_base, size_t len)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgfrom, **pgto;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vfrom, *vto;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(pgto_base <= pgfrom_base);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto_base += len;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom_base += len;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto = pages + (pgto_base >> PAGE_CACHE_SHIFT);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom = pages + (pgfrom_base >> PAGE_CACHE_SHIFT);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto_base &= ~PAGE_CACHE_MASK;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom_base &= ~PAGE_CACHE_MASK;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Are any pointers crossing a page boundary? */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgto_base == 0) {
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto_base = PAGE_CACHE_SIZE;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto--;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgfrom_base == 0) {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom_base = PAGE_CACHE_SIZE;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom--;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pgto_base)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pgto_base;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pgfrom_base)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pgfrom_base;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgto_base -= copy;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgfrom_base -= copy;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
235b85417860172ff693dc115d7999805fc240cec1cCong Wang		vto = kmap_atomic(*pgto);
236b85417860172ff693dc115d7999805fc240cec1cCong Wang		vfrom = kmap_atomic(*pgfrom);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
238bce3481c91801665e17f8daf59ede946129f3d3fTrond Myklebust		flush_dcache_page(*pgto);
239b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vfrom);
240b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vto);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((len -= copy) != 0);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _copy_to_pages
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: array of pages
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgbase: page vector address of destination
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: pointer to source data
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies data from an arbitrary memory location into an array of pages
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The copy is assumed to be non-overlapping.
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgto;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vto;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgto = pages + (pgbase >> PAGE_CACHE_SHIFT);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgbase &= ~PAGE_CACHE_MASK;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
265daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust	for (;;) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = PAGE_CACHE_SIZE - pgbase;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
270b85417860172ff693dc115d7999805fc240cec1cCong Wang		vto = kmap_atomic(*pgto);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(vto + pgbase, p, copy);
272b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vto);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
274daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust		len -= copy;
275daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust		if (len == 0)
276daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust			break;
277daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgbase += copy;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgbase == PAGE_CACHE_SIZE) {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flush_dcache_page(*pgto);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgbase = 0;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgto++;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += copy;
285daeba89d43af0fa469d38a4ccdc32fff8ca17c2eTrond Myklebust	}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_dcache_page(*pgto);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * _copy_from_pages
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: pointer to destination
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: array of pages
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pgbase: offset of source data
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies data into an arbitrary memory location from an array of pages
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The copy is assumed to be non-overlapping.
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
299bf118a342f10dafe44b14451a1392c3254629a1fAndy Adamsonvoid
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page **pgfrom;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vfrom;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgfrom = pages + (pgbase >> PAGE_CACHE_SHIFT);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgbase &= ~PAGE_CACHE_MASK;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = PAGE_CACHE_SIZE - pgbase;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
314b85417860172ff693dc115d7999805fc240cec1cCong Wang		vfrom = kmap_atomic(*pgfrom);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(p, vfrom + pgbase, copy);
316b85417860172ff693dc115d7999805fc240cec1cCong Wang		kunmap_atomic(vfrom);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgbase += copy;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pgbase == PAGE_CACHE_SIZE) {
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgbase = 0;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pgfrom++;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += copy;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((len -= copy) != 0);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
327bf118a342f10dafe44b14451a1392c3254629a1fAndy AdamsonEXPORT_SYMBOL_GPL(_copy_from_pages);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_shrink_bufhead
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: xdr_buf
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: bytes to remove from buf->head[0]
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
334cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki * Shrinks XDR buffer's header kvec buf->head[0] by
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'len' bytes. The extra data is not lost, but is instead
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved into the inlined pages and/or the tail.
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *head, *tail;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy, offs;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pglen = buf->page_len;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = buf->tail;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head = buf->head;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON (len > head->iov_len);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the tail first */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tail->iov_len != 0) {
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tail->iov_len > len) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len - len;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove((char *)tail->iov_base + len,
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tail->iov_base, copy);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy from the inlined pages into the tail */
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > pglen)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pglen;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offs = len - copy;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (offs >= tail->iov_len)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (copy > tail->iov_len - offs)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len - offs;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy != 0)
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_copy_from_pages((char *)tail->iov_base + offs,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->pages,
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base + pglen + offs - len,
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Do we also need to copy data from the head into the tail ? */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > pglen) {
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = copy = len - pglen;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy > tail->iov_len)
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy = tail->iov_len;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(tail->iov_base,
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(char *)head->iov_base +
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->iov_len - offs,
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now handle pages */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pglen != 0) {
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pglen > len)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_shift_data_right_pages(buf->pages,
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base + len,
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf->page_base,
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pglen - len);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copy = len;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > pglen)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = pglen;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_copy_to_pages(buf->pages, buf->page_base,
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(char *)head->iov_base + head->iov_len - len,
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->iov_len -= len;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen -= len;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Have we truncated the message? */
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf->len > buf->buflen)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf->len = buf->buflen;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_shrink_pagelen
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: xdr_buf
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: bytes to remove from buf->pages
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
407cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki * Shrinks XDR buffer's page array buf->pages by
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'len' bytes. The extra data is not lost, but is instead
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved into the tail.
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *tail;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t copy;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pglen = buf->page_len;
417cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	unsigned int tailbuf_len;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tail = buf->tail;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON (len > pglen);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
422cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len;
423cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the tail first */
425cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust	if (tailbuf_len != 0) {
426cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		unsigned int free_space = tailbuf_len - tail->iov_len;
427cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
428cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		if (len < free_space)
429cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust			free_space = len;
430cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust		tail->iov_len += free_space;
431cf187c2d7ec763cdd459fe43933a5cc4f5f48e1bTrond Myklebust
43242d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		copy = len;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tail->iov_len > len) {
4340fe62a35903e11fb41b492bd5b0e8e4c751d5c94Benny Halevy			char *p = (char *)tail->iov_base + len;
4352e29ebb8119e6037133921fac09cc5f9d625b511Benny Halevy			memmove(p, tail->iov_base, tail->iov_len - len);
43642d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		} else
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = tail->iov_len;
43842d6d8ab51ca04afcb8a64759076da624cdb71e8Benny Halevy		/* Copy from the inlined pages into the tail */
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_copy_from_pages((char *)tail->iov_base,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				buf->pages, buf->page_base + pglen - len,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len -= len;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen -= len;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Have we truncated the message? */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf->len > buf->buflen)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf->len = buf->buflen;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_shift_buf(struct xdr_buf *buf, size_t len)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr_shrink_bufhead(buf, len);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
455468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_shift_buf);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_init_encode - Initialize a struct xdr_stream for sending data.
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: pointer to XDR buffer in which to encode data
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: current pointer inside XDR buffer
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: at the moment the RPC client only passes the length of our
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 scratch buffer in the xdr_buf's header kvec. Previously this
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 meant we needed to call xdr_adjust_iovec() after encoding the
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 data. With the new scheme, the xdr_stream manages the details
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 of the buffer length, and takes care of adjusting the kvec
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 length for us.
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
470d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanvoid xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov = buf->head;
473334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
475334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	BUG_ON(scratch_len < 0);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf = buf;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov;
478d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
479d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
480334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	BUG_ON(iov->iov_len > scratch_len);
481334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust
482334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	if (p != xdr->p && p != NULL) {
483334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		size_t len;
484334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust
485334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		BUG_ON(p < xdr->p || p > xdr->end);
486334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		len = (char *)p - (char *)xdr->p;
487334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		xdr->p = p;
488334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		buf->len += len;
489334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust		iov->iov_len += len;
490334ccfd545bba9690515f2c5c167d5adb161989bTrond Myklebust	}
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
492468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_init_encode);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_reserve_space - Reserve buffer space for sending
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @nbytes: number of bytes to reserve
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Checks that we have enough buffer space to encode 'nbytes' more
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes of data. If so, update the total xdr_buf length, and
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adjust the length of the current kvec.
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
503d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
505d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32 *p = xdr->p;
506d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32 *q;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* align nbytes on the next 32-bit boundary */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nbytes += 3;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nbytes &= ~3;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q = p + (nbytes >> 2);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(q > xdr->end || q < p))
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->p = q;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov->iov_len += nbytes;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf->len += nbytes;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
519468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_reserve_space);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @pages: list of pages
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @base: offset of first byte
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: length of data in bytes
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned int len)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xdr_buf *buf = xdr->buf;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov = buf->tail;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->pages = pages;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_base = base;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len = len;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov->iov_base = (char *)xdr->p;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov->iov_len  = 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len & 3) {
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int pad = 4 - (len & 3);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(xdr->p >= xdr->end);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_base = (char *)xdr->p + (len & 3);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_len  += pad;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len += pad;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*xdr->p++ = 0;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen += len;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->len += len;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
554468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_write_pages);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5566650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
5571537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		unsigned int len)
5586650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
5596650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (len > iov->iov_len)
5606650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		len = iov->iov_len;
5611537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust	xdr->p = (__be32*)iov->iov_base;
5626650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->end = (__be32*)(iov->iov_base + len);
5636650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->iov = iov;
5646650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->page_ptr = NULL;
5656650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
5666650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5676650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic int xdr_set_page_base(struct xdr_stream *xdr,
5686650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		unsigned int base, unsigned int len)
5696650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
5706650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgnr;
5716650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int maxlen;
5726650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgoff;
5736650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int pgend;
5746650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	void *kaddr;
5756650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5766650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	maxlen = xdr->buf->page_len;
5776650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (base >= maxlen)
5786650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return -EINVAL;
5796650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	maxlen -= base;
5806650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (len > maxlen)
5816650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		len = maxlen;
5826650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5836650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	base += xdr->buf->page_base;
5846650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5856650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgnr = base >> PAGE_SHIFT;
5866650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->page_ptr = &xdr->buf->pages[pgnr];
5876650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	kaddr = page_address(*xdr->page_ptr);
5886650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5896650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgoff = base & ~PAGE_MASK;
5906650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->p = (__be32*)(kaddr + pgoff);
5916650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
5926650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	pgend = pgoff + len;
5936650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (pgend > PAGE_SIZE)
5946650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		pgend = PAGE_SIZE;
5956650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->end = (__be32*)(kaddr + pgend);
5966650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->iov = NULL;
5976650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return 0;
5986650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
5996650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6006650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic void xdr_set_next_page(struct xdr_stream *xdr)
6016650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
6026650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	unsigned int newbase;
6036650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6046650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
6056650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	newbase -= xdr->buf->page_base;
6066650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6076650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
6081537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
6096650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
6106650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6116650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic bool xdr_set_next_buffer(struct xdr_stream *xdr)
6126650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
6136650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr->page_ptr != NULL)
6146650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		xdr_set_next_page(xdr);
6156650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	else if (xdr->iov == xdr->buf->head) {
6166650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
6171537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust			xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
6186650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	}
6196650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr->p != xdr->end;
6206650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
6216650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_init_decode - Initialize an xdr_stream for decoding data.
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @buf: pointer to XDR buffer from which to decode data
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @p: current pointer inside XDR buffer
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
628d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyanvoid xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->buf = buf;
6316650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_base = NULL;
6326650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_len = 0;
633bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords = XDR_QUADLEN(buf->len);
6346650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (buf->head[0].iov_len != 0)
6351537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr_set_iov(xdr, buf->head, buf->len);
6366650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	else if (buf->page_len != 0)
6376650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		xdr_set_page_base(xdr, 0, buf->len);
638bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (p != NULL && p > xdr->p && xdr->end >= p) {
639bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust		xdr->nwords -= p - xdr->p;
6401537693ceaa8d6484f1ce631bec85658bfa9816cTrond Myklebust		xdr->p = p;
641bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
643468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_init_decode);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
645f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy/**
646f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * xdr_init_decode - Initialize an xdr_stream for decoding data.
647f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @xdr: pointer to xdr_stream struct
648f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @buf: pointer to XDR buffer from which to decode data
649f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @pages: list of pages to decode into
650f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy * @len: length in bytes of buffer in pages
651f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy */
652f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevyvoid xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
653f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy			   struct page **pages, unsigned int len)
654f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy{
655f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	memset(buf, 0, sizeof(*buf));
656f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->pages =  pages;
657f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->page_len =  len;
658f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->buflen =  len;
659f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	buf->len = len;
660f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy	xdr_init_decode(xdr, buf, NULL);
661f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy}
662f7da7a129d57bfe0f74573dc03531c63e1360faeBenny HalevyEXPORT_SYMBOL_GPL(xdr_init_decode_pages);
663f7da7a129d57bfe0f74573dc03531c63e1360faeBenny Halevy
6646650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
665ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust{
666bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	unsigned int nwords = XDR_QUADLEN(nbytes);
667ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust	__be32 *p = xdr->p;
668bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	__be32 *q = p + nwords;
669ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust
670bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
671ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust		return NULL;
6726650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->p = q;
673bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords -= nwords;
674ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust	return p;
675ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust}
676ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust
677ba8e452a4fe64a51b74d43761e14d99f0666cc45Trond Myklebust/**
6786650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
6796650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @xdr: pointer to xdr_stream struct
6806650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @buf: pointer to an empty buffer
6816650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * @buflen: size of 'buf'
6826650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust *
6836650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * The scratch buffer is used when decoding from an array of pages.
6846650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * If an xdr_inline_decode() call spans across page boundaries, then
6856650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * we copy the data into the scratch buffer in order to allow linear
6866650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * access.
6876650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust */
6886650239a4b01077e80d5a4468562756d77afaa59Trond Myklebustvoid xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
6896650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
6906650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_base = buf;
6916650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr->scratch.iov_len = buflen;
6926650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
6936650239a4b01077e80d5a4468562756d77afaa59Trond MyklebustEXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
6946650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
6956650239a4b01077e80d5a4468562756d77afaa59Trond Myklebuststatic __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
6966650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust{
6976650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	__be32 *p;
6986650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	void *cpdest = xdr->scratch.iov_base;
6996650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	size_t cplen = (char *)xdr->end - (char *)xdr->p;
7006650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7016650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (nbytes > xdr->scratch.iov_len)
7026650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
7036650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	memcpy(cpdest, xdr->p, cplen);
7046650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	cpdest += cplen;
7056650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	nbytes -= cplen;
7066650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (!xdr_set_next_buffer(xdr))
7076650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
7086650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	p = __xdr_inline_decode(xdr, nbytes);
7096650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (p == NULL)
7106650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return NULL;
7116650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	memcpy(cpdest, p, nbytes);
7126650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr->scratch.iov_base;
7136650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust}
7146650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust
7156650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust/**
7166650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust * xdr_inline_decode - Retrieve XDR data to decode
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @nbytes: number of bytes of data to decode
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check if the input buffer is long enough to enable us to decode
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'nbytes' more bytes of data starting at the current position.
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If so return the current pointer, then update the current
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointer position.
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
725d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7276650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	__be32 *p;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7296650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (nbytes == 0)
7306650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return xdr->p;
7316650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
7336650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	p = __xdr_inline_decode(xdr, nbytes);
7346650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	if (p != NULL)
7356650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust		return p;
7366650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	return xdr_copy_to_scratch(xdr, nbytes);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
738468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_inline_decode);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @xdr: pointer to xdr_stream struct
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: number of bytes of page data
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Moves data beyond the current pointer position from the XDR head[] buffer
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into the page list. Any data that lies beyond current position + "len"
7478b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * bytes is moved into the XDR tail[].
748c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust *
749c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust * Returns the number of XDR encoded bytes now contained in the pages
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
751c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebustunsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xdr_buf *buf = xdr->buf;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kvec *iov;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t shift;
756bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	unsigned int nwords = XDR_QUADLEN(len);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int end;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int padding;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
760bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (xdr->nwords == 0)
761c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust		return 0;
762bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (nwords > xdr->nwords) {
763bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust		nwords = xdr->nwords;
764bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust		len = nwords << 2;
765bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Realign pages to current pointer position */
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iov  = buf->head;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (shift > 0)
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xdr_shrink_bufhead(buf, shift);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Truncate page data and move it into the tail */
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf->page_len > len)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xdr_shrink_pagelen(buf, buf->page_len - len);
775bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	padding = (nwords << 2) - len;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xdr->iov = iov = buf->tail;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compute remaining message length.  */
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = iov->iov_len;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	shift = buf->buflen - buf->len;
780bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	if (end > shift + padding)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		end -= shift;
782bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	else
783bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust		end = padding;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Position current pointer at beginning of tail, and
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set remaining message length.
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
788d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->p = (__be32 *)((char *)iov->iov_base + padding);
789d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	xdr->end = (__be32 *)((char *)iov->iov_base + end);
79076cacaabf15a593833d96a65a1a251002bd88178Trond Myklebust	xdr->page_ptr = NULL;
791bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords = XDR_QUADLEN(end - padding);
792c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust	return len;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
794468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_read_pages);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7968b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust/**
7978b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * xdr_enter_page - decode data from the XDR page
7988b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * @xdr: pointer to xdr_stream struct
7998b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * @len: number of bytes of page data
8008b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust *
8018b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * Moves data beyond the current pointer position from the XDR head[] buffer
8028b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * into the page list. Any data that lies beyond current position + "len"
8038b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * bytes is moved into the XDR tail[]. The current pointer is then
8048b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust * repositioned at the beginning of the first XDR page.
8058b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust */
8068b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebustvoid xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
8078b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust{
808c337d3655ce85e12c7c476cb81406521926cacd2Trond Myklebust	len = xdr_read_pages(xdr, len);
8098b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	/*
8108b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 * Position current pointer at beginning of tail, and
8118b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 * set remaining message length.
8128b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust	 */
8136650239a4b01077e80d5a4468562756d77afaa59Trond Myklebust	xdr_set_page_base(xdr, 0, len);
814bfeea1dc1c9238f9e5a17a265489ecd0d19f66bbTrond Myklebust	xdr->nwords += XDR_QUADLEN(xdr->buf->page_len);
8158b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust}
816468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_enter_page);
8178b23ea7bedb8b45a5bb56745fa3ff11018acf04eTrond Myklebust
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->head[0] = *iov;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->tail[0] = empty_iov;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->page_len = 0;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->buflen = buf->len = iov->iov_len;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
828468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_from_iov);
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sets subbuf to the portion of buf of length len beginning base bytes
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the start of buf. Returns -1 if base of length are out of bounds. */
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsxdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
8341e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust			unsigned int base, unsigned int len)
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	subbuf->buflen = subbuf->len = len;
8371e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	if (base < buf->head[0].iov_len) {
8381e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_base = buf->head[0].iov_base + base;
8391e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_len = min_t(unsigned int, len,
8401e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust						buf->head[0].iov_len - base);
8411e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		len -= subbuf->head[0].iov_len;
8421e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base = 0;
8431e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	} else {
8441e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_base = NULL;
8451e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->head[0].iov_len = 0;
8461e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base -= buf->head[0].iov_len;
8471e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (base < buf->page_len) {
8501e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->page_len = min(buf->page_len - base, len);
8511e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base += buf->page_base;
8521e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->page_base = base & ~PAGE_CACHE_MASK;
8531e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->pages = &buf->pages[base >> PAGE_CACHE_SHIFT];
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len -= subbuf->page_len;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		base = 0;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		base -= buf->page_len;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		subbuf->page_len = 0;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8611e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	if (base < buf->tail[0].iov_len) {
8621e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_base = buf->tail[0].iov_base + base;
8631e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_len = min_t(unsigned int, len,
8641e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust						buf->tail[0].iov_len - base);
8651e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		len -= subbuf->tail[0].iov_len;
8661e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base = 0;
8671e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	} else {
8681e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_base = NULL;
8691e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		subbuf->tail[0].iov_len = 0;
8701e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust		base -= buf->tail[0].iov_len;
8711e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	}
8721e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (base || len)
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
877468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_subsegment);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8794e3e43ad14c574281034a27420abf1993694ac11Trond Myklebuststatic void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8811e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebust	unsigned int this_len;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8834e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
8844e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(obj, subbuf->head[0].iov_base, this_len);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len -= this_len;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj += this_len;
8874e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->page_len);
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (this_len)
8894e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		_copy_from_pages(obj, subbuf->pages, subbuf->page_base, this_len);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len -= this_len;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj += this_len;
8924e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
8934e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(obj, subbuf->tail[0].iov_base, this_len);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
896bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher/* obj is assumed to point to allocated memory of size at least len: */
8974e3e43ad14c574281034a27420abf1993694ac11Trond Myklebustint read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
898bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
899bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	struct xdr_buf subbuf;
900bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	int status;
901bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
902bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	status = xdr_buf_subsegment(buf, &subbuf, base, len);
9034e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	if (status != 0)
9044e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		return status;
9054e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	__read_bytes_from_xdr_buf(&subbuf, obj, len);
9064e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	return 0;
9074e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust}
908468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(read_bytes_from_xdr_buf);
9094e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
9104e3e43ad14c574281034a27420abf1993694ac11Trond Myklebuststatic void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
9114e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust{
9124e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	unsigned int this_len;
9134e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
9144e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
9154e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(subbuf->head[0].iov_base, obj, this_len);
916bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	len -= this_len;
917bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	obj += this_len;
9184e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->page_len);
919bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (this_len)
9204e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		_copy_to_pages(subbuf->pages, subbuf->page_base, obj, this_len);
921bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	len -= this_len;
922bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	obj += this_len;
9234e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
9244e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	memcpy(subbuf->tail[0].iov_base, obj, this_len);
9254e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust}
9264e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
9274e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust/* obj is assumed to point to allocated memory of size at least len: */
9284e3e43ad14c574281034a27420abf1993694ac11Trond Myklebustint write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
9294e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust{
9304e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	struct xdr_buf subbuf;
9314e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	int status;
9324e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust
9334e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	status = xdr_buf_subsegment(buf, &subbuf, base, len);
9344e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	if (status != 0)
9354e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust		return status;
9364e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	__write_bytes_to_xdr_buf(&subbuf, obj, len);
9374e3e43ad14c574281034a27420abf1993694ac11Trond Myklebust	return 0;
938bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
939c43abaedaff92a7bcbfe04b593164bb5faba3078Kevin CoffmanEXPORT_SYMBOL_GPL(write_bytes_to_xdr_buf);
940bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
941bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
9421e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebustxdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
944d8ed029d6000ba2e2908d9286409e4833c091b4cAlexey Dobriyan	__be32	raw;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	status;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status)
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return status;
95098866b5abe1513cdacc011874ca045d40002eccdBenny Halevy	*obj = be32_to_cpu(raw);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
953468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_word);
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
955bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
9561e78957e0a8f882df6a3660b62f9aae441f54891Trond Myklebustxdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
957bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
9589f162d2a810b4db48f7b8d7e734d0932c81ec2a1Benny Halevy	__be32	raw = cpu_to_be32(obj);
959bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
960bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
961bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
962468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_word);
963bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the netobj starting offset bytes from the start of xdr_buf is contained
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entirely in the head or the tail, set object to point to it; otherwise
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to find space for it at the end of the tail, copy it there, and
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set obj to point to it. */
968bee57c99c322d64407b80c8171958b4384902da4Trond Myklebustint xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
970bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	struct xdr_buf subbuf;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
972bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (xdr_decode_word(buf, offset, &obj->len))
973bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -EFAULT;
974bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))
975bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -EFAULT;
976bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust
977bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* Is the obj contained entirely in the head? */
978bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	obj->data = subbuf.head[0].iov_base;
979bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (subbuf.head[0].iov_len == obj->len)
980bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return 0;
981bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* ..or is the obj contained entirely in the tail? */
982bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	obj->data = subbuf.tail[0].iov_base;
983bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (subbuf.tail[0].iov_len == obj->len)
984bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return 0;
985bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust
986bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	/* use end of tail as storage for obj:
987bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * (We don't copy to the beginning because then we'd have
988bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * to worry about doing a potentially overlapping copy.
989bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * This assumes the object is at most half the length of the
990bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	 * tail.) */
991bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (obj->len > buf->buflen - buf->len)
992bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		return -ENOMEM;
993bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	if (buf->tail[0].iov_len != 0)
994bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len;
995bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	else
996bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust		obj->data = buf->head[0].iov_base + buf->head[0].iov_len;
997bee57c99c322d64407b80c8171958b4384902da4Trond Myklebust	__read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1000468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_buf_read_netobj);
1001bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1002bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher/* Returns 0 on success, or else a negative error code. */
1003bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherstatic int
1004bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_xcode_array2(struct xdr_buf *buf, unsigned int base,
1005bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		 struct xdr_array2_desc *desc, int encode)
1006bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1007bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	char *elem = NULL, *c;
1008bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	unsigned int copied = 0, todo, avail_here;
1009bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	struct page **ppages = NULL;
1010bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	int err;
1011bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1012bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (encode) {
1013bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (xdr_encode_word(buf, base, desc->array_len) != 0)
1014bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			return -EINVAL;
1015bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	} else {
1016bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||
101758fcb8df0bf663bb6b8f46cd3010bfe8d13d97cfTrond Myklebust		    desc->array_len > desc->array_maxlen ||
1018bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		    (unsigned long) base + 4 + desc->array_len *
1019bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				    desc->elem_size > buf->len)
1020bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			return -EINVAL;
1021bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1022bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base += 4;
1023bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1024bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (!desc->xcode)
1025bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return 0;
1026bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1027bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	todo = desc->array_len * desc->elem_size;
1028bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1029bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process head */
1030bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo && base < buf->head->iov_len) {
1031bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = buf->head->iov_base + base;
1032bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_here = min_t(unsigned int, todo,
1033bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				   buf->head->iov_len - base);
1034bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		todo -= avail_here;
1035bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1036bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (avail_here >= desc->elem_size) {
1037bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			err = desc->xcode(desc, c);
1038bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (err)
1039bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				goto out;
1040bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += desc->elem_size;
1041bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_here -= desc->elem_size;
1042bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1043bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (avail_here) {
1044bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (!elem) {
1045bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				elem = kmalloc(desc->elem_size, GFP_KERNEL);
1046bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = -ENOMEM;
1047bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem)
1048bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1049bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1050bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (encode) {
1051bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, elem);
1052bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1053bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1054bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(c, elem, avail_here);
1055bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			} else
1056bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(elem, c, avail_here);
1057bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			copied = avail_here;
1058bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1059bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base = buf->head->iov_len;  /* align to start of pages */
1060bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1061bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1062bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process pages array */
1063bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base -= buf->head->iov_len;
1064bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo && base < buf->page_len) {
1065bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		unsigned int avail_page;
1066bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1067bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_here = min(todo, buf->page_len - base);
1068bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		todo -= avail_here;
1069bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1070bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base += buf->page_base;
1071bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		ppages = buf->pages + (base >> PAGE_CACHE_SHIFT);
1072bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base &= ~PAGE_CACHE_MASK;
1073bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base,
1074bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					avail_here);
1075bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = kmap(*ppages) + base;
1076bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1077bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (avail_here) {
1078bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_here -= avail_page;
1079bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (copied || avail_page < desc->elem_size) {
1080bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				unsigned int l = min(avail_page,
1081bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					desc->elem_size - copied);
1082bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem) {
1083bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					elem = kmalloc(desc->elem_size,
1084bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						       GFP_KERNEL);
1085bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					err = -ENOMEM;
1086bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!elem)
1087bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						goto out;
1088bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1089bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (encode) {
1090bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!copied) {
1091bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1092bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1093bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1094bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1095bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(c, elem + copied, l);
1096bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1097bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size)
1098bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1099bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				} else {
1100bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(elem + copied, c, l);
1101bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1102bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size) {
1103bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1104bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1105bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1106bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1107bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1108bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1109bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				avail_page -= l;
1110bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c += l;
1111bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1112bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			while (avail_page >= desc->elem_size) {
1113bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, c);
1114bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1115bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1116bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c += desc->elem_size;
1117bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				avail_page -= desc->elem_size;
1118bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1119bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (avail_page) {
1120bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				unsigned int l = min(avail_page,
1121bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					    desc->elem_size - copied);
1122bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (!elem) {
1123bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					elem = kmalloc(desc->elem_size,
1124bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						       GFP_KERNEL);
1125bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					err = -ENOMEM;
1126bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!elem)
1127bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						goto out;
1128bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1129bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (encode) {
1130bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (!copied) {
1131bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1132bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1133bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1134bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1135bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(c, elem + copied, l);
1136bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1137bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size)
1138bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1139bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				} else {
1140bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					memcpy(elem + copied, c, l);
1141bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					copied += l;
1142bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					if (copied == desc->elem_size) {
1143bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						err = desc->xcode(desc, elem);
1144bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						if (err)
1145bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher							goto out;
1146bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher						copied = 0;
1147bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					}
1148bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				}
1149bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1150bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (avail_here) {
1151bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				kunmap(*ppages);
1152bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				ppages++;
1153bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				c = kmap(*ppages);
1154bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1155bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1156bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			avail_page = min(avail_here,
1157bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				 (unsigned int) PAGE_CACHE_SIZE);
1158bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1159bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		base = buf->page_len;  /* align to start of tail */
1160bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1161bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1162bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	/* process tail */
1163bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	base -= buf->page_len;
1164bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (todo) {
1165bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		c = buf->tail->iov_base + base;
1166bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		if (copied) {
1167bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			unsigned int l = desc->elem_size - copied;
1168bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1169bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (encode)
1170bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(c, elem + copied, l);
1171bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			else {
1172bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				memcpy(elem + copied, c, l);
1173bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				err = desc->xcode(desc, elem);
1174bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				if (err)
1175bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher					goto out;
1176bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			}
1177bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			todo -= l;
1178bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += l;
1179bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1180bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		while (todo) {
1181bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			err = desc->xcode(desc, c);
1182bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			if (err)
1183bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher				goto out;
1184bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			c += desc->elem_size;
1185bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher			todo -= desc->elem_size;
1186bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		}
1187bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	}
1188bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	err = 0;
1189bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1190bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherout:
1191a51482bde22f99c63fbbb57d5d46cc666384e379Jesper Juhl	kfree(elem);
1192bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (ppages)
1193bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		kunmap(*ppages);
1194bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return err;
1195bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1196bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1197bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
1198bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_decode_array2(struct xdr_buf *buf, unsigned int base,
1199bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		  struct xdr_array2_desc *desc)
1200bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1201bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if (base >= buf->len)
1202bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return -EINVAL;
1203bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1204bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return xdr_xcode_array2(buf, base, desc, 0);
1205bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1206468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_decode_array2);
1207bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1208bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherint
1209bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacherxdr_encode_array2(struct xdr_buf *buf, unsigned int base,
1210bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		  struct xdr_array2_desc *desc)
1211bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher{
1212bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >
1213bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	    buf->head->iov_len + buf->page_len + buf->tail->iov_len)
1214bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher		return -EINVAL;
1215bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher
1216bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher	return xdr_xcode_array2(buf, base, desc, 1);
1217bd8100e7eda87507649c6ba4cb32173b34e49986Andreas Gruenbacher}
1218468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_encode_array2);
121937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
122037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaint
122137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaxdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,
1222cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793YOSHIFUJI Hideaki		int (*actor)(struct scatterlist *, void *), void *data)
122337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia{
122437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	int i, ret = 0;
122595c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet	unsigned int page_len, thislen, page_offset;
122637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	struct scatterlist      sg[1];
122737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
122868e3f5dd4db62619fdbe520d36c9ebf62e672256Herbert Xu	sg_init_table(sg, 1);
122968e3f5dd4db62619fdbe520d36c9ebf62e672256Herbert Xu
123037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset >= buf->head[0].iov_len) {
123137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset -= buf->head[0].iov_len;
123237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	} else {
123337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = buf->head[0].iov_len - offset;
123437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (thislen > len)
123537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = len;
123637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		sg_set_buf(sg, buf->head[0].iov_base + offset, thislen);
123737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = actor(sg, data);
123837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (ret)
123937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			goto out;
124037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset = 0;
124137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= thislen;
124237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
124337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len == 0)
124437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		goto out;
124537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
124637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset >= buf->page_len) {
124737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset -= buf->page_len;
124837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	} else {
124937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		page_len = buf->page_len - offset;
125037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (page_len > len)
125137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_len = len;
125237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= page_len;
125337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1);
125437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT;
125537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = PAGE_CACHE_SIZE - page_offset;
125637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		do {
125737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			if (thislen > page_len)
125837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia				thislen = page_len;
1259642f149031d70415d9318b919d50b71e4724adbdJens Axboe			sg_set_page(sg, buf->pages[i], thislen, page_offset);
126037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			ret = actor(sg, data);
126137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			if (ret)
126237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia				goto out;
126337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_len -= thislen;
126437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			i++;
126537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			page_offset = 0;
126637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = PAGE_CACHE_SIZE;
126737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		} while (page_len != 0);
126837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		offset = 0;
126937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
127037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len == 0)
127137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		goto out;
127237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (offset < buf->tail[0].iov_len) {
127337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		thislen = buf->tail[0].iov_len - offset;
127437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		if (thislen > len)
127537a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia			thislen = len;
127637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen);
127737a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = actor(sg, data);
127837a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		len -= thislen;
127937a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	}
128037a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	if (len != 0)
128137a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia		ret = -EINVAL;
128237a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaiaout:
128337a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia	return ret;
128437a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia}
1285468039ee469c5772d3e39f736923c5e0c31017e2Trond MyklebustEXPORT_SYMBOL_GPL(xdr_process_buf);
128637a4e6cb0391f2293ba3d59e3a63ec0e56ed720dOlga Kornievskaia
1287