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

hi trond, andrew-

this patch has several benefits:

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

2.  it allows most of the read 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 21-odirect_cruft/fs/nfs/nfs3proc.c 22-read_offset/fs/nfs/nfs3proc.c


 fs/nfs/nfs3proc.c       |   30 +++++++++---------------------
 fs/nfs/nfs4proc.c       |   40 +++++++++++++++-------------------------
 fs/nfs/proc.c           |   30 +++++++++---------------------
 fs/nfs/read.c           |   39 +++++++++++++++++++++++++--------------
 include/linux/nfs_xdr.h |    6 ++----
 5 files changed, 60 insertions(+), 85 deletions(-)

diff -puN fs/nfs/nfs3proc.c~nfs-O_DIRECT-nfs_read_data fs/nfs/nfs3proc.c
--- 25/fs/nfs/nfs3proc.c~nfs-O_DIRECT-nfs_read_data	2003-06-17 16:00:20.000000000 -0700
+++ 25-akpm/fs/nfs/nfs3proc.c	2003-06-17 16:00:20.000000000 -0700
@@ -225,38 +225,26 @@ nfs3_proc_readlink(struct inode *inode, 
 }
 
 static int
-nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
-	       struct nfs_fattr *fattr, int flags,
-	       unsigned int base, unsigned int count, struct page *page,
-	       int *eofp)
+nfs3_proc_read(struct nfs_read_data *rdata)
 {
-	u64			offset = page_offset(page) + base;
-	struct nfs_readargs	arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.pgbase		= base,
-		.pages		= &page
-	};
-	struct nfs_readres	res = {
-		.fattr		= fattr,
-		.count		= count,
-	};
+	int			flags = rdata->flags;
+	struct inode *		inode = rdata->inode;
+	struct nfs_fattr *	fattr = rdata->res.fattr;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs3_procedures[NFS3PROC_READ],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred
+		.rpc_argp	= &rdata->args,
+		.rpc_resp	= &rdata->res,
+		.rpc_cred	= rdata->cred,
 	};
 	int			status;
 
-	dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
+			(long long) rdata->args.offset);
 	fattr->valid = 0;
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 	if (status >= 0)
 		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply read: %d\n", status);
-	*eofp = res.eof;
 	return status;
 }
 
diff -puN fs/nfs/nfs4proc.c~nfs-O_DIRECT-nfs_read_data fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfs-O_DIRECT-nfs_read_data	2003-06-17 16:00:20.000000000 -0700
+++ 25-akpm/fs/nfs/nfs4proc.c	2003-06-17 16:00:20.000000000 -0700
@@ -1012,45 +1012,36 @@ nfs4_proc_readlink(struct inode *inode, 
 }
 
 static int
-nfs4_proc_read(struct inode *inode, struct rpc_cred *cred,
-	       struct nfs_fattr *fattr, int flags,
-	       unsigned int base, unsigned int count,
-	       struct page *page, int *eofp)
+nfs4_proc_read(struct nfs_read_data *rdata)
 {
+	int flags = rdata->flags;
+	struct inode *inode = rdata->inode;
+	struct nfs_fattr *fattr = rdata->res.fattr;
+	nfs4_stateid *stateid = &rdata->args.stateid;
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs4_shareowner	*sp;
-	uint64_t offset = page_offset(page) + base;
-	struct nfs_readargs arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.pgbase		= base,
-		.pages		= &page,
-	};
-	struct nfs_readres res = {
-		.fattr		= fattr,
-		.count		= count,
-	};
 	struct rpc_message msg = {
 		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_READ],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred,
+		.rpc_argp	= &rdata->args,
+		.rpc_resp	= &rdata->res,
+		.rpc_cred	= rdata->cred,
 	};
 	unsigned long timestamp = jiffies;
 	int status;
 
-	dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
+			(long long) rdata->args.offset);
+
 	/*
-	* Try first to use O_RDONLY, then O_RDWR stateid.
-	*/
+	 * Try first to use O_RDONLY, then O_RDWR stateid.
+	 */
 	sp = nfs4_get_inode_share(inode, O_RDONLY);
 	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;
 	status = rpc_call_sync(server->client, &msg, flags);
@@ -1061,7 +1052,6 @@ nfs4_proc_read(struct inode *inode, stru
 			nfs_zap_caches(inode);
 	}
 	dprintk("NFS reply read: %d\n", status);
-	*eofp = res.eof;
 	return status;
 }
 
diff -puN fs/nfs/proc.c~nfs-O_DIRECT-nfs_read_data fs/nfs/proc.c
--- 25/fs/nfs/proc.c~nfs-O_DIRECT-nfs_read_data	2003-06-17 16:00:20.000000000 -0700
+++ 25-akpm/fs/nfs/proc.c	2003-06-17 16:00:20.000000000 -0700
@@ -149,39 +149,27 @@ nfs_proc_readlink(struct inode *inode, s
 }
 
 static int
