From: Chuck Lever 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 *, _