summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChuck Lever <cel@citi.umich.edu>2002-11-07 00:43:38 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-11-07 00:43:38 -0800
commit0bce91be4b67ba6aab55d889b7d4c23ba28ada53 (patch)
tree9ac5047dd16d4191eb5ccbd20f420831e266c0e5
parent2fbace6096db970a2e5c1e5a25570135394f494c (diff)
[PATCH] bug in NFSv2 end-of-file read handling
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.
-rw-r--r--fs/nfs/nfs2xdr.c7
-rw-r--r--fs/nfs/read.c18
2 files changed, 13 insertions, 12 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 8e652afdfea4..4673cca4d3b3 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -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);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 01d2447b737c..647ea4898a0d 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -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);