-nfs_proc_read(struct inode *inode, struct rpc_cred *cred,
-	      struct nfs_fattr *fattr, int flags,
-	      unsigned int base, unsigned int count, struct page *page,
-	      int *eofp)
+nfs_proc_read(struct nfs_read_data *rdata)
 {
-	u64			offset = page_offset(page) + base;
-	struct nfs_readargs	arg = {
-		.fh		= NFS_FH(inode),
-		.offset		= offset,
-		.count		= count,
-		.pgbase		= base,
-		.pages		= &page
-	};
-	struct nfs_readres	res = {
-		.fattr		= fattr,
-		.count		= count
-	};
+	int			flags = rdata->flags;
+	struct inode *		inode = rdata->inode;
+	struct nfs_fattr *	fattr = rdata->res.fattr;
 	struct rpc_message	msg = {
 		.rpc_proc	= &nfs_procedures[NFSPROC_READ],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred
+		.rpc_argp	= &rdata->args,
+		.rpc_resp	= &rdata->res,
+		.rpc_cred	= rdata->cred,
 	};
 	int			status;
 
-	dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
+	dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
+			(long long) rdata->args.offset);
 	fattr->valid = 0;
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
 	if (status >= 0)
 		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply read: %d\n", status);
-	*eofp = res.eof;
 	return status;
 }
 
diff -puN fs/nfs/read.c~nfs-O_DIRECT-nfs_read_data fs/nfs/read.c
--- 25/fs/nfs/read.c~nfs-O_DIRECT-nfs_read_data	2003-06-17 16:00:20.000000000 -0700
+++ 25-akpm/fs/nfs/read.c	2003-06-17 16:00:20.000000000 -0700
@@ -69,19 +69,28 @@ void nfs_readdata_release(struct rpc_tas
 static int
 nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
 {
-	struct rpc_cred	*cred = NULL;
-	struct nfs_fattr fattr;
-	unsigned int	offset = 0;
 	unsigned int	rsize = NFS_SERVER(inode)->rsize;
 	unsigned int	count = PAGE_CACHE_SIZE;
 	int		result;
-	int		flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
-	int		eof;
+	struct nfs_read_data	rdata = {
+		.flags		= (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0),
+		.cred		= NULL,
+		.inode		= inode,
+		.args		= {
+			.fh		= NFS_FH(inode),
+			.pages		= &page,
+			.pgbase		= 0UL,
+			.count		= rsize,
+		},
+		.res		= {
+			.fattr		= &rdata.fattr,
+		}
+	};
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
 
 	if (file)
-		cred = nfs_file_cred(file);
+		rdata.cred = nfs_file_cred(file);
 
 	/*
 	 * This works now because the socket layer never tries to DMA
@@ -89,17 +98,19 @@ nfs_readpage_sync(struct file *file, str
 	 */
 	do {
 		if (count < rsize)
-			rsize = count;
+			rdata.args.count = count;
+		rdata.res.count = rdata.args.count;
+		rdata.args.offset = page_offset(page) + rdata.args.pgbase;
 
 		dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
 			NFS_SERVER(inode)->hostname,
 			inode->i_sb->s_id,
 			(long long)NFS_FILEID(inode),
-			(unsigned long long)offset, rsize);
+			(unsigned long long)rdata.args.pgbase,
+			rdata.args.count);
 
 		lock_kernel();
-		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
-						offset, rsize, page, &eof);
+		result = NFS_PROTO(inode)->read(&rdata);
 		unlock_kernel();
 
 		/*
@@ -111,14 +122,14 @@ nfs_readpage_sync(struct file *file, str
 				result = -EINVAL;
 			goto io_error;
 		}
-		count  -= result;
-		offset += result;
-		if (result < rsize)	/* NFSv2ism */
+		count -= result;
+		rdata.args.pgbase += result;
+		if (result < rdata.args.count)	/* NFSv2ism */
 			break;
 	} while (count);
 
 	if (count)
-		memclear_highpage_flush(page, offset, count);
+		memclear_highpage_flush(page, rdata.args.pgbase, count);
 	SetPageUptodate(page);
 	if (PageError(page))
 		ClearPageError(page);
diff -puN include/linux/nfs_xdr.h~nfs-O_DIRECT-nfs_read_data include/linux/nfs_xdr.h
--- 25/include/linux/nfs_xdr.h~nfs-O_DIRECT-nfs_read_data	2003-06-17 16:00:20.000000000 -0700
+++ 25-akpm/include/linux/nfs_xdr.h	2003-06-17 16:00:20.000000000 -0700
@@ -591,6 +591,7 @@ struct nfs4_compound {
 #endif /* CONFIG_NFS_V4 */
 
 struct nfs_read_data {
+	int			flags;
 	struct rpc_task		task;
 	struct inode		*inode;
 	struct rpc_cred		*cred;
@@ -634,10 +635,7 @@ struct nfs_rpc_ops {
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*access)  (struct inode *, struct rpc_cred *, int);
 	int	(*readlink)(struct inode *, struct page *);
-	int	(*read)    (struct inode *, struct rpc_cred *,
-			    struct nfs_fattr *,
-			    int, unsigned int, unsigned int,
-			    struct page *, int *eofp);
+	int	(*read)    (struct nfs_read_data *);
 	int	(*write)   (struct inode *, struct rpc_cred *,
 			    struct nfs_fattr *,
 			    int, unsigned int, unsigned int,

_