fs/nfs/direct.c | 9 fs/nfs/inode.c | 23 fs/nfs/nfs2xdr.c | 6 fs/nfs/nfs3proc.c | 55 fs/nfs/nfs3xdr.c | 6 fs/nfs/nfs4proc.c | 1121 ++++--------- fs/nfs/nfs4state.c | 2 fs/nfs/nfs4xdr.c | 2801 ++++++++++++++++++++-------------- fs/nfs/nfsroot.c | 216 +- fs/nfs/pagelist.c | 3 fs/nfs/proc.c | 42 fs/nfs/read.c | 341 +++- fs/nfs/write.c | 532 ++++-- include/linux/nfs4.h | 129 - include/linux/nfs_fs.h | 16 include/linux/nfs_fs_sb.h | 11 include/linux/nfs_page.h | 42 include/linux/nfs_xdr.h | 288 +-- include/linux/sunrpc/sched.h | 66 include/linux/sunrpc/xdr.h | 91 - include/linux/sunrpc/xprt.h | 2 net/sunrpc/auth_gss/auth_gss.c | 9 net/sunrpc/auth_gss/gss_krb5_crypto.c | 35 net/sunrpc/clnt.c | 12 net/sunrpc/sched.c | 244 ++ net/sunrpc/sunrpc_syms.c | 3 net/sunrpc/xdr.c | 204 ++ net/sunrpc/xprt.c | 26 28 files changed, 3705 insertions(+), 2630 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/direct.c linux-2.6.5-31-server_caps/fs/nfs/direct.c --- linux-2.6.5-rc2/fs/nfs/direct.c 2004-03-25 00:30:05.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/direct.c 2004-03-25 00:35:45.000000000 -0500 @@ -128,6 +128,7 @@ nfs_direct_read_seg(struct inode *inode, .inode = inode, .args = { .fh = NFS_FH(inode), + .lockowner = current->files, }, .res = { .fattr = &rdata.fattr, @@ -258,6 +259,7 @@ nfs_direct_write_seg(struct inode *inode .inode = inode, .args = { .fh = NFS_FH(inode), + .lockowner = current->files, }, .res = { .fattr = &wdata.fattr, @@ -335,8 +337,7 @@ retry: VERF_SIZE) != 0) goto sync_retry; } - nfs_end_data_update(inode); - NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA; + nfs_end_data_update_defer(inode); return tot_bytes; @@ -395,10 +396,6 @@ nfs_direct_write(struct inode *inode, st if (result < size) break; } - /* Zap the page cache if we managed to write */ - if (tot_bytes > 0) - invalidate_remote_inode(inode); - return tot_bytes; } diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/inode.c linux-2.6.5-31-server_caps/fs/nfs/inode.c --- linux-2.6.5-rc2/fs/nfs/inode.c 2004-03-25 00:30:03.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/inode.c 2004-03-25 00:35:45.000000000 -0500 @@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode * nfs_end_data_update * @inode - pointer to inode * Declare end of the operations that will update file data + * This will mark the inode as immediately needing revalidation + * of its attribute cache. */ void nfs_end_data_update(struct inode *inode) { @@ -1027,6 +1029,27 @@ void nfs_end_data_update(struct inode *i } /** + * nfs_end_data_update_defer + * @inode - pointer to inode + * Declare end of the operations that will update file data + * This will defer marking the inode as needing revalidation + * unless there are no other pending updates. + */ +void nfs_end_data_update_defer(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (atomic_dec_and_test(&nfsi->data_updates)) { + /* Mark the attribute cache for revalidation */ + nfsi->flags |= NFS_INO_INVALID_ATTR; + /* Directories and symlinks: invalidate page cache too */ + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + nfsi->flags |= NFS_INO_INVALID_DATA; + nfsi->cache_change_attribute ++; + } +} + +/** * nfs_refresh_inode - verify consistency of the inode attribute cache * @inode - pointer to inode * @fattr - updated attributes diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs2xdr.c linux-2.6.5-31-server_caps/fs/nfs/nfs2xdr.c --- linux-2.6.5-rc2/fs/nfs/nfs2xdr.c 2004-03-25 00:29:42.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs2xdr.c 2004-03-25 00:37:38.000000000 -0500 @@ -231,7 +231,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u static int nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, recvd, hdrlen; if ((status = ntohl(*p++))) @@ -250,7 +250,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u3 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); @@ -396,7 +396,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs3proc.c linux-2.6.5-31-server_caps/fs/nfs/nfs3proc.c --- linux-2.6.5-rc2/fs/nfs/nfs3proc.c 2004-03-25 00:29:50.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs3proc.c 2004-03-25 00:35:13.000000000 -0500 @@ -729,11 +729,10 @@ nfs3_read_done(struct rpc_task *task) } static void -nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count) +nfs3_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int flags; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_READ], @@ -741,27 +740,13 @@ nfs3_proc_read_setup(struct nfs_read_dat .rpc_resp = &data->res, .rpc_cred = data->cred, }; - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.pages = data->pagevec; - data->args.count = count; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.eof = 0; - + /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_readdata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void @@ -778,11 +763,10 @@ nfs3_write_done(struct rpc_task *task) } static void -nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) +nfs3_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int stable; int flags; struct rpc_message msg = { @@ -799,28 +783,14 @@ nfs3_proc_write_setup(struct nfs_write_d stable = NFS_DATA_SYNC; } else stable = NFS_UNSTABLE; - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.count = count; data->args.stable = stable; - data->args.pages = data->pagevec; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.verf = &data->verf; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_writedata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void @@ -837,7 +807,7 @@ nfs3_commit_done(struct rpc_task *task) } static void -nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) +nfs3_proc_commit_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; @@ -849,23 +819,12 @@ nfs3_proc_commit_setup(struct nfs_write_ .rpc_cred = data->cred, }; - data->args.fh = NFS_FH(data->inode); - data->args.offset = start; - data->args.count = len; - data->res.count = len; - data->res.fattr = &data->fattr; - data->res.verf = &data->verf; - /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_commit_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } /* diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs3xdr.c linux-2.6.5-31-server_caps/fs/nfs/nfs3xdr.c --- linux-2.6.5-rc2/fs/nfs/nfs3xdr.c 2004-03-25 00:30:15.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs3xdr.c 2004-03-25 00:37:38.000000000 -0500 @@ -515,7 +515,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; @@ -758,7 +758,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *re static int nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, ocount, recvd, hdrlen; status = ntohl(*p++); @@ -789,7 +789,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs4proc.c linux-2.6.5-31-server_caps/fs/nfs/nfs4proc.c --- linux-2.6.5-rc2/fs/nfs/nfs4proc.c 2004-03-25 00:30:02.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs4proc.c 2004-03-25 14:27:20.000000000 -0500 @@ -51,10 +51,7 @@ #define NFS4_POLL_RETRY_TIME (15*HZ) -#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name -#define OPNUM(cp) cp->ops[cp->req_nops].opnum - -static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); +static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; @@ -72,102 +69,10 @@ static inline int nfs4_map_errors(int er return err; } -static void -nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, - struct nfs_server *server, char *tag) -{ - memset(cp, 0, sizeof(*cp)); - cp->ops = ops; - cp->server = server; -} - -static void -nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access) -{ - struct nfs4_access *access = GET_OP(cp, access); - - access->ac_req_access = req_access; - access->ac_resp_supported = resp_supported; - access->ac_resp_access = resp_access; - - OPNUM(cp) = OP_ACCESS; - cp->req_nops++; -} - -static void -nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name, - struct iattr *sattr, struct nfs4_change_info *info) -{ - struct nfs4_create *create = GET_OP(cp, create); - - create->cr_ftype = NF4DIR; - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - -static void -nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name, - struct qstr *linktext, struct iattr *sattr, - struct nfs4_change_info *info) -{ - struct nfs4_create *create = GET_OP(cp, create); - - create->cr_ftype = NF4LNK; - create->cr_textlen = linktext->len; - create->cr_text = linktext->name; - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - -static void -nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name, - dev_t dev, struct iattr *sattr, - struct nfs4_change_info *info) -{ - int mode = sattr->ia_mode; - struct nfs4_create *create = GET_OP(cp, create); - - BUG_ON(!(sattr->ia_valid & ATTR_MODE)); - BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); - - if (S_ISFIFO(mode)) - create->cr_ftype = NF4FIFO; - else if (S_ISBLK(mode)) { - create->cr_ftype = NF4BLK; - create->cr_specdata1 = MAJOR(dev); - create->cr_specdata2 = MINOR(dev); - } - else if (S_ISCHR(mode)) { - create->cr_ftype = NF4CHR; - create->cr_specdata1 = MAJOR(dev); - create->cr_specdata2 = MINOR(dev); - } - else - create->cr_ftype = NF4SOCK; - - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - /* * This is our standard bitmap for GETATTR requests. */ -u32 nfs4_fattr_bitmap[2] = { +const u32 nfs4_fattr_bitmap[2] = { FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE @@ -184,7 +89,7 @@ u32 nfs4_fattr_bitmap[2] = { | FATTR4_WORD1_TIME_MODIFY }; -u32 nfs4_statfs_bitmap[2] = { +const u32 nfs4_statfs_bitmap[2] = { FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL, @@ -199,121 +104,28 @@ u32 nfs4_pathconf_bitmap[2] = { 0 }; -static inline void -__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap, - struct nfs_fattr *fattr, - struct nfs_fsstat *fsstat, - struct nfs_pathconf *pathconf) -{ - struct nfs4_getattr *getattr = GET_OP(cp, getattr); - - getattr->gt_bmval = bitmap; - getattr->gt_attrs = fattr; - getattr->gt_fsstat = fsstat; - getattr->gt_pathconf = pathconf; - - OPNUM(cp) = OP_GETATTR; - cp->req_nops++; -} - -static void -nfs4_setup_getattr(struct nfs4_compound *cp, - struct nfs_fattr *fattr) -{ - __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr, - NULL, NULL); -} - -static void -nfs4_setup_statfs(struct nfs4_compound *cp, - struct nfs_fsstat *fsstat) -{ - __nfs4_setup_getattr(cp, nfs4_statfs_bitmap, - NULL, fsstat, NULL); -} - -static void -nfs4_setup_pathconf(struct nfs4_compound *cp, - struct nfs_pathconf *pathconf) -{ - __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap, - NULL, NULL, pathconf); -} - -static void -nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) -{ - struct nfs4_getfh *getfh = GET_OP(cp, getfh); - - getfh->gf_fhandle = fhandle; - - OPNUM(cp) = OP_GETFH; - cp->req_nops++; -} - -static void -nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name, - struct nfs4_change_info *info) -{ - struct nfs4_link *link = GET_OP(cp, link); - - link->ln_namelen = name->len; - link->ln_name = name->name; - link->ln_cinfo = info; - - OPNUM(cp) = OP_LINK; - cp->req_nops++; -} - -static void -nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q) -{ - struct nfs4_lookup *lookup = GET_OP(cp, lookup); - - lookup->lo_name = q; - - OPNUM(cp) = OP_LOOKUP; - cp->req_nops++; -} - -static void -nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) -{ - struct nfs4_putfh *putfh = GET_OP(cp, putfh); - - putfh->pf_fhandle = fhandle; - - OPNUM(cp) = OP_PUTFH; - cp->req_nops++; -} - -static void -nfs4_setup_putrootfh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_PUTROOTFH; - cp->req_nops++; -} +const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE + | FATTR4_WORD0_MAXREAD + | FATTR4_WORD0_MAXWRITE + | FATTR4_WORD0_LEASE_TIME, + 0 +}; -static void -nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, - struct page **pages, unsigned int bufsize, struct dentry *dentry) +static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, + struct nfs4_readdir_arg *readdir) { u32 *start, *p; - struct nfs4_readdir *readdir = GET_OP(cp, readdir); - BUG_ON(bufsize < 80); - readdir->rd_cookie = (cookie > 2) ? cookie : 0; - memcpy(&readdir->rd_req_verifier, verifier, sizeof(readdir->rd_req_verifier)); - readdir->rd_count = bufsize; - readdir->rd_bmval[0] = FATTR4_WORD0_FILEID; - readdir->rd_bmval[1] = 0; - readdir->rd_pages = pages; - readdir->rd_pgbase = 0; - - OPNUM(cp) = OP_READDIR; - cp->req_nops++; + BUG_ON(readdir->count < 80); + if (cookie > 2) { + readdir->cookie = (cookie > 2) ? cookie : 0; + memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); + return; + } - if (cookie >= 2) + readdir->cookie = 0; + memset(&readdir->verifier, 0, sizeof(readdir->verifier)); + if (cookie == 2) return; /* @@ -323,7 +135,7 @@ nfs4_setup_readdir(struct nfs4_compound * when talking to the server, we always send cookie 0 * instead of 1 or 2. */ - start = p = (u32 *)kmap_atomic(*pages, KM_USER0); + start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0); if (cookie == 0) { *p++ = xdr_one; /* next */ @@ -335,7 +147,7 @@ nfs4_setup_readdir(struct nfs4_compound *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode)); + p = xdr_encode_hyper(p, dentry->d_inode->i_ino); } *p++ = xdr_one; /* next */ @@ -347,70 +159,14 @@ nfs4_setup_readdir(struct nfs4_compound *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode)); + p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino); - readdir->rd_pgbase = (char *)p - (char *)start; - readdir->rd_count -= readdir->rd_pgbase; + readdir->pgbase = (char *)p - (char *)start; + readdir->count -= readdir->pgbase; kunmap_atomic(start, KM_USER0); } static void -nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages) -{ - struct nfs4_readlink *readlink = GET_OP(cp, readlink); - - readlink->rl_count = count; - readlink->rl_pages = pages; - - OPNUM(cp) = OP_READLINK; - cp->req_nops++; -} - -static void -nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo) -{ - struct nfs4_remove *remove = GET_OP(cp, remove); - - remove->rm_namelen = name->len; - remove->rm_name = name->name; - remove->rm_cinfo = cinfo; - - OPNUM(cp) = OP_REMOVE; - cp->req_nops++; -} - -static void -nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new, - struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo) -{ - struct nfs4_rename *rename = GET_OP(cp, rename); - - rename->rn_oldnamelen = old->len; - rename->rn_oldname = old->name; - rename->rn_newnamelen = new->len; - rename->rn_newname = new->name; - rename->rn_src_cinfo = old_cinfo; - rename->rn_dst_cinfo = new_cinfo; - - OPNUM(cp) = OP_RENAME; - cp->req_nops++; -} - -static void -nfs4_setup_restorefh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_RESTOREFH; - cp->req_nops++; -} - -static void -nfs4_setup_savefh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_SAVEFH; - cp->req_nops++; -} - -static void renew_lease(struct nfs_server *server, unsigned long timestamp) { struct nfs4_client *clp = server->nfs4_state; @@ -420,58 +176,12 @@ renew_lease(struct nfs_server *server, u spin_unlock(&clp->cl_lock); } -static inline void -process_lease(struct nfs4_compound *cp) +static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo) { - /* - * Generic lease processing: If this operation contains a - * lease-renewing operation, and it succeeded, update the RENEW time - * in the superblock. Instead of the current time, we use the time - * when the request was sent out. (All we know is that the lease was - * renewed sometime between then and now, and we have to assume the - * worst case.) - * - * Notes: - * (1) renewd doesn't acquire the spinlock when messing with - * server->last_renewal; this is OK since rpciod always runs - * under the BKL. - * (2) cp->timestamp was set at the end of XDR encode. - */ - if (!cp->renew_index) - return; - if (!cp->toplevel_status || cp->resp_nops > cp->renew_index) - renew_lease(cp->server, cp->timestamp); -} - -static int -nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags) -{ - int status; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND], - .rpc_argp = cp, - .rpc_resp = cp, - .rpc_cred = cred, - }; - - status = rpc_call_sync(cp->server->client, &msg, flags); - if (!status) - process_lease(cp); - - return status; -} + struct nfs_inode *nfsi = NFS_I(inode); -static inline void -process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) -{ - BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0); - BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0); - - if (fattr->change_attr == info->after) { - fattr->pre_change_attr = info->before; - fattr->valid |= NFS_ATTR_PRE_CHANGE; - fattr->timestamp = jiffies; - } + if (cinfo->before == nfsi->change_attr && cinfo->atomic) + nfsi->change_attr = cinfo->after; } /* @@ -487,12 +197,6 @@ nfs4_open_reclaim(struct nfs4_state_owne struct nfs_fattr fattr = { .valid = 0, }; - struct nfs4_change_info d_cinfo; - struct nfs4_getattr f_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &fattr, - }; - struct nfs_open_reclaimargs o_arg = { .fh = NFS_FH(inode), .seqid = sp->so_seqid, @@ -500,11 +204,10 @@ nfs4_open_reclaim(struct nfs4_state_owne .share_access = state->state, .clientid = server->nfs4_state->cl_clientid, .claim = NFS4_OPEN_CLAIM_PREVIOUS, - .f_getattr = &f_getattr, + .bitmask = server->attr_bitmask, }; struct nfs_openres o_res = { - .cinfo = &d_cinfo, - .f_getattr = &f_getattr, + .f_attr = &fattr, .server = server, /* Grrr */ }; struct rpc_message msg = { @@ -534,36 +237,21 @@ nfs4_do_open(struct inode *dir, struct q struct nfs4_state *state = NULL; struct nfs_server *server = NFS_SERVER(dir); struct inode *inode = NULL; - struct nfs4_change_info d_cinfo; int status; - struct nfs_fattr d_attr = { - .valid = 0, - }; struct nfs_fattr f_attr = { .valid = 0, }; - struct nfs4_getattr f_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &f_attr, - }; - struct nfs4_getattr d_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &d_attr, - }; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .share_access = flags & (FMODE_READ|FMODE_WRITE), .opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE, .createmode = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED, .name = name, - .f_getattr = &f_getattr, - .d_getattr = &d_getattr, .server = server, + .bitmask = server->attr_bitmask, }; struct nfs_openres o_res = { - .cinfo = &d_cinfo, - .f_getattr = &f_getattr, - .d_getattr = &d_getattr, + .f_attr = &f_attr, .server = server, }; struct rpc_message msg = { @@ -596,8 +284,7 @@ retry: nfs4_increment_seqid(status, sp); if (status) goto out_up; - process_cinfo(&d_cinfo, &d_attr); - nfs_refresh_inode(dir, &d_attr); + update_changeattr(dir, &o_res.cinfo); status = -ENOMEM; inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); @@ -679,18 +366,14 @@ nfs4_do_setattr(struct nfs_server *serve struct nfs_fh *fhandle, struct iattr *sattr, struct nfs4_state *state) { - struct nfs4_getattr getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = fattr, - }; struct nfs_setattrargs arg = { .fh = fhandle, .iap = sattr, - .attr = &getattr, .server = server, + .bitmask = server->attr_bitmask, }; struct nfs_setattrres res = { - .attr = &getattr, + .fattr = fattr, .server = server, }; struct rpc_message msg = { @@ -834,30 +517,85 @@ nfs4_open_revalidate(struct inode *dir, return 0; } -static int -nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *info) + +static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) +{ + struct nfs4_server_caps_res res = {}; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], + .rpc_argp = fhandle, + .rpc_resp = &res, + }; + int status; + + status = rpc_call_sync(server->client, &msg, 0); + if (status == 0) { + memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); + if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) + server->caps |= NFS_CAP_ACLS; + if (res.has_links != 0) + server->caps |= NFS_CAP_HARDLINKS; + if (res.has_symlinks != 0) + server->caps |= NFS_CAP_SYMLINKS; + server->acl_bitmask = res.acl_bitmask; + } + return status; +} + +static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) +{ + struct nfs_fattr * fattr = info->fattr; + struct nfs4_lookup_root_arg args = { + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_lookup_res res = { + .server = server, + .fattr = fattr, + .fh = fhandle, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; + return rpc_call_sync(server->client, &msg, 0); +} + +static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) { - struct nfs4_compound compound; - struct nfs4_op ops[4]; struct nfs_fattr * fattr = info->fattr; unsigned char * p; struct qstr q; - int status; + struct nfs4_lookup_arg args = { + .dir_fh = fhandle, + .name = &q, + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_lookup_res res = { + .server = server, + .fattr = fattr, + .fh = fhandle, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], + .rpc_argp = &args, + .rpc_resp = &res, + }; + int status; /* * Now we do a separate LOOKUP for each component of the mount path. * The LOOKUPs are done separately so that we can conveniently * catch an ERR_WRONGSEC if it occurs along the way... */ - p = server->mnt_path; - fattr->valid = 0; - nfs4_setup_compound(&compound, ops, server, "getrootfh"); - nfs4_setup_putrootfh(&compound); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - if ((status = nfs4_call_compound(&compound, NULL, 0))) + status = nfs4_lookup_root(server, fhandle, info); + if (status) goto out; + + p = server->mnt_path; for (;;) { while (*p == '/') p++; @@ -869,12 +607,7 @@ nfs4_proc_get_root(struct nfs_server *se q.len = p - q.name; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, server, "mount"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_lookup(&compound, &q); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(server->client, &msg, 0); if (!status) continue; if (status == -ENOENT) { @@ -883,24 +616,34 @@ nfs4_proc_get_root(struct nfs_server *se } break; } + if (status == 0) + status = nfs4_server_capabilities(server, fhandle); + if (status == 0) + status = nfs4_do_fsinfo(server, fhandle, info); out: - if (status) - return nfs4_map_errors(status); - return nfs4_proc_fsinfo(server, fhandle, info); + return nfs4_map_errors(status); } -static int -nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) +static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; - + struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_getattr_arg args = { + .fh = NFS_FH(inode), + .bitmask = server->attr_bitmask, + }; + struct nfs4_getattr_res res = { + .fattr = fattr, + .server = server, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_getattr(&compound, fattr); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); } /* @@ -962,75 +705,72 @@ out: return status; } -static int -nfs4_proc_lookup(struct inode *dir, struct qstr *name, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[5]; - struct nfs_fattr dir_attr; - int status; - - dir_attr.valid = 0; + int status; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_lookup_arg args = { + .bitmask = server->attr_bitmask, + .dir_fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_lookup_res res = { + .server = server, + .fattr = fattr, + .fh = fhandle, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; dprintk("NFS call lookup %s\n", name->name); - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_getattr(&compound, &dir_attr); - nfs4_setup_lookup(&compound, name); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply lookup: %d\n", status); - - if (status >= 0) - status = nfs_refresh_inode(dir, &dir_attr); return nfs4_map_errors(status); } -static int -nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode) +static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode) { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs_fattr fattr; - u32 req_access = 0, resp_supported, resp_access; int status; - - fattr.valid = 0; + struct nfs4_accessargs args = { + .fh = NFS_FH(inode), + }; + struct nfs4_accessres res = { 0 }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], + .rpc_argp = &args, + .rpc_resp = &res, + .rpc_cred = cred, + }; /* * Determine which access bits we want to ask for... */ if (mode & MAY_READ) - req_access |= NFS4_ACCESS_READ; + args.access |= NFS4_ACCESS_READ; if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) - req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE; + args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE; if (mode & MAY_EXEC) - req_access |= NFS4_ACCESS_LOOKUP; + args.access |= NFS4_ACCESS_LOOKUP; } else { if (mode & MAY_WRITE) - req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND; + args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND; if (mode & MAY_EXEC) - req_access |= NFS4_ACCESS_EXECUTE; + args.access |= NFS4_ACCESS_EXECUTE; } - - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_getattr(&compound, &fattr); - nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access); - status = nfs4_call_compound(&compound, cred, 0); - nfs_refresh_inode(inode, &fattr); - + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (!status) { - if (req_access != resp_supported) { + if (args.access != res.supported) { printk(KERN_NOTICE "NFS: server didn't support all access bits!\n"); status = -ENOTSUPP; - } - else if (req_access != resp_access) + } else if ((args.access & res.access) != args.access) status = -EACCES; } return nfs4_map_errors(status); @@ -1060,16 +800,20 @@ nfs4_proc_access(struct inode *inode, st * Both of these changes to the XDR layer would in fact be quite * minor, but I decided to leave them for a subsequent patch. */ -static int -nfs4_proc_readlink(struct inode *inode, struct page *page) +static int nfs4_proc_readlink(struct inode *inode, struct page *page) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_readlink args = { + .fh = NFS_FH(inode), + .count = PAGE_CACHE_SIZE, + .pages = &page, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], + .rpc_argp = &args, + .rpc_resp = NULL, + }; - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); } static int @@ -1096,10 +840,10 @@ nfs4_proc_read(struct nfs_read_data *rda if (filp) { struct nfs4_state *state; state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&rdata->args.stateid, state, rdata->lockowner); + rdata->args.state = state; msg.rpc_cred = state->owner->so_cred; } else { - memcpy(&rdata->args.stateid, &zero_stateid, sizeof(rdata->args.stateid)); + rdata->args.state = NULL; msg.rpc_cred = NFS_I(inode)->mm_cred; } @@ -1134,10 +878,10 @@ nfs4_proc_write(struct nfs_write_data *w if (filp) { struct nfs4_state *state; state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&wdata->args.stateid, state, wdata->lockowner); + wdata->args.state = state; msg.rpc_cred = state->owner->so_cred; } else { - memcpy(&wdata->args.stateid, &zero_stateid, sizeof(wdata->args.stateid)); + wdata->args.state = NULL; msg.rpc_cred = NFS_I(inode)->mm_cred; } @@ -1166,15 +910,10 @@ nfs4_proc_commit(struct nfs_write_data * /* * Try first to use O_WRONLY, then O_RDWR stateid. */ - if (filp) { - struct nfs4_state *state; - state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&cdata->args.stateid, state, cdata->lockowner); - msg.rpc_cred = state->owner->so_cred; - } else { - memcpy(&cdata->args.stateid, &zero_stateid, sizeof(cdata->args.stateid)); + if (filp) + msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred; + else msg.rpc_cred = NFS_I(inode)->mm_cred; - } fattr->valid = 0; status = rpc_call_sync(server->client, &msg, 0); @@ -1226,301 +965,318 @@ nfs4_proc_create(struct inode *dir, stru return inode; } -static int -nfs4_proc_remove(struct inode *dir, struct qstr *name) +static int nfs4_proc_remove(struct inode *dir, struct qstr *name) { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs4_change_info dir_cinfo; - struct nfs_fattr dir_attr; + struct nfs4_remove_arg args = { + .fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_change_info res; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], + .rpc_argp = &args, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_remove(&compound, name, &dir_cinfo); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (status == 0) + update_changeattr(dir, &res); return nfs4_map_errors(status); } struct unlink_desc { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs4_change_info cinfo; - struct nfs_fattr attrs; + struct nfs4_remove_arg args; + struct nfs4_change_info res; }; -static int -nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, + struct qstr *name) { - struct unlink_desc * up; - struct nfs4_compound * cp; + struct unlink_desc *up; up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; - cp = &up->compound; - nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup"); - nfs4_setup_putfh(cp, NFS_FH(dir->d_inode)); - nfs4_setup_remove(cp, name, &up->cinfo); - nfs4_setup_getattr(cp, &up->attrs); + up->args.fh = NFS_FH(dir->d_inode); + up->args.name = name; - msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND]; - msg->rpc_argp = cp; - msg->rpc_resp = cp; + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; + msg->rpc_argp = &up->args; + msg->rpc_resp = &up->res; return 0; } -static int -nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) +static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) { struct rpc_message *msg = &task->tk_msg; struct unlink_desc *up; - if (msg->rpc_argp) { - up = (struct unlink_desc *) msg->rpc_argp; - process_lease(&up->compound); - process_cinfo(&up->cinfo, &up->attrs); - nfs_refresh_inode(dir->d_inode, &up->attrs); + if (msg->rpc_resp != NULL) { + up = container_of(msg->rpc_resp, struct unlink_desc, res); + update_changeattr(dir->d_inode, &up->res); kfree(up); + msg->rpc_resp = NULL; msg->rpc_argp = NULL; } return 0; } -static int -nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) +static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, + struct inode *new_dir, struct qstr *new_name) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs4_change_info old_cinfo, new_cinfo; - struct nfs_fattr old_dir_attr, new_dir_attr; + struct nfs4_rename_arg arg = { + .old_dir = NFS_FH(old_dir), + .new_dir = NFS_FH(new_dir), + .old_name = old_name, + .new_name = new_name, + }; + struct nfs4_rename_res res = { }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - - old_dir_attr.valid = 0; - new_dir_attr.valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename"); - nfs4_setup_putfh(&compound, NFS_FH(old_dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_putfh(&compound, NFS_FH(new_dir)); - nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo); - nfs4_setup_getattr(&compound, &new_dir_attr); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &old_dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); if (!status) { - process_cinfo(&old_cinfo, &old_dir_attr); - process_cinfo(&new_cinfo, &new_dir_attr); - nfs_refresh_inode(old_dir, &old_dir_attr); - nfs_refresh_inode(new_dir, &new_dir_attr); + update_changeattr(old_dir, &res.old_cinfo); + update_changeattr(new_dir, &res.new_cinfo); } return nfs4_map_errors(status); } -static int -nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) +static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs4_change_info dir_cinfo; - struct nfs_fattr dir_attr, fattr; + struct nfs4_link_arg arg = { + .fh = NFS_FH(inode), + .dir_fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_change_info cinfo = { }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], + .rpc_argp = &arg, + .rpc_resp = &cinfo, + }; int status; - - dir_attr.valid = 0; - fattr.valid = 0; - - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_savefh(&compound); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_link(&compound, name, &dir_cinfo); - nfs4_setup_getattr(&compound, &dir_attr); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &fattr); - status = nfs4_call_compound(&compound, NULL, 0); - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - nfs_refresh_inode(inode, &fattr); - } + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + if (!status) + update_changeattr(dir, &cinfo); + return nfs4_map_errors(status); } -static int -nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, - struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) -{ - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; +static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, + struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) +{ + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = name, + .attrs = sattr, + .ftype = NF4LNK, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = fhandle, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; + arg.u.symlink = path; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } -static int -nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, + struct iattr *sattr, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = name, + .attrs = sattr, + .ftype = NF4DIR, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = fhandle, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } -static int -nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, +static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page *page, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_readdir_arg args = { + .fh = NFS_FH(dir), + .pages = &page, + .pgbase = 0, + .count = count, + }; + struct nfs4_readdir_res res; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR], + .rpc_argp = &args, + .rpc_resp = &res, + .rpc_cred = cred, + }; int status; lock_kernel(); - - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry); - status = nfs4_call_compound(&compound, cred, 0); + nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); + res.pgbase = args.pgbase; + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) - memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE); - + memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); unlock_kernel(); return nfs4_map_errors(status); } -static int -nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, - dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) +static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, + struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, + struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = server, + .name = name, + .attrs = sattr, + .bitmask = server->attr_bitmask, + }; + struct nfs4_create_res res = { + .server = server, + .fh = fh, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; + int mode = sattr->ia_mode; - dir_attr.valid = 0; fattr->valid = 0; - - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fh); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); + BUG_ON(!(sattr->ia_valid & ATTR_MODE)); + BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); + if (S_ISFIFO(mode)) + arg.ftype = NF4FIFO; + else if (S_ISBLK(mode)) { + arg.ftype = NF4BLK; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); } + else if (S_ISCHR(mode)) { + arg.ftype = NF4CHR; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); + } + else + arg.ftype = NF4SOCK; + + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } -static int -nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, +static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_statfs_arg args = { + .fh = fhandle, + .bitmask = server->attr_bitmask, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], + .rpc_argp = &args, + .rpc_resp = fsstat, + }; - nfs4_setup_compound(&compound, ops, server, "statfs"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_statfs(&compound, fsstat); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + fsstat->fattr->valid = 0; + return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } -static int -nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *fsinfo) +static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *fsinfo) { + struct nfs4_fsinfo_arg args = { + .fh = fhandle, + .bitmask = server->attr_bitmask, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], - .rpc_argp = fhandle, + .rpc_argp = &args, .rpc_resp = fsinfo, }; return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } -static int -nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_pathconf *pathconf) +static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; - - nfs4_setup_compound(&compound, ops, server, "statfs"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_pathconf(&compound, pathconf); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + fsinfo->fattr->valid = 0; + return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo)); } -static void -nfs4_restart_read(struct rpc_task *task) +static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_pathconf *pathconf) { - struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; - struct nfs_page *req; + struct nfs4_pathconf_arg args = { + .fh = fhandle, + .bitmask = server->attr_bitmask, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], + .rpc_argp = &args, + .rpc_resp = pathconf, + }; - rpc_restart_call(task); - req = nfs_list_entry(data->pages.next); - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); + /* None of the pathconf attributes are mandatory to implement */ + if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) { + memset(pathconf, 0, sizeof(*pathconf)); + return 0; + } + + pathconf->fattr->valid = 0; + return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } static void @@ -1530,7 +1286,7 @@ nfs4_read_done(struct rpc_task *task) struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_read; + rpc_restart_call(task); return; } if (task->tk_status > 0) @@ -1540,7 +1296,7 @@ nfs4_read_done(struct rpc_task *task) } static void -nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count) +nfs4_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1550,59 +1306,26 @@ nfs4_proc_read_setup(struct nfs_read_dat .rpc_cred = data->cred, }; struct inode *inode = data->inode; - struct nfs_page *req = nfs_list_entry(data->pages.next); int flags; - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.pages = data->pagevec; - data->args.count = count; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.eof = 0; data->timestamp = jiffies; - data->lockowner = req->wb_lockowner; - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); - /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_readdata_release; - rpc_call_setup(task, &msg, 0); } static void -nfs4_restart_write(struct rpc_task *task) -{ - struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; - struct nfs_page *req; - - rpc_restart_call(task); - req = nfs_list_entry(data->pages.next); - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); -} - -static void nfs4_write_done(struct rpc_task *task) { struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_write; + rpc_restart_call(task); return; } if (task->tk_status >= 0) @@ -1612,7 +1335,7 @@ nfs4_write_done(struct rpc_task *task) } static void -nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) +nfs4_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1622,7 +1345,6 @@ nfs4_proc_write_setup(struct nfs_write_d .rpc_cred = data->cred, }; struct inode *inode = data->inode; - struct nfs_page *req = nfs_list_entry(data->pages.next); int stable; int flags; @@ -1633,33 +1355,15 @@ nfs4_proc_write_setup(struct nfs_write_d stable = NFS_DATA_SYNC; } else stable = NFS_UNSTABLE; - - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.count = count; data->args.stable = stable; - data->args.pages = data->pagevec; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.verf = &data->verf; - data->timestamp = jiffies; - data->lockowner = req->wb_lockowner; - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); + data->timestamp = jiffies; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_writedata_release; - rpc_call_setup(task, &msg, 0); } @@ -1670,7 +1374,7 @@ nfs4_commit_done(struct rpc_task *task) struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_write; + rpc_restart_call(task); return; } /* Call back common NFS writeback processing */ @@ -1678,7 +1382,7 @@ nfs4_commit_done(struct rpc_task *task) } static void -nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) +nfs4_proc_commit_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1690,22 +1394,11 @@ nfs4_proc_commit_setup(struct nfs_write_ struct inode *inode = data->inode; int flags; - data->args.fh = NFS_FH(data->inode); - data->args.offset = start; - data->args.count = len; - data->res.count = len; - data->res.fattr = &data->fattr; - data->res.verf = &data->verf; - /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_commit_release; - rpc_call_setup(task, &msg, 0); } diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs4state.c linux-2.6.5-31-server_caps/fs/nfs/nfs4state.c --- linux-2.6.5-rc2/fs/nfs/nfs4state.c 2004-03-25 00:29:32.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs4state.c 2004-03-25 00:35:26.000000000 -0500 @@ -105,7 +105,7 @@ nfs4_alloc_client(struct in_addr *addr) INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); INIT_LIST_HEAD(&clp->cl_superblocks); init_waitqueue_head(&clp->cl_waitq); - INIT_RPC_WAITQ(&clp->cl_rpcwaitq, "NFS4 client"); + rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); clp->cl_state = 1 << NFS4CLNT_NEW; } return clp; diff -u --recursive --new-file --show-c-function linux-2.6.5-rc2/fs/nfs/nfs4xdr.c linux-2.6.5-31-server_caps/fs/nfs/nfs4xdr.c --- linux-2.6.5-rc2/fs/nfs/nfs4xdr.c 2004-03-25 00:30:14.000000000 -0500 +++ linux-2.6.5-31-server_caps/fs/nfs/nfs4xdr.c 2004-03-25 14:29:51.000000000 -0500 @@ -81,21 +81,14 @@ static int nfs_stat_to_errno(int); #define decode_putrootfh_maxsz (op_decode_hdr_maxsz) #define encode_getfh_maxsz (op_encode_hdr_maxsz) #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ - (NFS4_FHSIZE >> 2)) + ((3+NFS4_FHSIZE) >> 2)) #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) -#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)) +#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) +#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ nfs4_fattr_bitmap_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) -#define encode_restorefh_maxsz (op_encode_hdr_maxsz) -#define decode_restorefh_maxsz (op_decode_hdr_maxsz) -#define encode_read_getattr_maxsz (op_encode_hdr_maxsz + 2) -#define decode_read_getattr_maxsz (op_decode_hdr_maxsz + 8) -#define encode_pre_write_getattr_maxsz (op_encode_hdr_maxsz + 2) -#define decode_pre_write_getattr_maxsz (op_decode_hdr_maxsz + 5) -#define encode_post_write_getattr_maxsz (op_encode_hdr_maxsz + 2) -#define decode_post_write_getattr_maxsz (op_decode_hdr_maxsz + 13) #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) @@ -115,54 +108,63 @@ static int nfs_stat_to_errno(int); 3 + (NFS4_VERIFIER_SIZE >> 2)) #define decode_setclientid_confirm_maxsz \ (op_decode_hdr_maxsz) - +#define encode_lookup_maxsz (op_encode_hdr_maxsz + \ + 1 + ((3 + NFS4_FHSIZE) >> 2)) +#define encode_remove_maxsz (op_encode_hdr_maxsz + \ + nfs4_name_maxsz) +#define encode_rename_maxsz (op_encode_hdr_maxsz + \ + 2 * nfs4_name_maxsz) +#define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) +#define encode_link_maxsz (op_encode_hdr_maxsz + \ + nfs4_name_maxsz) +#define decode_link_maxsz (op_decode_hdr_maxsz + 5) +#define encode_create_maxsz (op_encode_hdr_maxsz + \ + 2 + 2 * nfs4_name_maxsz + \ + nfs4_fattr_bitmap_maxsz) +#define decode_create_maxsz (op_decode_hdr_maxsz + 8) #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_read_getattr_maxsz + \ op_encode_hdr_maxsz + 7) #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_read_getattr_maxsz + \ + op_decode_hdr_maxsz + 2) +#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz) +#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz) +#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 9) +#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ op_decode_hdr_maxsz + 2) #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_pre_write_getattr_maxsz + \ - op_encode_hdr_maxsz + 8 + \ - encode_post_write_getattr_maxsz) + op_encode_hdr_maxsz + 8) #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_pre_write_getattr_maxsz + \ - op_decode_hdr_maxsz + 4 + \ - decode_post_write_getattr_maxsz) + op_decode_hdr_maxsz + 4) #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_pre_write_getattr_maxsz + \ - op_encode_hdr_maxsz + 3 + \ - encode_post_write_getattr_maxsz) + op_encode_hdr_maxsz + 3) #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_pre_write_getattr_maxsz + \ - op_decode_hdr_maxsz + 2 + \ - decode_post_write_getattr_maxsz) + op_decode_hdr_maxsz + 2) #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_savefh_maxsz + \ op_encode_hdr_maxsz + \ 13 + 3 + 2 + 64 + \ encode_getattr_maxsz + \ - encode_getfh_maxsz + \ - encode_restorefh_maxsz + \ - encode_getattr_maxsz) + encode_getfh_maxsz) #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_savefh_maxsz + \ op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ decode_getattr_maxsz + \ - decode_getfh_maxsz + \ - decode_restorefh_maxsz + \ - decode_getattr_maxsz) + decode_getfh_maxsz) #define NFS4_enc_open_confirm_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -255,8 +257,88 @@ static int nfs_stat_to_errno(int); decode_putfh_maxsz + \ decode_getattr_maxsz + \ op_decode_hdr_maxsz + 4) - - +#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 1) +#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 2) +#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_getattr_maxsz) +#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_lookup_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) +#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ + encode_putrootfh_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ + decode_putrootfh_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) +#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_remove_maxsz) +#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 5) +#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + encode_putfh_maxsz + \ + encode_rename_maxsz) +#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + decode_putfh_maxsz + \ + decode_rename_maxsz) +#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + encode_putfh_maxsz + \ + encode_link_maxsz) +#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + decode_putfh_maxsz + \ + decode_link_maxsz) +#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_create_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_create_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) +#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_getattr_maxsz) +#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 12) +#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ + decode_getattr_maxsz) static struct { unsigned int mode; @@ -297,7 +379,7 @@ struct compound_hdr { *p++ = htonl((uint32_t)(n)); \ } while (0) #define WRITEMEM(ptr,nbytes) do { \ - p = xdr_writemem(p, ptr, nbytes); \ + p = xdr_encode_opaque_fixed(p, ptr, nbytes); \ } while (0) #define RESERVE_SPACE(nbytes) do { \ @@ -306,19 +388,7 @@ struct compound_hdr { BUG_ON(!p); \ } while (0) -static inline -uint32_t *xdr_writemem(uint32_t *p, const void *ptr, int nbytes) -{ - int tmp = XDR_QUADLEN(nbytes); - if (!tmp) - return p; - p[tmp-1] = 0; - memcpy(p, ptr, nbytes); - return p + tmp; -} - -static int -encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) +static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -332,9 +402,7 @@ encode_compound_hdr(struct xdr_stream *x return 0; } -static int -encode_attrs(struct xdr_stream *xdr, struct iattr *iap, - struct nfs_server *server) +static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) { char owner_name[IDMAP_NAMESZ]; char owner_group[IDMAP_NAMESZ]; @@ -461,20 +529,18 @@ encode_attrs(struct xdr_stream *xdr, str return status; } -static int -encode_access(struct xdr_stream *xdr, struct nfs4_access *access) +static int encode_access(struct xdr_stream *xdr, u32 access) { uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_ACCESS); - WRITE32(access->ac_req_access); + WRITE32(access); return 0; } -static int -encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg) +static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; @@ -486,8 +552,7 @@ encode_close(struct xdr_stream *xdr, str return 0; } -static int -encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args) +static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args) { uint32_t *p; @@ -499,42 +564,39 @@ encode_commit(struct xdr_stream *xdr, st return 0; } -static int -encode_create(struct xdr_stream *xdr, struct nfs4_create *create, - struct nfs_server *server) +static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create) { uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_CREATE); - WRITE32(create->cr_ftype); + WRITE32(create->ftype); - switch (create->cr_ftype) { + switch (create->ftype) { case NF4LNK: - RESERVE_SPACE(4 + create->cr_textlen); - WRITE32(create->cr_textlen); - WRITEMEM(create->cr_text, create->cr_textlen); + RESERVE_SPACE(4 + create->u.symlink->len); + WRITE32(create->u.symlink->len); + WRITEMEM(create->u.symlink->name, create->u.symlink->len); break; case NF4BLK: case NF4CHR: RESERVE_SPACE(8); - WRITE32(create->cr_specdata1); - WRITE32(create->cr_specdata2); + WRITE32(create->u.device.specdata1); + WRITE32(create->u.device.specdata2); break; default: break; } - RESERVE_SPACE(4 + create->cr_namelen); - WRITE32(create->cr_namelen); - WRITEMEM(create->cr_name, create->cr_namelen); + RESERVE_SPACE(4 + create->name->len); + WRITE32(create->name->len); + WRITEMEM(create->name->name, create->name->len); - return encode_attrs(xdr, create->cr_attrs, server); + return encode_attrs(xdr, create->attrs, create->server); } -static int -encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) +static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) { uint32_t *p; @@ -545,8 +607,7 @@ encode_getattr_one(struct xdr_stream *xd return 0; } -static int -encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) +static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) { uint32_t *p; @@ -558,56 +619,24 @@ encode_getattr_two(struct xdr_stream *xd return 0; } -static inline int -encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) -{ - return encode_getattr_two(xdr, getattr->gt_bmval[0], - getattr->gt_bmval[1]); -} - -/* - * Request the change attribute in order to check attribute+cache consistency - */ -static inline int -encode_read_getattr(struct xdr_stream *xdr) +static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) { - return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE, - FATTR4_WORD1_TIME_ACCESS); -} + extern u32 nfs4_fattr_bitmap[]; -/* - * Request the change attribute prior to doing a write operation - */ -static inline int -encode_pre_write_getattr(struct xdr_stream *xdr) -{ - /* Request the change attribute */ - return encode_getattr_one(xdr, FATTR4_WORD0_CHANGE); + return encode_getattr_two(xdr, + bitmask[0] & nfs4_fattr_bitmap[0], + bitmask[1] & nfs4_fattr_bitmap[1]); } -/* - * Request the change attribute, size, and [cm]time after a write operation - */ -static inline int -encode_post_write_getattr(struct xdr_stream *xdr) +static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) { - return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE, - FATTR4_WORD1_SPACE_USED | - FATTR4_WORD1_TIME_METADATA | - FATTR4_WORD1_TIME_MODIFY); -} + extern u32 nfs4_fsinfo_bitmap[]; -static int -encode_fsinfo(struct xdr_stream *xdr) -{ - return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE - | FATTR4_WORD0_MAXREAD - | FATTR4_WORD0_MAXWRITE - | FATTR4_WORD0_LEASE_TIME); + return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], + bitmask[1] & nfs4_fsinfo_bitmap[1]); } -static int -encode_getfh(struct xdr_stream *xdr) +static int encode_getfh(struct xdr_stream *xdr) { uint32_t *p; @@ -617,15 +646,14 @@ encode_getfh(struct xdr_stream *xdr) return 0; } -static int -encode_link(struct xdr_stream *xdr, struct nfs4_link *link) +static int encode_link(struct xdr_stream *xdr, const struct qstr *name) { uint32_t *p; - RESERVE_SPACE(8 + link->ln_namelen); + RESERVE_SPACE(8 + name->len); WRITE32(OP_LINK); - WRITE32(link->ln_namelen); - WRITEMEM(link->ln_name, link->ln_namelen); + WRITE32(name->len); + WRITEMEM(name->name, name->len); return 0; } @@ -634,8 +662,7 @@ encode_link(struct xdr_stream *xdr, stru * opcode,type,reclaim,offset,length,new_lock_owner = 32 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 */ -static int -encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_lock_opargs *opargs = arg->u.lock; @@ -669,8 +696,7 @@ encode_lock(struct xdr_stream *xdr, stru return 0; } -static int -encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_lowner *opargs = arg->u.lockt; @@ -687,8 +713,7 @@ encode_lockt(struct xdr_stream *xdr, str return 0; } -static int -encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_locku_opargs *opargs = arg->u.locku; @@ -704,22 +729,20 @@ encode_locku(struct xdr_stream *xdr, str return 0; } -static int -encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup) +static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) { - int len = lookup->lo_name->len; + int len = name->len; uint32_t *p; RESERVE_SPACE(8 + len); WRITE32(OP_LOOKUP); WRITE32(len); - WRITEMEM(lookup->lo_name->name, len); + WRITEMEM(name->name, len); return 0; } -static int -encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg) +static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg) { int status; uint32_t *p; @@ -778,8 +801,7 @@ encode_open(struct xdr_stream *xdr, stru return 0; } -static int -encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg) +static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg) { uint32_t *p; @@ -792,8 +814,7 @@ encode_open_confirm(struct xdr_stream *x } -static int -encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg) +static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg) { uint32_t *p; @@ -827,8 +848,7 @@ encode_open_reclaim(struct xdr_stream *x return 0; } -static int -encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg) +static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; @@ -844,7 +864,7 @@ encode_open_downgrade(struct xdr_stream } static int -encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh) +encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) { int len = fh->size; uint32_t *p; @@ -857,8 +877,7 @@ encode_putfh(struct xdr_stream *xdr, str return 0; } -static int -encode_putrootfh(struct xdr_stream *xdr) +static int encode_putrootfh(struct xdr_stream *xdr) { uint32_t *p; @@ -868,22 +887,37 @@ encode_putrootfh(struct xdr_stream *xdr) return 0; } -static int -encode_read(struct xdr_stream *xdr, struct nfs_readargs *args) +static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) { + extern nfs4_stateid zero_stateid; + nfs4_stateid stateid; uint32_t *p; - RESERVE_SPACE(32); + RESERVE_SPACE(16); + if (state != NULL) { + nfs4_copy_stateid(&stateid, state, lockowner); + WRITEMEM(stateid.data, sizeof(stateid.data)); + } else + WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); +} + +static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) +{ + uint32_t *p; + + RESERVE_SPACE(4); WRITE32(OP_READ); - WRITEMEM(args->stateid.data, sizeof(args->stateid.data)); + + encode_stateid(xdr, args->state, args->lockowner); + + RESERVE_SPACE(12); WRITE64(args->offset); WRITE32(args->count); return 0; } -static int -encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req) +static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; @@ -891,27 +925,26 @@ encode_readdir(struct xdr_stream *xdr, s RESERVE_SPACE(32+sizeof(nfs4_verifier)); WRITE32(OP_READDIR); - WRITE64(readdir->rd_cookie); - WRITEMEM(readdir->rd_req_verifier.data, sizeof(readdir->rd_req_verifier.data)); - WRITE32(readdir->rd_count >> 5); /* meaningless "dircount" field */ - WRITE32(readdir->rd_count); + WRITE64(readdir->cookie); + WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data)); + WRITE32(readdir->count >> 5); /* meaningless "dircount" field */ + WRITE32(readdir->count); WRITE32(2); - WRITE32(readdir->rd_bmval[0]); - WRITE32(readdir->rd_bmval[1]); + WRITE32(FATTR4_WORD0_FILEID); + WRITE32(0); /* set up reply iovec * toplevel_status + taglen + rescount + OP_PUTFH + status * + OP_READDIR + status + verifer(2) = 9 */ replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages, - readdir->rd_pgbase, readdir->rd_count); + xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, + readdir->pgbase, readdir->count); return 0; } -static int -encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct rpc_rqst *req) +static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; @@ -925,43 +958,40 @@ encode_readlink(struct xdr_stream *xdr, * + OP_READLINK + status = 7 */ replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count); + xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count); return 0; } -static int -encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove) +static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) { uint32_t *p; - RESERVE_SPACE(8 + remove->rm_namelen); + RESERVE_SPACE(8 + name->len); WRITE32(OP_REMOVE); - WRITE32(remove->rm_namelen); - WRITEMEM(remove->rm_name, remove->rm_namelen); + WRITE32(name->len); + WRITEMEM(name->name, name->len); return 0; } -static int -encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename) +static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname) { uint32_t *p; - RESERVE_SPACE(8 + rename->rn_oldnamelen); + RESERVE_SPACE(8 + oldname->len); WRITE32(OP_RENAME); - WRITE32(rename->rn_oldnamelen); - WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen); + WRITE32(oldname->len); + WRITEMEM(oldname->name, oldname->len); - RESERVE_SPACE(4 + rename->rn_newnamelen); - WRITE32(rename->rn_newnamelen); - WRITEMEM(rename->rn_newname, rename->rn_newnamelen); + RESERVE_SPACE(4 + newname->len); + WRITE32(newname->len); + WRITEMEM(newname->name, newname->len); return 0; } -static int -encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid) +static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid) { uint32_t *p; @@ -973,17 +1003,6 @@ encode_renew(struct xdr_stream *xdr, str } static int -encode_restorefh(struct xdr_stream *xdr) -{ - uint32_t *p; - - RESERVE_SPACE(4); - WRITE32(OP_RESTOREFH); - - return 0; -} - -static int encode_savefh(struct xdr_stream *xdr) { uint32_t *p; @@ -994,9 +1013,7 @@ encode_savefh(struct xdr_stream *xdr) return 0; } -static int -encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg, - struct nfs_server *server) +static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server) { int status; uint32_t *p; @@ -1011,8 +1028,7 @@ encode_setattr(struct xdr_stream *xdr, s return 0; } -static int -encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid) +static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) { uint32_t total_len; uint32_t len1, len2, len3; @@ -1039,8 +1055,7 @@ encode_setclientid(struct xdr_stream *xd return 0; } -static int -encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_state) +static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state) { uint32_t *p; @@ -1052,14 +1067,16 @@ encode_setclientid_confirm(struct xdr_st return 0; } -static int -encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args) +static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args) { uint32_t *p; - RESERVE_SPACE(36); + RESERVE_SPACE(4); WRITE32(OP_WRITE); - WRITEMEM(args->stateid.data, sizeof(args->stateid.data)); + + encode_stateid(xdr, args->state, args->lockowner); + + RESERVE_SPACE(16); WRITE64(args->offset); WRITE32(args->stable); WRITE32(args->count); @@ -1068,297 +1085,409 @@ encode_write(struct xdr_stream *xdr, str return 0; } - -/* FIXME: this sucks */ -static int -encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) -{ - struct compound_hdr hdr = { - .taglen = cp->taglen, - .tag = cp->tag, - .nops = cp->req_nops, - }; - int i, status = 0; - - encode_compound_hdr(xdr, &hdr); - - for (i = 0; i < cp->req_nops; i++) { - switch (cp->ops[i].opnum) { - case OP_ACCESS: - status = encode_access(xdr, &cp->ops[i].u.access); - break; - case OP_CREATE: - status = encode_create(xdr, &cp->ops[i].u.create, cp->server); - break; - case OP_GETATTR: - status = encode_getattr(xdr, &cp->ops[i].u.getattr); - break; - case OP_GETFH: - status = encode_getfh(xdr); - break; - case OP_LINK: - status = encode_link(xdr, &cp->ops[i].u.link); - break; - case OP_LOOKUP: - status = encode_lookup(xdr, &cp->ops[i].u.lookup); - break; - case OP_PUTFH: - status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); - break; - case OP_PUTROOTFH: - status = encode_putrootfh(xdr); - break; - case OP_READDIR: - status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); - break; - case OP_READLINK: - status = encode_readlink(xdr, &cp->ops[i].u.readlink, req); - break; - case OP_REMOVE: - status = encode_remove(xdr, &cp->ops[i].u.remove); - break; - case OP_RENAME: - status = encode_rename(xdr, &cp->ops[i].u.rename); - break; - case OP_RESTOREFH: - status = encode_restorefh(xdr); - break; - case OP_SAVEFH: - status = encode_savefh(xdr); - break; - default: - BUG(); - } - if (status) - return status; - } - - return 0; -} /* * END OF "GENERIC" ENCODE ROUTINES. */ - /* - * Encode COMPOUND argument + * Encode an ACCESS request */ -static int -nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp) +static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args) { struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; int status; - + xdr_init_encode(&xdr, &req->rq_snd_buf, p); - status = encode_compound(&xdr, cp, req); - cp->timestamp = jiffies; + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_access(&xdr, args->access); return status; } -/* - * Encode a CLOSE request - */ -static int -nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) -{ - struct xdr_stream xdr; - struct compound_hdr hdr = { - .nops = 2, - }; - int status; - - xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if(status) - goto out; - status = encode_close(&xdr, args); -out: - return status; -} /* - * Encode an OPEN request + * Encode LOOKUP request */ -static int -nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) +static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 7, + .nops = 4, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if (status) - goto out; - status = encode_savefh(&xdr); - if (status) - goto out; - status = encode_open(&xdr, args); - if (status) - goto out; - status = encode_getattr(&xdr, args->f_getattr); - if (status) + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; - status = encode_getfh(&xdr); - if (status) + if ((status = encode_lookup(&xdr, args->name)) != 0) goto out; - status = encode_restorefh(&xdr); - if (status) + if ((status = encode_getfh(&xdr)) != 0) goto out; - status = encode_getattr(&xdr, args->d_getattr); + status = encode_getfattr(&xdr, args->bitmask); out: return status; } /* - * Encode an OPEN_CONFIRM request + * Encode LOOKUP_ROOT request */ -static int -nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) +static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 3, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if(status) + if ((status = encode_putrootfh(&xdr)) != 0) goto out; - status = encode_open_confirm(&xdr, args); + if ((status = encode_getfh(&xdr)) == 0) + status = encode_getfattr(&xdr, args->bitmask); out: return status; } /* - * Encode an OPEN request + * Encode REMOVE request */ -static int -nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, - struct nfs_open_reclaimargs *args) +static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 3, + .nops = 2, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if (status) - goto out; - status = encode_open_reclaim(&xdr, args); - if (status) - goto out; - status = encode_getattr(&xdr, args->f_getattr); -out: + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_remove(&xdr, args->name); return status; } /* - * Encode an OPEN_DOWNGRADE request + * Encode RENAME request */ -static int -nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 4, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if (status) + if ((status = encode_putfh(&xdr, args->old_dir)) != 0) goto out; - status = encode_open_downgrade(&xdr, args); + if ((status = encode_savefh(&xdr)) != 0) + goto out; + if ((status = encode_putfh(&xdr, args->new_dir)) != 0) + goto out; + status = encode_rename(&xdr, args->old_name, args->new_name); out: return status; } /* - * Encode a LOCK request + * Encode LINK request */ -static int -nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 4, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if(status) + if ((status = encode_putfh(&xdr, args->fh)) != 0) goto out; - status = encode_lock(&xdr, args); + if ((status = encode_savefh(&xdr)) != 0) + goto out; + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) + goto out; + status = encode_link(&xdr, args->name); out: return status; } /* - * Encode a LOCKT request + * Encode CREATE request */ -static int -nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 4, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if(status) + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; - status = encode_lockt(&xdr, args); + if ((status = encode_create(&xdr, args)) != 0) + goto out; + if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) + goto out; + status = encode_getfh(&xdr); out: return status; } /* - * Encode a LOCKU request + * Encode GETATTR request */ -static int -nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 2, + .nops = 2, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, args->fh); - if(status) - goto out; - status = encode_locku(&xdr, args); -out: + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_getfattr(&xdr, args->bitmask); return status; } /* - * Encode a READ request + * Encode a CLOSE request */ -static int -nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args) +static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_close(&xdr, args); +out: + return status; +} + +/* + * Encode an OPEN request + */ +static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 3, + .nops = 4, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_open(&xdr, args); + if (status) + goto out; + status = encode_getfattr(&xdr, args->bitmask); + if (status) + goto out; + status = encode_getfh(&xdr); +out: + return status; +} + +/* + * Encode an OPEN_CONFIRM request + */ +static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_open_confirm(&xdr, args); +out: + return status; +} + +/* + * Encode an OPEN request + */ +static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 3, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_open_reclaim(&xdr, args); + if (status) + goto out; + status = encode_getfattr(&xdr, args->bitmask); +out: + return status; +} + +/* + * Encode an OPEN_DOWNGRADE request + */ +static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_open_downgrade(&xdr, args); +out: + return status; +} + +/* + * Encode a LOCK request + */ +static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_lock(&xdr, args); +out: + return status; +} + +/* + * Encode a LOCKT request + */ +static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_lockt(&xdr, args); +out: + return status; +} + +/* + * Encode a LOCKU request + */ +static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_locku(&xdr, args); +out: + return status; +} + +/* + * Encode a READLINK request + */ +static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_readlink(&xdr, args, req); +out: + return status; +} + +/* + * Encode a READDIR request + */ +static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_readdir(&xdr, args, req); +out: + return status; +} + +/* + * Encode a READ request + */ +static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args) +{ + struct rpc_auth *auth = req->rq_task->tk_auth; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, }; int replen, status; @@ -1370,14 +1499,12 @@ nfs4_xdr_enc_read(struct rpc_rqst *req, status = encode_read(&xdr, args); if (status) goto out; - status = encode_read_getattr(&xdr); /* set up reply iovec * toplevel status + taglen=0 + rescount + OP_PUTFH + status * + OP_READ + status + eof + datalen = 9 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + - NFS4_dec_read_sz - decode_read_getattr_maxsz) << 2; + replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->count); out: @@ -1387,8 +1514,7 @@ out: /* * Encode an SETATTR request */ -static int -nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) +static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) { struct xdr_stream xdr; @@ -1405,7 +1531,7 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *re status = encode_setattr(&xdr, args, args->server); if(status) goto out; - status = encode_getattr(&xdr, args->attr); + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -1413,12 +1539,11 @@ out: /* * Encode a WRITE request */ -static int -nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 2, }; int status; @@ -1427,13 +1552,7 @@ nfs4_xdr_enc_write(struct rpc_rqst *req, status = encode_putfh(&xdr, args->fh); if (status) goto out; - status = encode_pre_write_getattr(&xdr); - if (status) - goto out; status = encode_write(&xdr, args); - if (status) - goto out; - status = encode_post_write_getattr(&xdr); out: return status; } @@ -1441,12 +1560,11 @@ out: /* * a COMMIT request */ -static int -nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 4, + .nops = 2, }; int status; @@ -1455,13 +1573,7 @@ nfs4_xdr_enc_commit(struct rpc_rqst *req status = encode_putfh(&xdr, args->fh); if (status) goto out; - status = encode_pre_write_getattr(&xdr); - if (status) - goto out; status = encode_commit(&xdr, args); - if (status) - goto out; - status = encode_post_write_getattr(&xdr); out: return status; } @@ -1469,8 +1581,7 @@ out: /* * FSINFO request */ -static int -nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) +static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1480,17 +1591,81 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, fhandle); + status = encode_putfh(&xdr, args->fh); + if (!status) + status = encode_fsinfo(&xdr, args->bitmask); + return status; +} + +/* + * a PATHCONF request + */ +static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) +{ + extern u32 nfs4_pathconf_bitmap[2]; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); if (!status) - status = encode_fsinfo(&xdr); + status = encode_getattr_one(&xdr, + args->bitmask[0] & nfs4_pathconf_bitmap[0]); + return status; +} + +/* + * a STATFS request + */ +static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) +{ + extern u32 nfs4_statfs_bitmap[]; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status == 0) + status = encode_getattr_two(&xdr, + args->bitmask[0] & nfs4_statfs_bitmap[0], + args->bitmask[1] & nfs4_statfs_bitmap[1]); + return status; +} + +/* + * GETATTR_BITMAP request + */ +static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, fhandle); + if (status == 0) + status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| + FATTR4_WORD0_LINK_SUPPORT| + FATTR4_WORD0_SYMLINK_SUPPORT| + FATTR4_WORD0_ACLSUPPORT); return status; } /* * a RENEW request */ -static int -nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) +static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1505,9 +1680,7 @@ nfs4_xdr_enc_renew(struct rpc_rqst *req, /* * a SETCLIENTID request */ -static int -nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, - struct nfs4_setclientid *sc) +static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1522,14 +1695,13 @@ nfs4_xdr_enc_setclientid(struct rpc_rqst /* * a SETCLIENTID_CONFIRM request */ -static int -nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, - struct nfs4_client *clp) +static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { .nops = 3, }; + const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); @@ -1538,7 +1710,7 @@ nfs4_xdr_enc_setclientid_confirm(struct if (!status) status = encode_putrootfh(&xdr); if (!status) - status = encode_fsinfo(&xdr); + status = encode_fsinfo(&xdr, lease_bitmap); return status; } @@ -1552,15 +1724,6 @@ nfs4_xdr_enc_setclientid_confirm(struct * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define DECODE_TAIL \ - status = 0; \ -out: \ - return status; \ -xdr_error: \ - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ - status = -EIO; \ - goto out - #define READ32(x) (x) = ntohl(*p++) #define READ64(x) do { \ (x) = (u64)ntohl(*p++) << 32; \ @@ -1585,8 +1748,7 @@ xdr_error: \ } \ } while (0) -static int -decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) +static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -1601,30 +1763,616 @@ decode_compound_hdr(struct xdr_stream *x return 0; } -static int -decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +{ + uint32_t *p; + uint32_t opnum; + int32_t nfserr; + + READ_BUF(8); + READ32(opnum); + if (opnum != expected) { + printk(KERN_NOTICE + "nfs4_decode_op_hdr: Server returned operation" + " %d but we issued a request for %d\n", + opnum, expected); + return -EIO; + } + READ32(nfserr); + if (nfserr != NFS_OK) + return -nfs_stat_to_errno(nfserr); + return 0; +} + +static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) +{ + uint32_t bmlen, *p; + + READ_BUF(4); + READ32(bmlen); + + bitmap[0] = bitmap[1] = 0; + READ_BUF((bmlen << 2)); + if (bmlen > 0) { + READ32(bitmap[0]); + if (bmlen > 1) + READ32(bitmap[1]); + } + return 0; +} + +static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep) +{ + uint32_t *p; + + READ_BUF(4); + READ32(*attrlen); + *savep = xdr->p; + return 0; +} + +static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) +{ + if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { + decode_attr_bitmap(xdr, bitmask); + bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; + } else + bitmask[0] = bitmask[1] = 0; + dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]); + return 0; +} + +static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type) +{ + uint32_t *p; + + *type = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { + READ_BUF(4); + READ32(*type); + if (*type < NF4REG || *type > NF4NAMEDATTR) { + dprintk("%s: bad type %d\n", __FUNCTION__, *type); + return -EIO; + } + bitmap[0] &= ~FATTR4_WORD0_TYPE; + } + dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type); + return 0; +} + +static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) +{ + uint32_t *p; + + *change = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { + READ_BUF(8); + READ64(*change); + bitmap[0] &= ~FATTR4_WORD0_CHANGE; + } + dprintk("%s: change attribute=%Lu\n", __FUNCTION__, + (unsigned long long)*change); + return 0; +} + +static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) +{ + uint32_t *p; + + *size = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { + READ_BUF(8); + READ64(*size); + bitmap[0] &= ~FATTR4_WORD0_SIZE; + } + dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size); + return 0; +} + +static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; + } + dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + return 0; +} + +static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; + } + dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + return 0; +} + +static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid) +{ + uint32_t *p; + + fsid->major = 0; + fsid->minor = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { + READ_BUF(16); + READ64(fsid->major); + READ64(fsid->minor); + bitmap[0] &= ~FATTR4_WORD0_FSID; + } + dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__, + (unsigned long long)fsid->major, + (unsigned long long)fsid->minor); + return 0; +} + +static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 60; + if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; + } + dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res); + return 0; +} + +static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL; + if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; + } + dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res); + return 0; +} + +static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) +{ + uint32_t *p; + + *fileid = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { + READ_BUF(8); + READ64(*fileid); + bitmap[0] &= ~FATTR4_WORD0_FILEID; + } + dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid); + return 0; +} + +static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; + } + dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; + } + dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; + } + dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; + } + dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) +{ + uint32_t *p; + int status = 0; + + *maxlink = 1; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { + READ_BUF(4); + READ32(*maxlink); + bitmap[0] &= ~FATTR4_WORD0_MAXLINK; + } + dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink); + return status; +} + +static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) +{ + uint32_t *p; + int status = 0; + + *maxname = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { + READ_BUF(4); + READ32(*maxname); + bitmap[0] &= ~FATTR4_WORD0_MAXNAME; + } + dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname); + return status; +} + +static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { + uint64_t maxread; + READ_BUF(8); + READ64(maxread); + if (maxread > 0x7FFFFFFF) + maxread = 0x7FFFFFFF; + *res = (uint32_t)maxread; + bitmap[0] &= ~FATTR4_WORD0_MAXREAD; + } + dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res); + return status; +} + +static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { + uint64_t maxwrite; + READ_BUF(8); + READ64(maxwrite); + if (maxwrite > 0x7FFFFFFF) + maxwrite = 0x7FFFFFFF; + *res = (uint32_t)maxwrite; + bitmap[0] &= ~FATTR4_WORD0_MAXWRITE; + } + dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res); + return status; +} + +static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode) +{ + uint32_t *p; + + *mode = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { + READ_BUF(4); + READ32(*mode); + *mode &= ~S_IFMT; + bitmap[1] &= ~FATTR4_WORD1_MODE; + } + dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode); + return 0; +} + +static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) +{ + uint32_t *p; + + *nlink = 1; + if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { + READ_BUF(4); + READ32(*nlink); + bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; + } + dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink); + return 0; +} + +static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid) +{ + uint32_t len, *p; + int status = 0; + + *uid = -2; + if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { + READ_BUF(4); + READ32(len); + READ_BUF(len); + if (len < XDR_MAX_NETOBJ) { + status = nfs_map_name_to_uid(clp, (char *)p, len, uid); + if (status != 0) + dprintk("%s: nfs_map_name_to_uid failed!\n", + __FUNCTION__); + } else + printk(KERN_WARNING "%s: name too long (%u)!\n", + __FUNCTION__, len); + bitmap[1] &= ~FATTR4_WORD1_OWNER; + } + dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid); + return status; +} + +static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid) +{ + uint32_t len, *p; + int status = 0; + + *gid = -2; + if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { + READ_BUF(4); + READ32(len); + READ_BUF(len); + if (len < XDR_MAX_NETOBJ) { + status = nfs_map_group_to_gid(clp, (char *)p, len, gid); + if (status != 0) + dprintk("%s: nfs_map_group_to_gid failed!\n", + __FUNCTION__); + } else + printk(KERN_WARNING "%s: name too long (%u)!\n", + __FUNCTION__, len); + bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP; + } + dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid); + return status; +} + +static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) +{ + uint32_t major = 0, minor = 0, *p; + + *rdev = MKDEV(0,0); + if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) { + dev_t tmp; + + READ_BUF(8); + READ32(major); + READ32(minor); + tmp = MKDEV(major, minor); + if (MAJOR(tmp) == major && MINOR(tmp) == minor) + *rdev = tmp; + bitmap[1] &= ~ FATTR4_WORD1_RAWDEV; + } + dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor); + return 0; +} + +static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; + } + dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; + } + dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; + } + dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) +{ + uint32_t *p; + + *used = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { + READ_BUF(8); + READ64(*used); + bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; + } + dprintk("%s: space used=%Lu\n", __FUNCTION__, + (unsigned long long)*used); + return 0; +} + +static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) +{ + uint32_t *p; + uint64_t sec; + uint32_t nsec; + + READ_BUF(12); + READ64(sec); + READ32(nsec); + time->tv_sec = (time_t)sec; + time->tv_nsec = (long)nsec; + return 0; +} + +static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS; + } + dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA; + } + dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY; + } + dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen) { - uint32_t *p; - uint32_t opnum; - int32_t nfserr; + unsigned int attrwords = XDR_QUADLEN(attrlen); + unsigned int nwords = xdr->p - savep; - READ_BUF(8); - READ32(opnum); - if (opnum != expected) { - printk(KERN_NOTICE - "nfs4_decode_op_hdr: Server returned operation" - " %d but we issued a request for %d\n", - opnum, expected); + if (unlikely(attrwords != nwords)) { + printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n", + __FUNCTION__, + attrwords << 2, + (attrwords < nwords) ? '<' : '>', + nwords << 2); return -EIO; } - READ32(nfserr); - if (nfserr != NFS_OK) - return -nfs_stat_to_errno(nfserr); return 0; } -static int -decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) +static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { uint32_t *p; @@ -1635,8 +2383,7 @@ decode_change_info(struct xdr_stream *xd return 0; } -static int -decode_access(struct xdr_stream *xdr, struct nfs4_access *access) +static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) { uint32_t *p; uint32_t supp, acc; @@ -1648,17 +2395,12 @@ decode_access(struct xdr_stream *xdr, st READ_BUF(8); READ32(supp); READ32(acc); - if ((supp & ~access->ac_req_access) || (acc & ~supp)) { - printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n"); - return -EIO; - } - *access->ac_resp_supported = supp; - *access->ac_resp_access = acc; + access->supported = supp; + access->access = acc; return 0; } -static int -decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) +static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) { uint32_t *p; int status; @@ -1671,8 +2413,7 @@ decode_close(struct xdr_stream *xdr, str return 0; } -static int -decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) +static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) { uint32_t *p; int status; @@ -1685,8 +2426,7 @@ decode_commit(struct xdr_stream *xdr, st return 0; } -static int -decode_create(struct xdr_stream *xdr, struct nfs4_create *create) +static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { uint32_t *p; uint32_t bmlen; @@ -1695,7 +2435,7 @@ decode_create(struct xdr_stream *xdr, st status = decode_op_hdr(xdr, OP_CREATE); if (status) return status; - if ((status = decode_change_info(xdr, create->cr_cinfo))) + if ((status = decode_change_info(xdr, cinfo))) return status; READ_BUF(4); READ32(bmlen); @@ -1703,443 +2443,192 @@ decode_create(struct xdr_stream *xdr, st return 0; } -extern uint32_t nfs4_fattr_bitmap[2]; -extern uint32_t nfs4_fsstat_bitmap[2]; -extern uint32_t nfs4_pathconf_bitmap[2]; - -static int -decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, - struct nfs_server *server) +static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) { - struct nfs_fattr *nfp = getattr->gt_attrs; - struct nfs_fsstat *fsstat = getattr->gt_fsstat; - struct nfs_pathconf *pathconf = getattr->gt_pathconf; - uint32_t attrlen, dummy32, bmlen, - bmval0 = 0, - bmval1 = 0, - len = 0; - uint32_t *p; - unsigned int type; - int fmode = 0; + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; int status; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0) + goto xdr_error; + if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0) + goto xdr_error; + if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0) + goto xdr_error; + if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0) + goto xdr_error; + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; +} - status = decode_op_hdr(xdr, OP_GETATTR); - if (status) - return status; - - READ_BUF(4); - READ32(bmlen); - if (bmlen > 2) - goto xdr_error; +static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; + int status; - READ_BUF((bmlen << 2) + 4); - if (bmlen > 0) - READ32(bmval0); - if (bmlen > 1) - READ32(bmval1); - READ32(attrlen); - - if ((bmval0 & ~getattr->gt_bmval[0]) || - (bmval1 & ~getattr->gt_bmval[1])) { - dprintk("read_attrs: server returned bad attributes!\n"); + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) goto xdr_error; - } - if (nfp) { - nfp->bitmap[0] = bmval0; - nfp->bitmap[1] = bmval1; - } - /* - * In case the server doesn't return some attributes, - * we initialize them here to some nominal values.. - */ - if (nfp) { - nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; - nfp->nlink = 1; - nfp->timestamp = jiffies; - } - if (bmval0 & FATTR4_WORD0_TYPE) { - READ_BUF(4); - len += 4; - READ32(type); - if (type < NF4REG || type > NF4NAMEDATTR) { - dprintk("read_attrs: bad type %d\n", type); - goto xdr_error; - } - nfp->type = nfs_type2fmt[type].nfs2type; - fmode = nfs_type2fmt[type].mode; - dprintk("read_attrs: type=%d\n", (uint32_t)nfp->type); - } - if (bmval0 & FATTR4_WORD0_CHANGE) { - READ_BUF(8); - len += 8; - READ64(nfp->change_attr); - dprintk("read_attrs: changeid=%Ld\n", (long long)nfp->change_attr); - } - if (bmval0 & FATTR4_WORD0_SIZE) { - READ_BUF(8); - len += 8; - READ64(nfp->size); - dprintk("read_attrs: size=%Ld\n", (long long)nfp->size); - } - if (bmval0 & FATTR4_WORD0_FSID) { - READ_BUF(16); - len += 16; - READ64(nfp->fsid_u.nfs4.major); - READ64(nfp->fsid_u.nfs4.minor); - dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n", - (long long)nfp->fsid_u.nfs4.major, - (long long)nfp->fsid_u.nfs4.minor); - } - if (bmval0 & FATTR4_WORD0_FILEID) { - READ_BUF(8); - len += 8; - READ64(nfp->fileid); - dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid); - } - if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { - READ_BUF(8); - len += 8; - READ64(fsstat->afiles); - dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles); - } - if (bmval0 & FATTR4_WORD0_FILES_FREE) { - READ_BUF(8); - len += 8; - READ64(fsstat->ffiles); - dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles); - } - if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { - READ_BUF(8); - len += 8; - READ64(fsstat->tfiles); - dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles); - } - if (bmval0 & FATTR4_WORD0_MAXLINK) { - READ_BUF(4); - len += 4; - READ32(pathconf->max_link); - dprintk("read_attrs: maxlink=%d\n", pathconf->max_link); - } - if (bmval0 & FATTR4_WORD0_MAXNAME) { - READ_BUF(4); - len += 4; - READ32(pathconf->max_namelen); - dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen); - } - - if (bmval1 & FATTR4_WORD1_MODE) { - READ_BUF(4); - len += 4; - READ32(dummy32); - nfp->mode = (dummy32 & ~S_IFMT) | fmode; - dprintk("read_attrs: mode=0%o\n", nfp->mode); - } - if (bmval1 & FATTR4_WORD1_NUMLINKS) { - READ_BUF(4); - len += 4; - READ32(nfp->nlink); - dprintk("read_attrs: nlinks=0%o\n", nfp->nlink); - } - if (bmval1 & FATTR4_WORD1_OWNER) { - READ_BUF(4); - len += 4; - READ32(dummy32); /* name length */ - if (dummy32 > XDR_MAX_NETOBJ) { - dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32, - &nfp->uid)) < 0) { - dprintk("read_attrs: name-to-uid mapping failed!\n"); - nfp->uid = -2; - } - dprintk("read_attrs: uid=%d\n", (int)nfp->uid); - } - if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - READ_BUF(4); - len += 4; - READ32(dummy32); - if (dummy32 > XDR_MAX_NETOBJ) { - dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32, - &nfp->gid)) < 0) { - dprintk("read_attrs: group-to-gid mapping failed!\n"); - nfp->gid = -2; - } - dprintk("read_attrs: gid=%d\n", (int)nfp->gid); - } - if (bmval1 & FATTR4_WORD1_RAWDEV) { - uint32_t major, minor; + if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0) + goto xdr_error; + if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0) + goto xdr_error; + if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) + goto xdr_error; + if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) + goto xdr_error; + if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) + goto xdr_error; + if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0) + goto xdr_error; - READ_BUF(8); - len += 8; - READ32(major); - READ32(minor); - nfp->rdev = MKDEV(major, minor); - if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor) - nfp->rdev = 0; - dprintk("read_attrs: rdev=%u:%u\n", major, minor); - } - if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { - READ_BUF(8); - len += 8; - READ64(fsstat->abytes); - dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes); - } - if (bmval1 & FATTR4_WORD1_SPACE_FREE) { - READ_BUF(8); - len += 8; - READ64(fsstat->fbytes); - dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes); - } - if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { - READ_BUF(8); - len += 8; - READ64(fsstat->tbytes); - dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes); - } - if (bmval1 & FATTR4_WORD1_SPACE_USED) { - READ_BUF(8); - len += 8; - READ64(nfp->du.nfs3.used); - dprintk("read_attrs: sused=0x%Lx\n", (long long) nfp->du.nfs3.used); - } - if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { - READ_BUF(12); - len += 12; - READTIME(nfp->atime); - dprintk("read_attrs: atime=%ld\n", (long)nfp->atime.tv_sec); - } - if (bmval1 & FATTR4_WORD1_TIME_METADATA) { - READ_BUF(12); - len += 12; - READTIME(nfp->ctime); - dprintk("read_attrs: ctime=%ld\n", (long)nfp->ctime.tv_sec); - } - if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { - READ_BUF(12); - len += 12; - READTIME(nfp->mtime); - dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec); - } - if (len != attrlen) - goto xdr_error; - - DECODE_TAIL; + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; } -static int -decode_change_attr(struct xdr_stream *xdr, uint64_t *change_attr) +static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) { - uint32_t *p; - uint32_t attrlen, bmlen, bmval = 0; + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; int status; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; - status = decode_op_hdr(xdr, OP_GETATTR); - if (status) - return status; - READ_BUF(4); - READ32(bmlen); - if (bmlen < 1) - return -EIO; - READ_BUF(bmlen << 2); - READ32(bmval); - if (bmval != FATTR4_WORD0_CHANGE) { - printk(KERN_NOTICE "decode_change_attr: server returned bad attribute bitmap 0x%x\n", - (unsigned int)bmval); - return -EIO; - } - READ_BUF(4); - READ32(attrlen); - READ_BUF(attrlen); - if (attrlen < 8) { - printk(KERN_NOTICE "decode_change_attr: server returned bad attribute length