[PATCH 9/8] nfsd: handle arbitrary page array layouts in nfsd_cache_crc

Jeff Layton
2013-02-04T18:07:45Z

The original code didn't handle the case where the page_base was close
to the end of the page. In practice, page_base is always 0 on receive,
so it's not a problem today, but let's future-proof this in the event
that it ever is.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/nfsd/nfscache.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index cb655f3..e705fea 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -248,6 +248,8 @@ nfsd_reply_cache_shrink(struct shrinker *shrink, struct shrink_control *sc)
static u32
nfsd_cache_crc(struct xdr_buf *buf)
{
+ int idx;
+ unsigned int base;
u32 crc;
const unsigned char *p = buf->head[0].iov_base;
size_t csum_len = min_t(size_t, buf->head[0].iov_len + buf->page_len,
@@ -258,13 +260,18 @@ nfsd_cache_crc(struct xdr_buf *buf)
crc = crc32(crc_seed, p, len);
csum_len -= len;

- /* Nothing left */
- if (!csum_len)
- return crc;
-
- /* checksum the rest from the page_array */
- p = page_address(buf->pages[0]) + buf->page_base;
- return crc32(crc, p, csum_len);
+ /* Continue into page array */
+ idx = buf->page_base / PAGE_SIZE;
+ base = buf->page_base & ~PAGE_MASK;
+ while (csum_len) {
+ p = page_address(buf->pages[idx]) + base;
+ len = min(PAGE_SIZE - base, csum_len);
+ crc = crc32(crc, p, len);
+ csum_len -= len;
+ base = 0;
+ ++idx;
+ }
+ return crc;
}

/*
--
1.7.11.7