read.c | 19 +++++++++++++++---- write.c | 45 +++++++++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 18 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.4-25-rpc_fixes2/fs/nfs/read.c linux-2.6.4-26-short_rw/fs/nfs/read.c --- linux-2.6.4-25-rpc_fixes2/fs/nfs/read.c 2004-03-06 02:25:51.000000000 -0500 +++ linux-2.6.4-26-short_rw/fs/nfs/read.c 2004-03-06 02:46:22.000000000 -0500 @@ -421,8 +421,6 @@ static void nfs_readpage_result_partial( memclear_highpage_flush(page, data->args.pgbase + result, request - result); - if (!data->res.eof) - SetPageError(page); } } else SetPageError(page); @@ -453,8 +451,6 @@ static void nfs_readpage_result_full(str memclear_highpage_flush(page, req->wb_pgbase + count, req->wb_bytes - count); - if (!data->res.eof) - SetPageError(page); count = 0; } else count -= PAGE_CACHE_SIZE; @@ -472,11 +468,26 @@ static void nfs_readpage_result_full(str void nfs_readpage_result(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; + struct nfs_readargs *argp = &data->args; + struct nfs_readres *resp = &data->res; int status = task->tk_status; dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", task->tk_pid, status); + /* Is this a short read? */ + if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { + /* Has the server at least made some progress? */ + if (resp->count != 0) { + /* Yes, so retry the read at the end of the data */ + argp->offset += resp->count; + argp->pgbase += resp->count; + argp->count -= resp->count; + rpc_restart_call(task); + return; + } + task->tk_status = -EIO; + } NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; data->complete(data, status); } diff -u --recursive --new-file --show-c-function linux-2.6.4-25-rpc_fixes2/fs/nfs/write.c linux-2.6.4-26-short_rw/fs/nfs/write.c --- linux-2.6.4-25-rpc_fixes2/fs/nfs/write.c 2004-03-06 02:25:51.000000000 -0500 +++ linux-2.6.4-26-short_rw/fs/nfs/write.c 2004-03-06 02:48:28.000000000 -0500 @@ -1140,20 +1140,8 @@ void nfs_writeback_done(struct rpc_task dprintk("NFS: %4d nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); - /* We can't handle that yet but we check for it nevertheless */ - if (resp->count < argp->count && task->tk_status >= 0) { - static unsigned long complain; - if (time_before(complain, jiffies)) { - printk(KERN_WARNING - "NFS: Server wrote less than requested.\n"); - complain = jiffies + 300 * HZ; - } - /* Can't do anything about it right now except throw - * an error. */ - task->tk_status = -EIO; - } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) - if (data->verf.committed < argp->stable && task->tk_status >= 0) { + if (resp->verf->committed < argp->stable && task->tk_status >= 0) { /* We tried a write call, but the server did not * commit data to stable storage even though we * requested it. @@ -1168,11 +1156,40 @@ void nfs_writeback_done(struct rpc_task dprintk("NFS: faulty NFS server %s:" " (committed = %d) != (stable = %d)\n", NFS_SERVER(data->inode)->hostname, - data->verf.committed, argp->stable); + resp->verf->committed, argp->stable); complain = jiffies + 300 * HZ; } } #endif + /* Is this a short write? */ + if (task->tk_status >= 0 && resp->count < argp->count) { + static unsigned long complain; + + /* Has the server at least made some progress? */ + if (resp->count != 0) { + /* Was this an NFSv2 write or an NFSv3 stable write? */ + if (resp->verf->committed != NFS_UNSTABLE) { + /* Resend from where the server left off */ + argp->offset += resp->count; + argp->pgbase += resp->count; + argp->count -= resp->count; + } else { + /* Resend as a stable write in order to avoid + * headaches in the case of a server crash. + */ + argp->stable = NFS_FILE_SYNC; + } + rpc_restart_call(task); + return; + } + if (time_before(complain, jiffies)) { + printk(KERN_WARNING + "NFS: Server wrote less than requested.\n"); + complain = jiffies + 300 * HZ; + } + /* Can't do anything about it except throw an error. */ + task->tk_status = -EIO; + } /* * Process the nfs_page list