aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xdr.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 22:16:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 22:16:57 -0400
commit1fad1e9a747687a7399bf58e87974f9b1bbcae06 (patch)
treefde2dc9a35321e21c99e06d4b79d5fa06fd34679 /net/sunrpc/xdr.c
parentbbeb0af25f493261c15ceee176c99b7fd6fd5479 (diff)
parentf44106e2173f08ccb1c9195d85a6c22388b461c1 (diff)
Merge tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Features include: - More preparatory patches for modularising NFSv2/v3/v4. Split out the various NFSv2/v3/v4-specific code into separate files - More preparation for the NFSv4 migration code - Ensure that OPEN(O_CREATE) observes the pNFS mds threshold parameters - pNFS fast failover when the data servers are down - Various cleanups and debugging patches" * tag 'nfs-for-3.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (67 commits) nfs: fix fl_type tests in NFSv4 code NFS: fix pnfs regression with directio writes NFS: fix pnfs regression with directio reads sunrpc: clnt: Add missing braces nfs: fix stub return type warnings NFS: exit_nfs_v4() shouldn't be an __exit function SUNRPC: Add a missing spin_unlock to gss_mech_list_pseudoflavors NFS: Split out NFS v4 client functions NFS: Split out the NFS v4 filesystem types NFS: Create a single nfs_clone_super() function NFS: Split out NFS v4 server creating code NFS: Initialize the NFS v4 client from init_nfs_v4() NFS: Move the v4 getroot code to nfs4getroot.c NFS: Split out NFS v4 file operations NFS: Initialize v4 sysctls from nfs_init_v4() NFS: Create an init_nfs_v4() function NFS: Split out NFS v4 inode operations NFS: Split out NFS v3 inode operations NFS: Split out NFS v2 inode operations NFS: Clean up nfs4_proc_setclientid() and friends ...
Diffstat (limited to 'net/sunrpc/xdr.c')
-rw-r--r--net/sunrpc/xdr.c127
1 files changed, 69 insertions, 58 deletions
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 0cf165580d8d..0afba1b4b656 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -129,34 +129,6 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len)
129EXPORT_SYMBOL_GPL(xdr_terminate_string); 129EXPORT_SYMBOL_GPL(xdr_terminate_string);
130 130
131void 131void
132xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
133 unsigned int len)
134{
135 struct kvec *tail = xdr->tail;
136 u32 *p;
137
138 xdr->pages = pages;
139 xdr->page_base = base;
140 xdr->page_len = len;
141
142 p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
143 tail->iov_base = p;
144 tail->iov_len = 0;
145
146 if (len & 3) {
147 unsigned int pad = 4 - (len & 3);
148
149 *p = 0;
150 tail->iov_base = (char *)p + (len & 3);
151 tail->iov_len = pad;
152 len += pad;
153 }
154 xdr->buflen += len;
155 xdr->len += len;
156}
157EXPORT_SYMBOL_GPL(xdr_encode_pages);
158
159void
160xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, 132xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
161 struct page **pages, unsigned int base, unsigned int len) 133 struct page **pages, unsigned int base, unsigned int len)
162{ 134{
@@ -457,6 +429,16 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
457EXPORT_SYMBOL_GPL(xdr_shift_buf); 429EXPORT_SYMBOL_GPL(xdr_shift_buf);
458 430
459/** 431/**
432 * xdr_stream_pos - Return the current offset from the start of the xdr_stream
433 * @xdr: pointer to struct xdr_stream
434 */
435unsigned int xdr_stream_pos(const struct xdr_stream *xdr)
436{
437 return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
438}
439EXPORT_SYMBOL_GPL(xdr_stream_pos);
440
441/**
460 * xdr_init_encode - Initialize a struct xdr_stream for sending data. 442 * xdr_init_encode - Initialize a struct xdr_stream for sending data.
461 * @xdr: pointer to xdr_stream struct 443 * @xdr: pointer to xdr_stream struct
462 * @buf: pointer to XDR buffer in which to encode data 444 * @buf: pointer to XDR buffer in which to encode data
@@ -556,13 +538,11 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
556EXPORT_SYMBOL_GPL(xdr_write_pages); 538EXPORT_SYMBOL_GPL(xdr_write_pages);
557 539
558static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov, 540static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
559 __be32 *p, unsigned int len) 541 unsigned int len)
560{ 542{
561 if (len > iov->iov_len) 543 if (len > iov->iov_len)
562 len = iov->iov_len; 544 len = iov->iov_len;
563 if (p == NULL) 545 xdr->p = (__be32*)iov->iov_base;
564 p = (__be32*)iov->iov_base;
565 xdr->p = p;
566 xdr->end = (__be32*)(iov->iov_base + len); 546 xdr->end = (__be32*)(iov->iov_base + len);
567 xdr->iov = iov; 547 xdr->iov = iov;
568 xdr->page_ptr = NULL; 548 xdr->page_ptr = NULL;
@@ -609,7 +589,7 @@ static void xdr_set_next_page(struct xdr_stream *xdr)
609 newbase -= xdr->buf->page_base; 589 newbase -= xdr->buf->page_base;
610 590
611 if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0) 591 if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
612 xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len); 592 xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
613} 593}
614 594
615static bool xdr_set_next_buffer(struct xdr_stream *xdr) 595static bool xdr_set_next_buffer(struct xdr_stream *xdr)
@@ -618,7 +598,7 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr)
618 xdr_set_next_page(xdr); 598 xdr_set_next_page(xdr);
619 else if (xdr->iov == xdr->buf->head) { 599 else if (xdr->iov == xdr->buf->head) {
620 if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0) 600 if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
621 xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len); 601 xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
622 } 602 }
623 return xdr->p != xdr->end; 603 return xdr->p != xdr->end;
624} 604}
@@ -634,10 +614,15 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
634 xdr->buf = buf; 614 xdr->buf = buf;
635 xdr->scratch.iov_base = NULL; 615 xdr->scratch.iov_base = NULL;
636 xdr->scratch.iov_len = 0; 616 xdr->scratch.iov_len = 0;
617 xdr->nwords = XDR_QUADLEN(buf->len);
637 if (buf->head[0].iov_len != 0) 618 if (buf->head[0].iov_len != 0)
638 xdr_set_iov(xdr, buf->head, p, buf->len); 619 xdr_set_iov(xdr, buf->head, buf->len);
639 else if (buf->page_len != 0) 620 else if (buf->page_len != 0)
640 xdr_set_page_base(xdr, 0, buf->len); 621 xdr_set_page_base(xdr, 0, buf->len);
622 if (p != NULL && p > xdr->p && xdr->end >= p) {
623 xdr->nwords -= p - xdr->p;
624 xdr->p = p;
625 }
641} 626}
642EXPORT_SYMBOL_GPL(xdr_init_decode); 627EXPORT_SYMBOL_GPL(xdr_init_decode);
643 628
@@ -662,12 +647,14 @@ EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
662 647
663static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) 648static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
664{ 649{
650 unsigned int nwords = XDR_QUADLEN(nbytes);
665 __be32 *p = xdr->p; 651 __be32 *p = xdr->p;
666 __be32 *q = p + XDR_QUADLEN(nbytes); 652 __be32 *q = p + nwords;
667 653
668 if (unlikely(q > xdr->end || q < p)) 654 if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
669 return NULL; 655 return NULL;
670 xdr->p = q; 656 xdr->p = q;
657 xdr->nwords -= nwords;
671 return p; 658 return p;
672} 659}
673 660
@@ -734,6 +721,31 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
734} 721}
735EXPORT_SYMBOL_GPL(xdr_inline_decode); 722EXPORT_SYMBOL_GPL(xdr_inline_decode);
736 723
724static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
725{
726 struct xdr_buf *buf = xdr->buf;
727 struct kvec *iov;
728 unsigned int nwords = XDR_QUADLEN(len);
729 unsigned int cur = xdr_stream_pos(xdr);
730
731 if (xdr->nwords == 0)
732 return 0;
733 if (nwords > xdr->nwords) {
734 nwords = xdr->nwords;
735 len = nwords << 2;
736 }
737 /* Realign pages to current pointer position */
738 iov = buf->head;
739 if (iov->iov_len > cur)
740 xdr_shrink_bufhead(buf, iov->iov_len - cur);
741
742 /* Truncate page data and move it into the tail */
743 if (buf->page_len > len)
744 xdr_shrink_pagelen(buf, buf->page_len - len);
745 xdr->nwords = XDR_QUADLEN(buf->len - cur);
746 return len;
747}
748
737/** 749/**
738 * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position 750 * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
739 * @xdr: pointer to xdr_stream struct 751 * @xdr: pointer to xdr_stream struct
@@ -742,39 +754,37 @@ EXPORT_SYMBOL_GPL(xdr_inline_decode);
742 * Moves data beyond the current pointer position from the XDR head[] buffer 754 * Moves data beyond the current pointer position from the XDR head[] buffer
743 * into the page list. Any data that lies beyond current position + "len" 755 * into the page list. Any data that lies beyond current position + "len"
744 * bytes is moved into the XDR tail[]. 756 * bytes is moved into the XDR tail[].
757 *
758 * Returns the number of XDR encoded bytes now contained in the pages
745 */ 759 */
746void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) 760unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
747{ 761{
748 struct xdr_buf *buf = xdr->buf; 762 struct xdr_buf *buf = xdr->buf;
749 struct kvec *iov; 763 struct kvec *iov;
750 ssize_t shift; 764 unsigned int nwords;
751 unsigned int end; 765 unsigned int end;
752 int padding; 766 unsigned int padding;
753 767
754 /* Realign pages to current pointer position */ 768 len = xdr_align_pages(xdr, len);
755 iov = buf->head; 769 if (len == 0)
756 shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p; 770 return 0;
757 if (shift > 0) 771 nwords = XDR_QUADLEN(len);
758 xdr_shrink_bufhead(buf, shift); 772 padding = (nwords << 2) - len;
759
760 /* Truncate page data and move it into the tail */
761 if (buf->page_len > len)
762 xdr_shrink_pagelen(buf, buf->page_len - len);
763 padding = (XDR_QUADLEN(len) << 2) - len;
764 xdr->iov = iov = buf->tail; 773 xdr->iov = iov = buf->tail;
765 /* Compute remaining message length. */ 774 /* Compute remaining message length. */
766 end = iov->iov_len; 775 end = ((xdr->nwords - nwords) << 2) + padding;
767 shift = buf->buflen - buf->len; 776 if (end > iov->iov_len)
768 if (shift < end) 777 end = iov->iov_len;
769 end -= shift; 778
770 else if (shift > 0)
771 end = 0;
772 /* 779 /*
773 * Position current pointer at beginning of tail, and 780 * Position current pointer at beginning of tail, and
774 * set remaining message length. 781 * set remaining message length.
775 */ 782 */
776 xdr->p = (__be32 *)((char *)iov->iov_base + padding); 783 xdr->p = (__be32 *)((char *)iov->iov_base + padding);
777 xdr->end = (__be32 *)((char *)iov->iov_base + end); 784 xdr->end = (__be32 *)((char *)iov->iov_base + end);
785 xdr->page_ptr = NULL;
786 xdr->nwords = XDR_QUADLEN(end - padding);
787 return len;
778} 788}
779EXPORT_SYMBOL_GPL(xdr_read_pages); 789EXPORT_SYMBOL_GPL(xdr_read_pages);
780 790
@@ -790,12 +800,13 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
790 */ 800 */
791void xdr_enter_page(struct xdr_stream *xdr, unsigned int len) 801void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
792{ 802{
793 xdr_read_pages(xdr, len); 803 len = xdr_align_pages(xdr, len);
794 /* 804 /*
795 * Position current pointer at beginning of tail, and 805 * Position current pointer at beginning of tail, and
796 * set remaining message length. 806 * set remaining message length.
797 */ 807 */
798 xdr_set_page_base(xdr, 0, len); 808 if (len != 0)
809 xdr_set_page_base(xdr, 0, len);
799} 810}
800EXPORT_SYMBOL_GPL(xdr_enter_page); 811EXPORT_SYMBOL_GPL(xdr_enter_page);
801 812