From: Chuck Lever <cel@citi.umich.edu>

hi trond, andrew-

this patch has several benefits:

1.  it changes the NFS write proc to use a single argument rather than
    six.

2.  it allows most of the write request parameters to be initialized once
    per request, rather than once for every RPC call.

3.  it exposes the "offset" field to callers (required for direct I/O).

diff -Naurp 22-read_offset/fs/nfs/nfs3proc.c 23-write_offset/fs/nfs/nfs3proc.c


 fs/nfs/nfs3proc.c       |   44 ++++++++---------------------
 fs/nfs/nfs4proc.c       |   48 ++++++++++++--------------------
 fs/nfs/proc.c           |   47 ++++++++++---------------------
 fs/nfs/write.c          |   71 ++++++++++++++++++++++++++----------------------
 include/linux/nfs_xdr.h |    6 +---
 5 files changed, 89 insertions(+), 127 deletions(-)

diff -puN fs/nfs/nfs3proc.c~nfs-O_DIRECT-nfs_write_proc fs/nfs/nfs3proc.c
--- 25/fs/nfs/nfs3proc.c~nfs-O_DIRECT-nfs_write_proc	2003-06-17 16:00:22.000000000 -0700
+++ 25-akpm/fs/nfs/nfs3proc.c	2003-06-17 16:00:22.000000000 -0700
@@ -249,45 +249,27 @@ nfs3_proc_read(struct nfs_read_data *rda
 }
 
 static int
-nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
-		struct nfs_fattr *fattr, int flags,
-		unsigned int base, unsigned int count,
-		struct page *page, struct nfs_writeverf *verf)
-{
-	u64			offset = page_offset(page) + base;
-	struct nfs_writeargs	arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.stable		= NFS_FILE_SYNC,
-		.pgbase		= base,
-		.pages		= &page
-	};
-	struct nfs_writeres	res = {
-		.fattr		= fattr,
-		.verf		= verf,
-	};
+nfs3_proc_write(struct nfs_write_data *wdata)
+{
+	int			rpcflags = wdata->flags;
+	struct inode *		inode = wdata->inode;
+	struct nfs_fattr *	fattr = wdata->res.fattr;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs3_procedures[NFS3PROC_WRITE],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred
+		.rpc_argp	= &wdata->args,
+		.rpc_resp	= &wdata->res,
+		.rpc_cred	= wdata->cred,
 	};
-	int			status, rpcflags = 0;
+	int			status;
 
-	dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
+			(long long) wdata->args.offset);
 	fattr->valid = 0;
-	if (flags & NFS_RW_SWAP)
-		rpcflags |= NFS_RPC_SWAPFLAGS;
-	arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
-
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
-
 	if (status >= 0)
 		nfs3_write_refresh_inode(inode, fattr);
-
-	dprintk("NFS reply read: %d\n", status);
-	return status < 0? status : res.count;
+	dprintk("NFS reply write: %d\n", status);
+	return status < 0? status : wdata->res.count;
 }
 
 /*
diff -puN fs/nfs/nfs4proc.c~nfs-O_DIRECT-nfs_write_proc fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfs-O_DIRECT-nfs_write_proc	2003-06-17 16:00:22.000000000 -0700
+++ 25-akpm/fs/nfs/nfs4proc.c	2003-06-17 16:00:22.000000000 -0700
@@ -1056,51 +1056,41 @@ nfs4_proc_read(struct nfs_read_data *rda
 }
 
 static int
-nfs4_proc_write(struct inode *inode, struct rpc_cred *cred,
-		struct nfs_fattr *fattr, int flags,
-		unsigned int base, unsigned int count,
-		struct page *page, struct nfs_writeverf *verf)
+nfs4_proc_write(struct nfs_write_data *wdata)
 {
+	int rpcflags = wdata->flags;
+	struct inode *inode = wdata->inode;
+	struct nfs_fattr *fattr = wdata->res.fattr;
+	nfs4_stateid *stateid = &wdata->args.stateid;
 	struct nfs_server *server = NFS_SERVER(inode);
-	struct nfs4_shareowner	*sp;
-	uint64_t offset = page_offset(page) + base;
-	struct nfs_writeargs arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.stable		= (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE,
-		.pgbase		= base,
-		.pages		= &page,
-	};
-	struct nfs_writeres res = {
-		.fattr		= fattr,
-		.count		= count,
-		.verf		= verf,
-	};
+	struct nfs4_shareowner *sp;
 	struct rpc_message msg = {
 		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_WRITE],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred,
+		.rpc_argp	= &wdata->args,
+		.rpc_resp	= &wdata->res,
+		.rpc_cred	= wdata->cred,
 	};
-	int			rpcflags = (flags & NFS_RW_SWAP) ? NFS_RPC_SWAPFLAGS : 0;
+	int status;
 
-	dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
+			(long long) wdata->args.offset);
 
 	/*
-	* Try first to use O_WRONLY, then O_RDWR stateid.
-	*/
+	 * Try first to use O_WRONLY, then O_RDWR stateid.
+	 */
 	sp = nfs4_get_inode_share(inode, O_WRONLY);
 	if (!sp)
 		sp = nfs4_get_inode_share(inode, O_RDWR);
 
 	if (sp)
-		memcpy(arg.stateid,sp->so_stateid, sizeof(nfs4_stateid));
+		memcpy(stateid, sp->so_stateid, sizeof(nfs4_stateid));
 	else
-		memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid));
+		memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
 
 	fattr->valid = 0;
-	return rpc_call_sync(server->client, &msg, rpcflags);
+	status = rpc_call_sync(server->client, &msg, rpcflags);
+	dprintk("NFS reply write: %d\n", status);
+	return status;
 }
 
 /*
diff -puN fs/nfs/proc.c~nfs-O_DIRECT-nfs_write_proc fs/nfs/proc.c
--- 25/fs/nfs/proc.c~nfs-O_DIRECT-nfs_write_proc	2003-06-17 16:00:22.000000000 -0700
+++ 25-akpm/fs/nfs/proc.c	2003-06-17 16:00:22.000000000 -0700
@@ -174,45 +174,30 @@ nfs_proc_read(struct nfs_read_data *rdat
 }
 
 static int
-nfs_proc_write(struct inode *inode, struct rpc_cred *cred,
-	       struct nfs_fattr *fattr, int how,
-	       unsigned int base, unsigned int count,
-	       struct page *page, struct nfs_writeverf *verf)
-{
-	u64			offset = page_offset(page) + base;
-	struct nfs_writeargs	arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.stable		= NFS_FILE_SYNC,
-		.pgbase		= base,
-		.pages		= &page
-	};
-	struct nfs_writeres     res = {
-		.fattr		= fattr,
-		.verf		= verf,
-		.count		= count
-	};
+nfs_proc_write(struct nfs_write_data *wdata)
+{
+	int			flags = wdata->flags;
+	struct inode *		inode = wdata->inode;
+	struct nfs_fattr *	fattr = wdata->res.fattr;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs_procedures[NFSPROC_WRITE],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred
+		.rpc_argp	= &wdata->args,
+		.rpc_resp	= &wdata->res,
+		.rpc_cred	= wdata->cred
 	};
-	int			status, flags = 0;
+	int			status;
 
-	dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
+			(long long) wdata->args.offset);
 	fattr->valid = 0;
-	if (how & NFS_RW_SWAP)
-		flags |= NFS_RPC_SWAPFLAGS;
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
-
-	if (status >= 0)
+	if (status >= 0) {
 		nfs_write_refresh_inode(inode, fattr);
-
+		wdata->res.count = wdata->args.count;
+		wdata->verf.committed = NFS_FILE_SYNC;
+	}
 	dprintk("NFS reply write: %d\n", status);
-	verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
-	return status < 0? status : count;
+	return status < 0? status : wdata->res.count;
 }
 
 static int
diff -puN fs/nfs/write.c~nfs-O_DIRECT-nfs_write_proc fs/nfs/write.c
--- 25/fs/nfs/write.c~nfs-O_DIRECT-nfs_write_proc	2003-06-17 16:00:22.000000000 -0700
+++ 25-akpm/fs/nfs/write.c	2003-06-17 16:00:22.000000000 -0700
@@ -132,66 +132,73 @@ static int
 nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int count)
 {
-	struct rpc_cred	*cred = NULL;
-	loff_t		base;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
-	int		result, refresh = 0, written = 0, flags;
-	u8		*buffer;
-	struct nfs_fattr fattr;
-	struct nfs_writeverf verf;
-
+	int		result, written = 0;
+	int		swapfile = IS_SWAPFILE(inode);
+	struct nfs_write_data	wdata = {
+		.flags		= swapfile ? NFS_RPC_SWAPFLAGS : 0,
+		.cred		= NULL,
+		.inode		= inode,
+		.args		= {
+			.fh		= NFS_FH(inode),
+			.pages		= &page,
+			.stable		= NFS_FILE_SYNC,
+			.pgbase		= offset,
+			.count		= wsize,
+		},
+		.res		= {
+			.fattr		= &wdata.fattr,
+			.verf		= &wdata.verf,
+		},
+	};
 
 	if (file)
-		cred = get_rpccred(nfs_file_cred(file));
-	if (!cred)
-		cred = get_rpccred(NFS_I(inode)->mm_cred);
+		wdata.cred = get_rpccred(nfs_file_cred(file));
+	if (!wdata.cred)
+		wdata.cred = get_rpccred(NFS_I(inode)->mm_cred);
 
 	dprintk("NFS:      nfs_writepage_sync(%s/%Ld %d@%Ld)\n",
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
-	base = page_offset(page) + offset;
-
-	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
-
 	do {
-		if (count < wsize && !IS_SWAPFILE(inode))
-			wsize = count;
+		if (count < wsize && !swapfile)
+			wdata.args.count = count;
+		wdata.args.offset = page_offset(page) + wdata.args.pgbase;
 
-		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
-						 offset, wsize, page, &verf);
+		result = NFS_PROTO(inode)->write(&wdata);
 
 		if (result < 0) {
 			/* Must mark the page invalid after I/O error */
 			ClearPageUptodate(page);
 			goto io_error;
 		}
