fs/nfs/nfs4proc.c | 130 ++++++++------------------------ fs/nfs/nfs4xdr.c | 192 +++++++++++++++--------------------------------- include/linux/nfs4.h | 2 include/linux/nfs_xdr.h | 97 ++---------------------- 4 files changed, 107 insertions(+), 314 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.5-26-decompoundify_readlink/fs/nfs/nfs4proc.c linux-2.6.5-27-decompoundify_readdir/fs/nfs/nfs4proc.c --- linux-2.6.5-26-decompoundify_readlink/fs/nfs/nfs4proc.c 2004-03-24 00:49:04.000000000 -0500 +++ linux-2.6.5-27-decompoundify_readdir/fs/nfs/nfs4proc.c 2004-03-24 00:49:12.000000000 -0500 @@ -51,9 +51,6 @@ #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_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); @@ -72,15 +69,6 @@ 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; -} - /* * This is our standard bitmap for GETATTR requests. */ @@ -116,37 +104,21 @@ u32 nfs4_pathconf_bitmap[2] = { 0 }; -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_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; /* @@ -156,7 +128,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 */ @@ -168,7 +140,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 */ @@ -180,10 +152,10 @@ 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); } @@ -198,47 +170,6 @@ renew_lease(struct nfs_server *server, u } static inline void -process_lease(struct nfs4_compound *cp) -{ - /* - * 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; -} - -static inline void process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) { BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0); @@ -1209,24 +1140,31 @@ static int nfs4_proc_mkdir(struct inode 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); } diff -u --recursive --new-file --show-c-function linux-2.6.5-26-decompoundify_readlink/fs/nfs/nfs4xdr.c linux-2.6.5-27-decompoundify_readdir/fs/nfs/nfs4xdr.c --- linux-2.6.5-26-decompoundify_readlink/fs/nfs/nfs4xdr.c 2004-03-24 00:49:04.000000000 -0500 +++ linux-2.6.5-27-decompoundify_readdir/fs/nfs/nfs4xdr.c 2004-03-24 00:49:12.000000000 -0500 @@ -138,6 +138,12 @@ static int nfs_stat_to_errno(int); #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 + \ op_encode_hdr_maxsz + 8) @@ -941,8 +947,7 @@ encode_read(struct xdr_stream *xdr, stru 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; @@ -950,21 +955,21 @@ 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; } @@ -1127,57 +1132,11 @@ 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_PUTFH: - status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); - break; - case OP_READDIR: - status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); - break; - default: - BUG(); - } - if (status) - return status; - } - - return 0; -} /* * END OF "GENERIC" ENCODE ROUTINES. */ /* - * Encode COMPOUND argument - */ -static int -nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp) -{ - struct xdr_stream xdr; - int status; - - xdr_init_encode(&xdr, &req->rq_snd_buf, p); - status = encode_compound(&xdr, cp, req); - cp->timestamp = jiffies; - return status; -} - -/* * Encode an ACCESS request */ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args) @@ -1565,6 +1524,27 @@ out: } /* + * 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 @@ -2960,8 +2940,7 @@ decode_read(struct xdr_stream *xdr, stru return 0; } -static int -decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir *readdir) +static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct page *page = *rcvbuf->pages; @@ -2975,7 +2954,7 @@ decode_readdir(struct xdr_stream *xdr, s if (status) return status; READ_BUF(8); - COPYMEM(readdir->rd_resp_verifier.data, 8); + COPYMEM(readdir->verifier.data, 8); hdrlen = (char *) p - (char *) iov->iov_base; recvd = req->rq_received - hdrlen; @@ -2983,9 +2962,9 @@ decode_readdir(struct xdr_stream *xdr, s pglen = recvd; xdr_read_pages(xdr, pglen); - BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE); + BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); - end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase); + end = (uint32_t *) ((char *)p + pglen + readdir->pgbase); entry = p; for (nr = 0; *p++; nr++) { if (p + 3 > end) @@ -3210,53 +3189,6 @@ decode_write(struct xdr_stream *xdr, str return 0; } -/* FIXME: this sucks */ -static int -decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) -{ - struct compound_hdr hdr; - struct nfs4_op *op; - int status; - - status = decode_compound_hdr(xdr, &hdr); - if (status) - goto out; - - cp->toplevel_status = hdr.status; - - /* - * We need this if our zero-copy I/O is going to work. Rumor has - * it that the spec will soon mandate it... - */ - if (hdr.taglen != cp->taglen) - dprintk("nfs4: non-conforming server returns tag length mismatch!\n"); - - cp->resp_nops = hdr.nops; - if (hdr.nops > cp->req_nops) { - dprintk("nfs4: resp_nops > req_nops!\n"); - goto xdr_error; - } - - op = &cp->ops[0]; - for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) { - switch (op->opnum) { - case OP_PUTFH: - status = decode_putfh(xdr); - break; - case OP_READDIR: - status = decode_readdir(xdr, req, &op->u.readdir); - break; - default: - BUG(); - return -EIO; - } - if (status) - break; - } - - DECODE_TAIL; -} - /* * Decode OPEN_DOWNGRADE response */ @@ -3284,27 +3216,6 @@ out: */ /* - * Decode COMPOUND response - */ -static int -nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp) -{ - struct xdr_stream xdr; - int status; - - xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); - if ((status = decode_compound(&xdr, cp, rqstp))) - goto out; - - status = 0; - if (cp->toplevel_status) - status = -nfs_stat_to_errno(cp->toplevel_status); - -out: - return status; -} - -/* * Decode ACCESS response */ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res) @@ -3696,6 +3607,27 @@ out: } /* + * Decode READDIR response + */ +static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_readdir(&xdr, rqstp, res); +out: + return status; +} + +/* * Decode Read response */ static int @@ -3999,7 +3931,6 @@ nfs_stat_to_errno(int stat) } struct rpc_procinfo nfs4_procedures[] = { - PROC(COMPOUND, enc_compound, dec_compound), PROC(READ, enc_read, dec_read), PROC(WRITE, enc_write, dec_write), PROC(COMMIT, enc_commit, dec_commit), @@ -4027,6 +3958,7 @@ struct rpc_procinfo nfs4_procedures[] = PROC(PATHCONF, enc_pathconf, dec_pathconf), PROC(STATFS, enc_statfs, dec_statfs), PROC(READLINK, enc_readlink, dec_readlink), + PROC(READDIR, enc_readdir, dec_readdir), }; struct rpc_version nfs_version4 = { diff -u --recursive --new-file --show-c-function linux-2.6.5-26-decompoundify_readlink/include/linux/nfs4.h linux-2.6.5-27-decompoundify_readdir/include/linux/nfs4.h --- linux-2.6.5-26-decompoundify_readlink/include/linux/nfs4.h 2004-03-24 00:49:04.000000000 -0500 +++ linux-2.6.5-27-decompoundify_readdir/include/linux/nfs4.h 2004-03-24 00:49:12.000000000 -0500 @@ -286,7 +286,6 @@ enum lock_type4 { enum { NFSPROC4_CLNT_NULL = 0, /* Unused */ - NFSPROC4_CLNT_COMPOUND, /* Soon to be unused */ NFSPROC4_CLNT_READ, NFSPROC4_CLNT_WRITE, NFSPROC4_CLNT_COMMIT, @@ -314,6 +313,7 @@ enum { NFSPROC4_CLNT_PATHCONF, NFSPROC4_CLNT_STATFS, NFSPROC4_CLNT_READLINK, + NFSPROC4_CLNT_READDIR, }; #endif diff -u --recursive --new-file --show-c-function linux-2.6.5-26-decompoundify_readlink/include/linux/nfs_xdr.h linux-2.6.5-27-decompoundify_readdir/include/linux/nfs_xdr.h --- linux-2.6.5-26-decompoundify_readlink/include/linux/nfs_xdr.h 2004-03-24 00:49:04.000000000 -0500 +++ linux-2.6.5-27-decompoundify_readdir/include/linux/nfs_xdr.h 2004-03-24 00:49:12.000000000 -0500 @@ -496,11 +496,6 @@ struct nfs4_accessres { u32 access; }; -struct nfs4_close { - char * cl_stateid; /* request */ - u32 cl_seqid; /* request */ -}; - struct nfs4_create_arg { u32 ftype; union { @@ -524,12 +519,6 @@ struct nfs4_create_res { struct nfs4_change_info dir_cinfo; }; - -#define cr_textlen u.symlink.textlen -#define cr_text u.symlink.text -#define cr_specdata1 u.device.specdata1 -#define cr_specdata2 u.device.specdata2 - struct nfs4_getattr { u32 * gt_bmval; /* request */ struct nfs_fattr * gt_attrs; /* response */ @@ -568,44 +557,23 @@ struct nfs4_lookup_root_arg { const u32 * bitmask; }; -struct nfs4_open { - struct nfs4_client * op_client_state; /* request */ - u32 op_share_access; /* request */ - u32 op_opentype; /* request */ - u32 op_createmode; /* request */ - union { /* request */ - struct iattr * attrs; /* UNCHECKED, GUARDED */ - nfs4_verifier verifier; /* EXCLUSIVE */ - } u; - struct qstr * op_name; /* request */ - char * op_stateid; /* response */ - struct nfs4_change_info * op_cinfo; /* response */ - u32 * op_rflags; /* response */ -}; -#define op_attrs u.attrs -#define op_verifier u.verifier - -struct nfs4_open_confirm { - char * oc_stateid; /* request */ -}; - struct nfs4_pathconf_arg { const struct nfs_fh * fh; const u32 * bitmask; }; -struct nfs4_putfh { - struct nfs_fh * pf_fhandle; /* request */ +struct nfs4_readdir_arg { + const struct nfs_fh * fh; + u64 cookie; + nfs4_verifier verifier; + u32 count; + struct page ** pages; /* zero-copy data */ + unsigned int pgbase; /* zero-copy data */ }; -struct nfs4_readdir { - u64 rd_cookie; /* request */ - nfs4_verifier rd_req_verifier; /* request */ - u32 rd_count; /* request */ - u32 rd_bmval[2]; /* request */ - nfs4_verifier rd_resp_verifier; /* response */ - struct page ** rd_pages; /* zero-copy data */ - unsigned int rd_pgbase; /* zero-copy data */ +struct nfs4_readdir_res { + nfs4_verifier verifier; + unsigned int pgbase; }; struct nfs4_readlink { @@ -631,11 +599,6 @@ struct nfs4_rename_res { struct nfs4_change_info new_cinfo; }; -struct nfs4_setattr { - char * st_stateid; /* request */ - struct iattr * st_iap; /* request */ -}; - struct nfs4_setclientid { nfs4_verifier sc_verifier; /* request */ char * sc_name; /* request */ @@ -651,46 +614,6 @@ struct nfs4_statfs_arg { const u32 * bitmask; }; -struct nfs4_op { - u32 opnum; - union { - struct nfs4_close close; - struct nfs4_open open; - struct nfs4_open_confirm open_confirm; - struct nfs4_putfh putfh; - struct nfs4_readdir readdir; - struct nfs4_readlink readlink; - struct nfs4_client * renew; - struct nfs4_setattr setattr; - } u; -}; - -struct nfs4_compound { - unsigned int flags; /* defined below */ - struct nfs_server * server; - - /* RENEW information */ - int renew_index; - unsigned long timestamp; - - /* scratch variables for XDR encode/decode */ - int nops; - u32 * p; - u32 * end; - - /* the individual COMPOUND operations */ - struct nfs4_op *ops; - - /* request */ - int req_nops; - u32 taglen; - char * tag; - - /* response */ - int resp_nops; - int toplevel_status; -}; - #endif /* CONFIG_NFS_V4 */ struct nfs_page;