diff options
| -rw-r--r-- | include/linux/sunrpc/xdr.h | 2 | ||||
| -rw-r--r-- | net/sunrpc/xdr.c | 22 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 35 |
3 files changed, 42 insertions, 17 deletions
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 0f5b7a5a7432..5d1eed2b58a1 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
| @@ -160,7 +160,7 @@ typedef struct { | |||
| 160 | 160 | ||
| 161 | typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); | 161 | typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); |
| 162 | 162 | ||
| 163 | extern int xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, | 163 | extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, |
| 164 | skb_reader_t *, skb_read_actor_t); | 164 | skb_reader_t *, skb_read_actor_t); |
| 165 | 165 | ||
| 166 | struct socket; | 166 | struct socket; |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 65b268d39782..b3ac3f72bf9c 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
| @@ -176,21 +176,23 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | |||
| 176 | xdr->buflen += len; | 176 | xdr->buflen += len; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | int | 179 | ssize_t |
| 180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | 180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, |
| 181 | skb_reader_t *desc, | 181 | skb_reader_t *desc, |
| 182 | skb_read_actor_t copy_actor) | 182 | skb_read_actor_t copy_actor) |
| 183 | { | 183 | { |
| 184 | struct page **ppage = xdr->pages; | 184 | struct page **ppage = xdr->pages; |
| 185 | unsigned int len, pglen = xdr->page_len; | 185 | unsigned int len, pglen = xdr->page_len; |
| 186 | ssize_t copied = 0; | ||
| 186 | int ret; | 187 | int ret; |
| 187 | 188 | ||
| 188 | len = xdr->head[0].iov_len; | 189 | len = xdr->head[0].iov_len; |
| 189 | if (base < len) { | 190 | if (base < len) { |
| 190 | len -= base; | 191 | len -= base; |
| 191 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); | 192 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); |
| 193 | copied += ret; | ||
| 192 | if (ret != len || !desc->count) | 194 | if (ret != len || !desc->count) |
| 193 | return 0; | 195 | goto out; |
| 194 | base = 0; | 196 | base = 0; |
| 195 | } else | 197 | } else |
| 196 | base -= len; | 198 | base -= len; |
| @@ -214,8 +216,11 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
| 214 | * are small by default but can get huge. */ | 216 | * are small by default but can get huge. */ |
| 215 | if (unlikely(*ppage == NULL)) { | 217 | if (unlikely(*ppage == NULL)) { |
| 216 | *ppage = alloc_page(GFP_ATOMIC); | 218 | *ppage = alloc_page(GFP_ATOMIC); |
| 217 | if (unlikely(*ppage == NULL)) | 219 | if (unlikely(*ppage == NULL)) { |
| 218 | return -ENOMEM; | 220 | if (copied == 0) |
| 221 | copied = -ENOMEM; | ||
| 222 | goto out; | ||
| 223 | } | ||
| 219 | } | 224 | } |
| 220 | 225 | ||
| 221 | len = PAGE_CACHE_SIZE; | 226 | len = PAGE_CACHE_SIZE; |
| @@ -233,16 +238,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
| 233 | } | 238 | } |
| 234 | flush_dcache_page(*ppage); | 239 | flush_dcache_page(*ppage); |
| 235 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); | 240 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); |
| 241 | copied += ret; | ||
| 236 | if (ret != len || !desc->count) | 242 | if (ret != len || !desc->count) |
| 237 | return 0; | 243 | goto out; |
| 238 | ppage++; | 244 | ppage++; |
| 239 | } while ((pglen -= len) != 0); | 245 | } while ((pglen -= len) != 0); |
| 240 | copy_tail: | 246 | copy_tail: |
| 241 | len = xdr->tail[0].iov_len; | 247 | len = xdr->tail[0].iov_len; |
| 242 | if (base < len) | 248 | if (base < len) |
| 243 | copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); | 249 | copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); |
| 244 | 250 | out: | |
| 245 | return 0; | 251 | return copied; |
| 246 | } | 252 | } |
| 247 | 253 | ||
| 248 | 254 | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a180ed4952d6..ef941e7de8bf 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -823,10 +823,15 @@ tcp_copy_data(skb_reader_t *desc, void *p, size_t len) | |||
| 823 | { | 823 | { |
| 824 | if (len > desc->count) | 824 | if (len > desc->count) |
| 825 | len = desc->count; | 825 | len = desc->count; |
| 826 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) | 826 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) { |
| 827 | dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", | ||
| 828 | len, desc->count); | ||
| 827 | return 0; | 829 | return 0; |
| 830 | } | ||
| 828 | desc->offset += len; | 831 | desc->offset += len; |
| 829 | desc->count -= len; | 832 | desc->count -= len; |
| 833 | dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", | ||
| 834 | len, desc->count); | ||
| 830 | return len; | 835 | return len; |
| 831 | } | 836 | } |
| 832 | 837 | ||
| @@ -865,6 +870,8 @@ tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 865 | static void | 870 | static void |
| 866 | tcp_check_recm(struct rpc_xprt *xprt) | 871 | tcp_check_recm(struct rpc_xprt *xprt) |
| 867 | { | 872 | { |
| 873 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", | ||
| 874 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); | ||
| 868 | if (xprt->tcp_offset == xprt->tcp_reclen) { | 875 | if (xprt->tcp_offset == xprt->tcp_reclen) { |
| 869 | xprt->tcp_flags |= XPRT_COPY_RECM; | 876 | xprt->tcp_flags |= XPRT_COPY_RECM; |
| 870 | xprt->tcp_offset = 0; | 877 | xprt->tcp_offset = 0; |
| @@ -909,7 +916,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 909 | struct rpc_rqst *req; | 916 | struct rpc_rqst *req; |
| 910 | struct xdr_buf *rcvbuf; | 917 | struct xdr_buf *rcvbuf; |
| 911 | size_t len; | 918 | size_t len; |
| 912 | int r; | 919 | ssize_t r; |
| 913 | 920 | ||
| 914 | /* Find and lock the request corresponding to this xid */ | 921 | /* Find and lock the request corresponding to this xid */ |
| 915 | spin_lock(&xprt->sock_lock); | 922 | spin_lock(&xprt->sock_lock); |
| @@ -932,15 +939,17 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 932 | my_desc.count = len; | 939 | my_desc.count = len; |
| 933 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 940 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
| 934 | &my_desc, tcp_copy_data); | 941 | &my_desc, tcp_copy_data); |
| 935 | desc->count -= len; | 942 | desc->count -= r; |
| 936 | desc->offset += len; | 943 | desc->offset += r; |
| 937 | } else | 944 | } else |
| 938 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 945 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
| 939 | desc, tcp_copy_data); | 946 | desc, tcp_copy_data); |
| 940 | xprt->tcp_copied += len; | ||
| 941 | xprt->tcp_offset += len; | ||
| 942 | 947 | ||
| 943 | if (r < 0) { | 948 | if (r > 0) { |
| 949 | xprt->tcp_copied += r; | ||
| 950 | xprt->tcp_offset += r; | ||
| 951 | } | ||
| 952 | if (r != len) { | ||
| 944 | /* Error when copying to the receive buffer, | 953 | /* Error when copying to the receive buffer, |
| 945 | * usually because we weren't able to allocate | 954 | * usually because we weren't able to allocate |
| 946 | * additional buffer pages. All we can do now | 955 | * additional buffer pages. All we can do now |
| @@ -951,9 +960,18 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 951 | * be discarded. | 960 | * be discarded. |
| 952 | */ | 961 | */ |
| 953 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 962 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
| 963 | dprintk("RPC: XID %08x truncated request\n", | ||
| 964 | ntohl(xprt->tcp_xid)); | ||
| 965 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
| 966 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
| 954 | goto out; | 967 | goto out; |
| 955 | } | 968 | } |
| 956 | 969 | ||
| 970 | dprintk("RPC: XID %08x read %u bytes\n", | ||
| 971 | ntohl(xprt->tcp_xid), r); | ||
| 972 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
| 973 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
| 974 | |||
| 957 | if (xprt->tcp_copied == req->rq_private_buf.buflen) | 975 | if (xprt->tcp_copied == req->rq_private_buf.buflen) |
| 958 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 976 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
| 959 | else if (xprt->tcp_offset == xprt->tcp_reclen) { | 977 | else if (xprt->tcp_offset == xprt->tcp_reclen) { |
| @@ -961,12 +979,12 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 961 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 979 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
| 962 | } | 980 | } |
| 963 | 981 | ||
| 982 | out: | ||
| 964 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { | 983 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { |
| 965 | dprintk("RPC: %4d received reply complete\n", | 984 | dprintk("RPC: %4d received reply complete\n", |
| 966 | req->rq_task->tk_pid); | 985 | req->rq_task->tk_pid); |
| 967 | xprt_complete_rqst(xprt, req, xprt->tcp_copied); | 986 | xprt_complete_rqst(xprt, req, xprt->tcp_copied); |
| 968 | } | 987 | } |
| 969 | out: | ||
| 970 | spin_unlock(&xprt->sock_lock); | 988 | spin_unlock(&xprt->sock_lock); |
| 971 | tcp_check_recm(xprt); | 989 | tcp_check_recm(xprt); |
| 972 | } | 990 | } |
| @@ -985,6 +1003,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
| 985 | desc->count -= len; | 1003 | desc->count -= len; |
| 986 | desc->offset += len; | 1004 | desc->offset += len; |
| 987 | xprt->tcp_offset += len; | 1005 | xprt->tcp_offset += len; |
| 1006 | dprintk("RPC: discarded %u bytes\n", len); | ||
| 988 | tcp_check_recm(xprt); | 1007 | tcp_check_recm(xprt); |
| 989 | } | 1008 | } |
| 990 | 1009 | ||