-		if (result != wsize)
-			printk("NFS: short write, wsize=%u, result=%d\n",
-			wsize, result);
-		refresh = 1;
-		buffer  += wsize;
-		base    += wsize;
-	        offset  += wsize;
-		written += wsize;
-		count   -= wsize;
+		if (result < wdata.args.count)
+			printk(KERN_WARNING "NFS: short write, count=%u, result=%d\n",
+					wdata.args.count, result);
+
+		wdata.args.offset += result;
+	        wdata.args.pgbase += result;
+		written += result;
+		count -= result;
+
 		/*
 		 * If we've extended the file, update the inode
 		 * now so we don't invalidate the cache.
 		 */
-		if (base > inode->i_size)
-			inode->i_size = base;
+		if (wdata.args.offset > inode->i_size)
+			inode->i_size = wdata.args.offset;
 	} while (count);
 
 	if (PageError(page))
 		ClearPageError(page);
 
 io_error:
-	if (cred)
-		put_rpccred(cred);
+	if (wdata.cred)
+		put_rpccred(wdata.cred);
 
-	return written? written : result;
+	return written ? written : result;
 }
 
 static int
diff -puN include/linux/nfs_xdr.h~nfs-O_DIRECT-nfs_write_proc include/linux/nfs_xdr.h
--- 25/include/linux/nfs_xdr.h~nfs-O_DIRECT-nfs_write_proc	2003-06-17 16:00:22.000000000 -0700
+++ 25-akpm/include/linux/nfs_xdr.h	2003-06-17 16:00:22.000000000 -0700
@@ -606,6 +606,7 @@ struct nfs_read_data {
 };
 
 struct nfs_write_data {
+	int			flags;
 	struct rpc_task		task;
 	struct inode		*inode;
 	struct rpc_cred		*cred;
@@ -636,10 +637,7 @@ struct nfs_rpc_ops {
 	int	(*access)  (struct inode *, struct rpc_cred *, int);
 	int	(*readlink)(struct inode *, struct page *);
 	int	(*read)    (struct nfs_read_data *);
-	int	(*write)   (struct inode *, struct rpc_cred *,
-			    struct nfs_fattr *,
-			    int, unsigned int, unsigned int,
-			    struct page *, struct nfs_writeverf *verfp);
+	int	(*write)   (struct nfs_write_data *);
 	int	(*commit)  (struct inode *, struct nfs_fattr *,
 			    unsigned long, unsigned int);
 	int	(*create)  (struct inode *, struct qstr *, struct iattr *,

_