Commit 0bce91be authored by Chuck Lever's avatar Chuck Lever Committed by Linus Torvalds

[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.
parent 2fbace60
...@@ -233,7 +233,6 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) ...@@ -233,7 +233,6 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
static int static int
nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) 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; struct iovec *iov = req->rq_rvec;
int status, count, recvd, hdrlen; int status, count, recvd, hdrlen;
...@@ -243,11 +242,6 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) ...@@ -243,11 +242,6 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
count = ntohl(*p++); count = ntohl(*p++);
res->eof = 0; 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; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READ reply header overflowed:" 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) ...@@ -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: " printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd); "count %d > recvd %d\n", count, recvd);
count = recvd; count = recvd;
res->eof = 0;
} }
dprintk("RPC: readres OK count %d\n", count); dprintk("RPC: readres OK count %d\n", count);
......
...@@ -256,11 +256,12 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof) ...@@ -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 nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
struct inode *inode = data->inode; struct inode *inode = data->inode;
struct nfs_fattr *fattr = &data->fattr;
dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
task->tk_pid, task->tk_status); task->tk_pid, task->tk_status);
nfs_refresh_inode(inode, &data->fattr); nfs_refresh_inode(inode, fattr);
while (!list_empty(&data->pages)) { while (!list_empty(&data->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next); struct nfs_page *req = nfs_list_entry(data->pages.next);
struct page *page = req->wb_page; struct page *page = req->wb_page;
...@@ -269,13 +270,20 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof) ...@@ -269,13 +270,20 @@ nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
if (count < PAGE_CACHE_SIZE) { if (count < PAGE_CACHE_SIZE) {
char *p = kmap(page); 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); kunmap(page);
count = 0;
if (eof) if (eof ||
((fattr->valid & NFS_ATTR_FATTR) &&
((req_offset(req) + req->wb_offset + count) >= fattr->size)))
SetPageUptodate(page); SetPageUptodate(page);
else else
SetPageError(page); if (count < req->wb_bytes)
SetPageError(page);
count = 0;
} else { } else {
count -= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE;
SetPageUptodate(page); SetPageUptodate(page);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment