patch-2.4.20 linux-2.4.20/net/sunrpc/xdr.c
Next file: linux-2.4.20/net/sunrpc/xprt.c
Previous file: linux-2.4.20/net/sunrpc/timer.c
Back to the patch index
Back to the overall index
- Lines: 224
- Date:
Thu Nov 28 15:53:16 2002
- Orig file:
linux-2.4.19/net/sunrpc/xdr.c
- Orig date:
Mon Oct 1 09:19:56 2001
diff -urN linux-2.4.19/net/sunrpc/xdr.c linux-2.4.20/net/sunrpc/xdr.c
@@ -10,6 +10,8 @@
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
#include <linux/in.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
@@ -100,6 +102,46 @@
}
+void
+xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
+ unsigned int len)
+{
+ xdr->pages = pages;
+ xdr->page_base = base;
+ xdr->page_len = len;
+
+ if (len & 3) {
+ struct iovec *iov = xdr->tail;
+ unsigned int pad = 4 - (len & 3);
+
+ iov->iov_base = (void *) "\0\0\0";
+ iov->iov_len = pad;
+ len += pad;
+ }
+ xdr->len += len;
+}
+
+void
+xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
+ struct page **pages, unsigned int base, unsigned int len)
+{
+ struct iovec *head = xdr->head;
+ struct iovec *tail = xdr->tail;
+ char *buf = (char *)head->iov_base;
+ unsigned int buflen = head->iov_len;
+
+ head->iov_len = offset;
+
+ xdr->pages = pages;
+ xdr->page_base = base;
+ xdr->page_len = len;
+
+ tail->iov_base = buf + offset;
+ tail->iov_len = buflen - offset;
+
+ xdr->len += len;
+}
+
/*
* Realign the iovec if the server missed out some reply elements
* (such as post-op attributes,...)
@@ -132,19 +174,157 @@
}
/*
- * Zero the last n bytes in an iovec array of 'nr' elements
+ * Map a struct xdr_buf into an iovec array.
*/
-void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
{
- struct iovec *pvec;
+ struct iovec *iov = iov_base;
+ struct page **ppage = xdr->pages;
+ unsigned int len, pglen = xdr->page_len;
+
+ len = xdr->head[0].iov_len;
+ if (base < len) {
+ iov->iov_len = len - base;
+ iov->iov_base = (char *)xdr->head[0].iov_base + base;
+ iov++;
+ base = 0;
+ } else
+ base -= len;
+
+ if (pglen == 0)
+ goto map_tail;
+ if (base >= pglen) {
+ base -= pglen;
+ goto map_tail;
+ }
+ if (base || xdr->page_base) {
+ pglen -= base;
+ base += xdr->page_base;
+ ppage += base >> PAGE_CACHE_SHIFT;
+ base &= ~PAGE_CACHE_MASK;
+ }
+ do {
+ len = PAGE_CACHE_SIZE;
+ iov->iov_base = kmap(*ppage);
+ if (base) {
+ iov->iov_base += base;
+ len -= base;
+ base = 0;
+ }
+ if (pglen < len)
+ len = pglen;
+ iov->iov_len = len;
+ iov++;
+ ppage++;
+ } while ((pglen -= len) != 0);
+map_tail:
+ if (xdr->tail[0].iov_len) {
+ iov->iov_len = xdr->tail[0].iov_len - base;
+ iov->iov_base = (char *)xdr->tail[0].iov_base + base;
+ iov++;
+ }
+ return (iov - iov_base);
+}
- for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
- if (n < pvec->iov_len) {
- memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
- n = 0;
+void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+{
+ struct page **ppage = xdr->pages;
+ unsigned int pglen = xdr->page_len;
+
+ if (!pglen)
+ return;
+ if (base > xdr->head[0].iov_len)
+ base -= xdr->head[0].iov_len;
+ else
+ base = 0;
+
+ if (base >= pglen)
+ return;
+ if (base || xdr->page_base) {
+ pglen -= base;
+ base += xdr->page_base;
+ ppage += base >> PAGE_CACHE_SHIFT;
+ /* Note: The offset means that the length of the first
+ * page is really (PAGE_CACHE_SIZE - (base & ~PAGE_CACHE_MASK)).
+ * In order to avoid an extra test inside the loop,
+ * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */
+ pglen += base & ~PAGE_CACHE_MASK;
+ }
+ for (;;) {
+ flush_dcache_page(*ppage);
+ kunmap(*ppage);
+ if (pglen <= PAGE_CACHE_SIZE)
+ break;
+ pglen -= PAGE_CACHE_SIZE;
+ ppage++;
+ }
+}
+
+void
+xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
+ skb_reader_t *desc,
+ skb_read_actor_t copy_actor)
+{
+ struct page **ppage = xdr->pages;
+ unsigned int len, pglen = xdr->page_len;
+ int ret;
+
+ len = xdr->head[0].iov_len;
+ if (base < len) {
+ len -= base;
+ ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
+ if (ret != len || !desc->count)
+ return;
+ base = 0;
+ } else
+ base -= len;
+
+ if (pglen == 0)
+ goto copy_tail;
+ if (base >= pglen) {
+ base -= pglen;
+ goto copy_tail;
+ }
+ if (base || xdr->page_base) {
+ pglen -= base;
+ base += xdr->page_base;
+ ppage += base >> PAGE_CACHE_SHIFT;
+ base &= ~PAGE_CACHE_MASK;
+ }
+ do {
+ char *kaddr;
+
+ len = PAGE_CACHE_SIZE;
+ kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
+ if (base) {
+ len -= base;
+ if (pglen < len)
+ len = pglen;
+ ret = copy_actor(desc, kaddr + base, len);
+ base = 0;
} else {
- memset(pvec->iov_base, 0, pvec->iov_len);
- n -= pvec->iov_len;
+ if (pglen < len)
+ len = pglen;
+ ret = copy_actor(desc, kaddr, len);
}
- }
+ kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
+ if (ret != len || !desc->count)
+ return;
+ ppage++;
+ } while ((pglen -= len) != 0);
+copy_tail:
+ len = xdr->tail[0].iov_len;
+ if (len)
+ copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
+}
+
+void
+xdr_shift_buf(struct xdr_buf *xdr, size_t len)
+{
+ struct iovec iov[MAX_IOVEC];
+ unsigned int nr;
+
+ nr = xdr_kmap(iov, xdr, 0);
+ xdr_shift_iovec(iov, nr, len);
+ xdr_kunmap(xdr, 0);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)