aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-12-04 17:39:23 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-13 16:48:01 -0500
commitafce3609db524d801a8fc4096810fa6844062f65 (patch)
treebaad405fa2d236e3a348d624e693776adf65b1cf /fs
parent4371c272186d393fbb401a743867a209f3e218ae (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.c47
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
3005static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) 3005static 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;
3024out_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;
3025out_overflow: 3030out_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
3036static 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