diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 13:16:24 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 16:07:19 -0400 |
commit | 7e06b53d796a3740307b54aa2799077f8a0c84e7 (patch) | |
tree | 95c00126400914bfd68f84ed7669272e581e9386 /net/sunrpc/xdr.c | |
parent | e053d1ab62c8ef0eff3dd4c95448cad3c6d2fbf4 (diff) |
[PATCH] RPC: fix accounting bug in the case of a truncated RPC message
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/xdr.c')
-rw-r--r-- | net/sunrpc/xdr.c | 22 |
1 files changed, 14 insertions, 8 deletions
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 | ||