]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] bug in NFSv2 end-of-file read handling
authorChuck Lever <cel@citi.umich.edu>
Thu, 7 Nov 2002 08:43:38 +0000 (00:43 -0800)
committerLinus Torvalds <torvalds@penguin.transmeta.com>
Thu, 7 Nov 2002 08:43:38 +0000 (00:43 -0800)
NFSv2 doesn't pass connectathon 2002, at least on some Linux kernels.
Trond deemed the following modification necessary in all kernels to
address the problem.

fs/nfs/nfs2xdr.c
fs/nfs/read.c

index 8e652afdfea481705a81b1b78f75fd247e89330c..4673cca4d3b322517b80028106d19d458e030b65 100644 (file)
@@ -233,7 +233,6 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 static int
 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-       struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
        struct iovec *iov = req->rq_rvec;
        int     status, count, recvd, hdrlen;
 
@@ -243,11 +242,6 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 
        count = ntohl(*p++);
        res->eof = 0;
-       if (rcvbuf->page_len) {
-               u32 end = page_offset(rcvbuf->pages[0]) + rcvbuf->page_base + count;
-               if (end >= res->fattr->size)
-                       res->eof = 1;
-       }
        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
        if (iov->iov_len < hdrlen) {
                printk(KERN_WARNING "NFS: READ reply header overflowed:"
@@ -263,7 +257,6 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
                printk(KERN_WARNING "NFS: server cheating in read reply: "
                        "count %d > recvd %d\n", count, recvd);
                count = recvd;
-               res->eof = 0;
        }
 
        dprintk("RPC:      readres OK count %d\n", count);
index 01d2447b737c85ca207f78a1457bb082f99f46bb..647ea4898a0d1d6fd8b7d7fd552cc226a99bfeee 100644 (file)
@@ -256,11 +256,12 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
 {
        struct nfs_read_data    *data = (struct nfs_read_data *) task->tk_calldata;
        struct inode            *inode = data->inode;
+       struct nfs_fattr        *fattr = &data->fattr;
 
        dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
                task->tk_pid, task->tk_status);
 
-       nfs_refresh_inode(inode, &data->fattr);
+       nfs_refresh_inode(inode, fattr);
        while (!list_empty(&data->pages)) {
                struct nfs_page *req = nfs_list_entry(data->pages.next);
                struct page *page = req->wb_page;
@@ -269,13 +270,20 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
                if (task->tk_status >= 0) {
                        if (count < PAGE_CACHE_SIZE) {
                                char *p = kmap(page);
-                               memset(p + count, 0, PAGE_CACHE_SIZE - count);
+
+                               if (count < req->wb_bytes)
+                                       memset(p + req->wb_offset + count, 0,
+                                                       req->wb_bytes - count);
                                kunmap(page);
-                               count = 0;
-                               if (eof)
+
+                               if (eof ||
+                                   ((fattr->valid & NFS_ATTR_FATTR) &&
+                                    ((req_offset(req) + req->wb_offset + count) >= fattr->size)))
                                        SetPageUptodate(page);
                                else
-                                       SetPageError(page);
+                                       if (count < req->wb_bytes)
+                                               SetPageError(page);
+                               count = 0;
                        } else {
                                count -= PAGE_CACHE_SIZE;
                                SetPageUptodate(page);