]>
Commit | Line | Data |
---|---|---|
53d66ca4 GKH |
1 | From c7848f69ec4a8c03732cde5c949bd2aa711a9f4b Mon Sep 17 00:00:00 2001 |
2 | From: Trond Myklebust <Trond.Myklebust@netapp.com> | |
3 | Date: Wed, 4 Dec 2013 17:39:23 -0500 | |
4 | Subject: NFSv4: OPEN must handle the NFS4ERR_IO return code correctly | |
5 | ||
6 | From: Trond Myklebust <Trond.Myklebust@netapp.com> | |
7 | ||
8 | commit c7848f69ec4a8c03732cde5c949bd2aa711a9f4b upstream. | |
9 | ||
10 | decode_op_hdr() cannot distinguish between an XDR decoding error and | |
11 | the perfectly valid errorcode NFS4ERR_IO. This is normally not a | |
12 | problem, but for the particular case of OPEN, we need to be able | |
13 | to increment the NFSv4 open sequence id when the server returns | |
14 | a valid response. | |
15 | ||
16 | Reported-by: J Bruce Fields <bfields@fieldses.org> | |
17 | Link: http://lkml.kernel.org/r/20131204210356.GA19452@fieldses.org | |
18 | Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
20 | ||
21 | --- | |
22 | fs/nfs/nfs4xdr.c | 47 +++++++++++++++++++++++++++++++---------------- | |
23 | 1 file changed, 31 insertions(+), 16 deletions(-) | |
24 | ||
25 | --- a/fs/nfs/nfs4xdr.c | |
26 | +++ b/fs/nfs/nfs4xdr.c | |
27 | @@ -3002,7 +3002,8 @@ out_overflow: | |
28 | return -EIO; | |
29 | } | |
30 | ||
31 | -static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |
32 | +static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, | |
33 | + int *nfs_retval) | |
34 | { | |
35 | __be32 *p; | |
36 | uint32_t opnum; | |
37 | @@ -3012,19 +3013,32 @@ static int decode_op_hdr(struct xdr_stre | |
38 | if (unlikely(!p)) | |
39 | goto out_overflow; | |
40 | opnum = be32_to_cpup(p++); | |
41 | - if (opnum != expected) { | |
42 | - dprintk("nfs: Server returned operation" | |
43 | - " %d but we issued a request for %d\n", | |
44 | - opnum, expected); | |
45 | - return -EIO; | |
46 | - } | |
47 | + if (unlikely(opnum != expected)) | |
48 | + goto out_bad_operation; | |
49 | nfserr = be32_to_cpup(p); | |
50 | - if (nfserr != NFS_OK) | |
51 | - return nfs4_stat_to_errno(nfserr); | |
52 | - return 0; | |
53 | + if (nfserr == NFS_OK) | |
54 | + *nfs_retval = 0; | |
55 | + else | |
56 | + *nfs_retval = nfs4_stat_to_errno(nfserr); | |
57 | + return true; | |
58 | +out_bad_operation: | |
59 | + dprintk("nfs: Server returned operation" | |
60 | + " %d but we issued a request for %d\n", | |
61 | + opnum, expected); | |
62 | + *nfs_retval = -EREMOTEIO; | |
63 | + return false; | |
64 | out_overflow: | |
65 | print_overflow_msg(__func__, xdr); | |
66 | - return -EIO; | |
67 | + *nfs_retval = -EIO; | |
68 | + return false; | |
69 | +} | |
70 | + | |
71 | +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |
72 | +{ | |
73 | + int retval; | |
74 | + | |
75 | + __decode_op_hdr(xdr, expected, &retval); | |
76 | + return retval; | |
77 | } | |
78 | ||
79 | /* Dummy routine */ | |
80 | @@ -4842,11 +4856,12 @@ static int decode_open(struct xdr_stream | |
81 | uint32_t savewords, bmlen, i; | |
82 | int status; | |
83 | ||
84 | - status = decode_op_hdr(xdr, OP_OPEN); | |
85 | - if (status != -EIO) | |
86 | - nfs_increment_open_seqid(status, res->seqid); | |
87 | - if (!status) | |
88 | - status = decode_stateid(xdr, &res->stateid); | |
89 | + if (!__decode_op_hdr(xdr, OP_OPEN, &status)) | |
90 | + return status; | |
91 | + nfs_increment_open_seqid(status, res->seqid); | |
92 | + if (status) | |
93 | + return status; | |
94 | + status = decode_stateid(xdr, &res->stateid); | |
95 | if (unlikely(status)) | |
96 | return status; | |
97 |