diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-12-04 17:39:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-13 16:48:01 -0500 |
commit | afce3609db524d801a8fc4096810fa6844062f65 (patch) | |
tree | baad405fa2d236e3a348d624e693776adf65b1cf /fs | |
parent | 4371c272186d393fbb401a743867a209f3e218ae (diff) |
NFSv4: OPEN must handle the NFS4ERR_IO return code correctly
commit c7848f69ec4a8c03732cde5c949bd2aa711a9f4b upstream.
decode_op_hdr() cannot distinguish between an XDR decoding error and
the perfectly valid errorcode NFS4ERR_IO. This is normally not a
problem, but for the particular case of OPEN, we need to be able
to increment the NFSv4 open sequence id when the server returns
a valid response.
Reported-by: J Bruce Fields <bfields@fieldses.org>
Link: http://lkml.kernel.org/r/20131204210356.GA19452@fieldses.org
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4be8d135ed61..988efb4caac0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -3002,7 +3002,8 @@ out_overflow: | |||
3002 | return -EIO; | 3002 | return -EIO; |
3003 | } | 3003 | } |
3004 | 3004 | ||
3005 | static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | 3005 | static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, |
3006 | int *nfs_retval) | ||
3006 | { | 3007 | { |
3007 | __be32 *p; | 3008 | __be32 *p; |
3008 | uint32_t opnum; | 3009 | uint32_t opnum; |
@@ -3012,19 +3013,32 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
3012 | if (unlikely(!p)) | 3013 | if (unlikely(!p)) |
3013 | goto out_overflow; | 3014 | goto out_overflow; |
3014 | opnum = be32_to_cpup(p++); | 3015 | opnum = be32_to_cpup(p++); |
3015 | if (opnum != expected) { | 3016 | if (unlikely(opnum != expected)) |
3016 | dprintk("nfs: Server returned operation" | 3017 | goto out_bad_operation; |
3017 | " %d but we issued a request for %d\n", | ||
3018 | opnum, expected); | ||
3019 | return -EIO; | ||
3020 | } | ||
3021 | nfserr = be32_to_cpup(p); | 3018 | nfserr = be32_to_cpup(p); |
3022 | if (nfserr != NFS_OK) | 3019 | if (nfserr == NFS_OK) |
3023 | return nfs4_stat_to_errno(nfserr); | 3020 | *nfs_retval = 0; |
3024 | return 0; | 3021 | else |
3022 | *nfs_retval = nfs4_stat_to_errno(nfserr); | ||
3023 | return true; | ||
3024 | out_bad_operation: | ||
3025 | dprintk("nfs: Server returned operation" | ||
3026 | " %d but we issued a request for %d\n", | ||
3027 | opnum, expected); | ||
3028 | *nfs_retval = -EREMOTEIO; | ||
3029 | return false; | ||
3025 | out_overflow: | 3030 | out_overflow: |
3026 | print_overflow_msg(__func__, xdr); | 3031 | print_overflow_msg(__func__, xdr); |
3027 | return -EIO; | 3032 | *nfs_retval = -EIO; |
3033 | return false; | ||
3034 | } | ||
3035 | |||
3036 | static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | ||
3037 | { | ||
3038 | int retval; | ||
3039 | |||
3040 | __decode_op_hdr(xdr, expected, &retval); | ||
3041 | return retval; | ||
3028 | } | 3042 | } |
3029 | 3043 | ||
3030 | /* Dummy routine */ | 3044 | /* Dummy routine */ |
@@ -4842,11 +4856,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
4842 | uint32_t savewords, bmlen, i; | 4856 | uint32_t savewords, bmlen, i; |
4843 | int status; | 4857 | int status; |
4844 | 4858 | ||
4845 | status = decode_op_hdr(xdr, OP_OPEN); | 4859 | if (!__decode_op_hdr(xdr, OP_OPEN, &status)) |
4846 | if (status != -EIO) | 4860 | return status; |
4847 | nfs_increment_open_seqid(status, res->seqid); | 4861 | nfs_increment_open_seqid(status, res->seqid); |
4848 | if (!status) | 4862 | if (status) |
4849 | status = decode_stateid(xdr, &res->stateid); | 4863 | return status; |
4864 | status = decode_stateid(xdr, &res->stateid); | ||
4850 | if (unlikely(status)) | 4865 | if (unlikely(status)) |
4851 | return status; | 4866 | return status; |
4852 | 4867 | ||