#include <asm/uaccess.h>
 #include <asm/atomic.h>
 
+#include "internal.h"
 #include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
                bytes = min(rsize,count);
 
                result = -ENOMEM;
-               data = nfs_readdata_alloc(pgbase + bytes);
+               data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes));
                if (unlikely(!data))
                        break;
 
                bytes = min(wsize,count);
 
                result = -ENOMEM;
-               data = nfs_writedata_alloc(pgbase + bytes);
+               data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes));
                if (unlikely(!data))
                        break;
 
 
        }
        return 0;
 }
+
+/*
+ * Determine the number of pages in an array of length 'len' and
+ * with a base offset of 'base'
+ */
+static inline
+unsigned int nfs_page_array_len(unsigned int base, size_t len)
+{
+       return ((unsigned long)len + (unsigned long)base +
+               PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 
+#include "internal.h"
+
 #define NFS_PARANOIA 1
 
 static struct kmem_cache *nfs_page_cachep;
  */
 void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                     struct inode *inode,
-                    int (*doio)(struct inode *, struct list_head *, size_t, int),
+                    int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
                     unsigned int bsize,
                     int io_flags)
 {
                 * since nfs_flush_multi and nfs_pagein_multi assume you
                 * can have only one struct nfs_page.
                 */
+               if (desc->pg_bsize < PAGE_SIZE)
+                       return 0;
                newlen += desc->pg_count;
-               if (desc->pg_base + newlen > desc->pg_bsize)
+               if (newlen > desc->pg_bsize)
                        return 0;
                prev = nfs_list_entry(desc->pg_list.prev);
                if (!nfs_can_coalesce_requests(prev, req))
        if (!list_empty(&desc->pg_list)) {
                int error = desc->pg_doio(desc->pg_inode,
                                          &desc->pg_list,
+                                         nfs_page_array_len(desc->pg_base,
+                                                            desc->pg_count),
                                          desc->pg_count,
                                          desc->pg_ioflags);
                if (error < 0)
 
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
-static int nfs_pagein_multi(struct inode *, struct list_head *, size_t, int);
-static int nfs_pagein_one(struct inode *, struct list_head *, size_t, int);
+static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
 static const struct rpc_call_ops nfs_read_partial_ops;
 static const struct rpc_call_ops nfs_read_full_ops;
 
 
 #define MIN_POOL_READ  (32)
 
-struct nfs_read_data *nfs_readdata_alloc(size_t len)
+struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
 {
-       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS);
 
        if (p) {
 
        nfs_list_add_request(new, &one_request);
        if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
-               nfs_pagein_multi(inode, &one_request, len, 0);
+               nfs_pagein_multi(inode, &one_request, 1, len, 0);
        else
-               nfs_pagein_one(inode, &one_request, len, 0);
+               nfs_pagein_one(inode, &one_request, 1, len, 0);
        return 0;
 }
 
  * won't see the new data until our attribute cache is updated.  This is more
  * or less conventional NFS client behavior.
  */
-static int nfs_pagein_multi(struct inode *inode, struct list_head *head, size_t count, int flags)
+static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
        do {
                size_t len = min(nbytes,rsize);
 
-               data = nfs_readdata_alloc(len);
+               data = nfs_readdata_alloc(1);
                if (!data)
                        goto out_bad;
                INIT_LIST_HEAD(&data->pages);
        return -ENOMEM;
 }
 
-static int nfs_pagein_one(struct inode *inode, struct list_head *head, size_t count, int flags)
+static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_read_data    *data;
 
-       data = nfs_readdata_alloc(count);
+       data = nfs_readdata_alloc(npages);
        if (!data)
                goto out_bad;
 
 
        call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free);
 }
 
-struct nfs_write_data *nfs_writedata_alloc(size_t len)
+struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
 {
-       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
 
        if (p) {
  * Generate multiple small requests to write out a single
  * contiguous dirty area on one page.
  */
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, size_t count, int how)
+static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
        do {
                size_t len = min(nbytes, wsize);
 
-               data = nfs_writedata_alloc(len);
+               data = nfs_writedata_alloc(1);
                if (!data)
                        goto out_bad;
                list_add(&data->pages, &list);
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int nfs_flush_one(struct inode *inode, struct list_head *head, size_t count, int how)
+static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_write_data   *data;
 
-       data = nfs_writedata_alloc(count);
+       data = nfs_writedata_alloc(npages);
        if (!data)
                goto out_bad;
 
 
 /*
  * Allocate nfs_write_data structures
  */
-extern struct nfs_write_data *nfs_writedata_alloc(size_t len);
+extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs/read.c
 /*
  * Allocate nfs_read_data structures
  */
-extern struct nfs_read_data *nfs_readdata_alloc(size_t len);
+extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs3proc.c
 
        unsigned int            pg_base;
 
        struct inode            *pg_inode;
-       int                     (*pg_doio)(struct inode *, struct list_head *, size_t, int);
+       int                     (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
        int                     pg_ioflags;
        int                     pg_error;
 };
                          unsigned long idx_start, unsigned int npages);
 extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                             struct inode *inode,
-                            int (*doio)(struct inode *, struct list_head *, size_t, int),
+                            int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
                             size_t bsize,
                             int how);
 extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,