From: Trond Myklebust Date: Mon, 10 Jan 2011 19:48:02 +0000 (-0500) Subject: Merge branch 'bugfixes' into nfs-for-2.6.38 X-Git-Tag: v2.6.38-rc1~407^2~1 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=68c404b18f6fba404b2753622d0459c68ee128ae;p=~shefty%2Frdma-dev.git Merge branch 'bugfixes' into nfs-for-2.6.38 Conflicts: fs/nfs/nfs2xdr.c fs/nfs/nfs3xdr.c fs/nfs/nfs4xdr.c --- 68c404b18f6fba404b2753622d0459c68ee128ae diff --cc fs/nfs/dir.c index 65d5cb4f70b,0108cf4f340..16ec096f6b2 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@@ -33,9 -33,7 +33,8 @@@ #include #include #include - #include #include +#include #include "delegation.h" #include "iostat.h" diff --cc fs/nfs/nfs2xdr.c index 51f1cfa04d2,b382a1b5e7e..792cb13a430 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@@ -943,12 -487,7 +943,7 @@@ int nfs2_decode_dirent(struct xdr_strea entry->d_type = DT_UNKNOWN; - /* Peek at the next entry to see if we're at EOD */ - p = xdr_inline_peek(xdr, 4 + 4); - entry->eof = 0; - if (p != NULL) - entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero); - return p; + return 0; out_overflow: print_overflow_msg(__func__, xdr); diff --cc fs/nfs/nfs3xdr.c index df30a26cc4f,ba91236c6ee..01c5e8b1941 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@@ -1771,238 -1048,23 +1771,233 @@@ out_default } /* - * Decode PATHCONF reply + * 3.3.12 REMOVE3res + * + * struct REMOVE3resok { + * wcc_data dir_wcc; + * }; + * + * struct REMOVE3resfail { + * wcc_data dir_wcc; + * }; + * + * union REMOVE3res switch (nfsstat3 status) { + * case NFS3_OK: + * REMOVE3resok resok; + * default: + * REMOVE3resfail resfail; + * }; */ -static int -nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) +static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, + struct xdr_stream *xdr, + struct nfs_removeres *result) { - int status; + enum nfs_stat status; + int error; + + error = decode_nfsstat3(xdr, &status); + if (unlikely(error)) + goto out; + error = decode_wcc_data(xdr, result->dir_attr); + if (unlikely(error)) + goto out; + if (status != NFS3_OK) + goto out_status; +out: + return error; +out_status: + return nfs_stat_to_errno(status); +} - status = ntohl(*p++); +/* + * 3.3.14 RENAME3res + * + * struct RENAME3resok { + * wcc_data fromdir_wcc; + * wcc_data todir_wcc; + * }; + * + * struct RENAME3resfail { + * wcc_data fromdir_wcc; + * wcc_data todir_wcc; + * }; + * + * union RENAME3res switch (nfsstat3 status) { + * case NFS3_OK: + * RENAME3resok resok; + * default: + * RENAME3resfail resfail; + * }; + */ +static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, + struct xdr_stream *xdr, + struct nfs_renameres *result) +{ + enum nfs_stat status; + int error; + + error = decode_nfsstat3(xdr, &status); + if (unlikely(error)) + goto out; + error = decode_wcc_data(xdr, result->old_fattr); + if (unlikely(error)) + goto out; + error = decode_wcc_data(xdr, result->new_fattr); + if (unlikely(error)) + goto out; + if (status != NFS3_OK) + goto out_status; +out: + return error; +out_status: + return nfs_stat_to_errno(status); +} - p = xdr_decode_post_op_attr(p, res->fattr); - if (status != 0) - return nfs_stat_to_errno(status); - res->max_link = ntohl(*p++); - res->max_namelen = ntohl(*p++); +/* + * 3.3.15 LINK3res + * + * struct LINK3resok { + * post_op_attr file_attributes; + * wcc_data linkdir_wcc; + * }; + * + * struct LINK3resfail { + * post_op_attr file_attributes; + * wcc_data linkdir_wcc; + * }; + * + * union LINK3res switch (nfsstat3 status) { + * case NFS3_OK: + * LINK3resok resok; + * default: + * LINK3resfail resfail; + * }; + */ +static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr, + struct nfs3_linkres *result) +{ + enum nfs_stat status; + int error; + + error = decode_nfsstat3(xdr, &status); + if (unlikely(error)) + goto out; + error = decode_post_op_attr(xdr, result->fattr); + if (unlikely(error)) + goto out; + error = decode_wcc_data(xdr, result->dir_attr); + if (unlikely(error)) + goto out; + if (status != NFS3_OK) + goto out_status; +out: + return error; +out_status: + return nfs_stat_to_errno(status); +} + +/** + * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in + * the local page cache + * @xdr: XDR stream where entry resides + * @entry: buffer to fill in with entry data + * @plus: boolean indicating whether this should be a readdirplus entry + * + * Returns zero if successful, otherwise a negative errno value is + * returned. + * + * This function is not invoked during READDIR reply decoding, but + * rather whenever an application invokes the getdents(2) system call + * on a directory already in our cache. + * + * 3.3.16 entry3 + * + * struct entry3 { + * fileid3 fileid; + * filename3 name; + * cookie3 cookie; + * fhandle3 filehandle; + * post_op_attr3 attributes; + * entry3 *nextentry; + * }; + * + * 3.3.17 entryplus3 + * struct entryplus3 { + * fileid3 fileid; + * filename3 name; + * cookie3 cookie; + * post_op_attr name_attributes; + * post_op_fh3 name_handle; + * entryplus3 *nextentry; + * }; + */ +int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, + int plus) +{ + struct nfs_entry old = *entry; + __be32 *p; + int error; + + p = xdr_inline_decode(xdr, 4); + if (unlikely(p == NULL)) + goto out_overflow; + if (*p == xdr_zero) { + p = xdr_inline_decode(xdr, 4); + if (unlikely(p == NULL)) + goto out_overflow; + if (*p == xdr_zero) + return -EAGAIN; + entry->eof = 1; + return -EBADCOOKIE; + } + + error = decode_fileid3(xdr, &entry->ino); + if (unlikely(error)) + return error; + + error = decode_inline_filename3(xdr, &entry->name, &entry->len); + if (unlikely(error)) + return error; + + entry->prev_cookie = entry->cookie; + error = decode_cookie3(xdr, &entry->cookie); + if (unlikely(error)) + return error; + + entry->d_type = DT_UNKNOWN; + + if (plus) { + entry->fattr->valid = 0; + error = decode_post_op_attr(xdr, entry->fattr); + if (unlikely(error)) + return error; + if (entry->fattr->valid & NFS_ATTR_FATTR_V3) + entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); + + /* In fact, a post_op_fh3: */ + p = xdr_inline_decode(xdr, 4); + if (unlikely(p == NULL)) + goto out_overflow; + if (*p != xdr_zero) { + error = decode_nfs_fh3(xdr, entry->fh); + if (unlikely(error)) { + if (error == -E2BIG) + goto out_truncated; + return error; + } + } else + zero_nfs_fh3(entry->fh); + } - /* Peek at the next entry to see if we're at EOD */ - p = xdr_inline_peek(xdr, 4 + 4); - entry->eof = 0; - if (p != NULL) - entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero); - /* ignore remaining fields */ return 0; + +out_overflow: + print_overflow_msg(__func__, xdr); + return -EAGAIN; +out_truncated: + dprintk("NFS: directory entry contains invalid file handle\n"); + *entry = old; + return -EAGAIN; } /* diff --cc fs/nfs/nfs4xdr.c index 8e496887ec6,0662a9821df..2ab8e5cb8f5 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@@ -6135,13 -6215,7 +6135,7 @@@ int nfs4_decode_dirent(struct xdr_strea if (verify_attr_len(xdr, p, len) < 0) goto out_overflow; - p = xdr_inline_peek(xdr, 8); - if (p != NULL) - entry->eof = !p[0] && p[1]; - else - entry->eof = 0; - - return p; + return 0; out_overflow: print_overflow_msg(__func__, xdr); diff --cc include/linux/sunrpc/xdr.h index 9a21e8102c4,7783c687c77..fc84b7a19ca --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@@ -201,14 -201,10 +201,16 @@@ struct xdr_stream __be32 *end; /* end of available buffer space */ struct kvec *iov; /* pointer to the current kvec */ + struct kvec scratch; /* Scratch buffer */ + struct page **page_ptr; /* pointer to the current page */ }; +/* + * These are the xdr_stream style generic XDR encode and decode functions. + */ +typedef void (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj); +typedef int (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj); + extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,