Skip to content

Commit 434b399

Browse files
sbashirogregkh
authored andcommitted
nfsd: Use correct error code when decoding extents
[ Upstream commit 26d05e1 ] Update error codes in decoding functions of block and scsi layout drivers to match the core nfsd code. NFS4ERR_EINVAL means that the server was able to decode the request, but the decoded values are invalid. Use NFS4ERR_BADXDR instead to indicate a decoding error. And ENOMEM is changed to nfs code NFS4ERR_DELAY. Signed-off-by: Sergey Bashirov <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Chuck Lever <[email protected]> Stable-dep-of: d68886b ("NFSD: Fix last write offset handling in layoutcommit") Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7e708db commit 434b399

File tree

4 files changed

+73
-27
lines changed

4 files changed

+73
-27
lines changed

fs/nfsd/blocklayout.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,13 @@ nfsd4_block_proc_layoutcommit(struct inode *inode,
178178
{
179179
struct iomap *iomaps;
180180
int nr_iomaps;
181+
__be32 nfserr;
181182

182-
nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
183-
lcp->lc_up_len, &iomaps, i_blocksize(inode));
184-
if (nr_iomaps < 0)
185-
return nfserrno(nr_iomaps);
183+
nfserr = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
184+
lcp->lc_up_len, &iomaps, &nr_iomaps,
185+
i_blocksize(inode));
186+
if (nfserr != nfs_ok)
187+
return nfserr;
186188

187189
return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
188190
}
@@ -316,11 +318,13 @@ nfsd4_scsi_proc_layoutcommit(struct inode *inode,
316318
{
317319
struct iomap *iomaps;
318320
int nr_iomaps;
321+
__be32 nfserr;
319322

320-
nr_iomaps = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
321-
lcp->lc_up_len, &iomaps, i_blocksize(inode));
322-
if (nr_iomaps < 0)
323-
return nfserrno(nr_iomaps);
323+
nfserr = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
324+
lcp->lc_up_len, &iomaps, &nr_iomaps,
325+
i_blocksize(inode));
326+
if (nfserr != nfs_ok)
327+
return nfserr;
324328

325329
return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
326330
}

fs/nfsd/blocklayoutxdr.c

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,54 @@ nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
112112
return 0;
113113
}
114114

115-
int
115+
/**
116+
* nfsd4_block_decode_layoutupdate - decode the block layout extent array
117+
* @p: pointer to the xdr data
118+
* @len: number of bytes to decode
119+
* @iomapp: pointer to store the decoded extent array
120+
* @nr_iomapsp: pointer to store the number of extents
121+
* @block_size: alignment of extent offset and length
122+
*
123+
* This function decodes the opaque field of the layoutupdate4 structure
124+
* in a layoutcommit request for the block layout driver. The field is
125+
* actually an array of extents sent by the client. It also checks that
126+
* the file offset, storage offset and length of each extent are aligned
127+
* by @block_size.
128+
*
129+
* Return values:
130+
* %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
131+
* %nfserr_bad_xdr: The encoded array in @p is invalid
132+
* %nfserr_inval: An unaligned extent found
133+
* %nfserr_delay: Failed to allocate memory for @iomapp
134+
*/
135+
__be32
116136
nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
117-
u32 block_size)
137+
int *nr_iomapsp, u32 block_size)
118138
{
119139
struct iomap *iomaps;
120140
u32 nr_iomaps, i;
121141

122142
if (len < sizeof(u32)) {
123143
dprintk("%s: extent array too small: %u\n", __func__, len);
124-
return -EINVAL;
144+
return nfserr_bad_xdr;
125145
}
126146
len -= sizeof(u32);
127147
if (len % PNFS_BLOCK_EXTENT_SIZE) {
128148
dprintk("%s: extent array invalid: %u\n", __func__, len);
129-
return -EINVAL;
149+
return nfserr_bad_xdr;
130150
}
131151

132152
nr_iomaps = be32_to_cpup(p++);
133153
if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) {
134154
dprintk("%s: extent array size mismatch: %u/%u\n",
135155
__func__, len, nr_iomaps);
136-
return -EINVAL;
156+
return nfserr_bad_xdr;
137157
}
138158

139159
iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
140160
if (!iomaps) {
141161
dprintk("%s: failed to allocate extent array\n", __func__);
142-
return -ENOMEM;
162+
return nfserr_delay;
143163
}
144164

145165
for (i = 0; i < nr_iomaps; i++) {
@@ -178,36 +198,56 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
178198
}
179199

180200
*iomapp = iomaps;
181-
return nr_iomaps;
201+
*nr_iomapsp = nr_iomaps;
202+
return nfs_ok;
182203
fail:
183204
kfree(iomaps);
184-
return -EINVAL;
205+
return nfserr_inval;
185206
}
186207

187-
int
208+
/**
209+
* nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array
210+
* @p: pointer to the xdr data
211+
* @len: number of bytes to decode
212+
* @iomapp: pointer to store the decoded extent array
213+
* @nr_iomapsp: pointer to store the number of extents
214+
* @block_size: alignment of extent offset and length
215+
*
216+
* This function decodes the opaque field of the layoutupdate4 structure
217+
* in a layoutcommit request for the scsi layout driver. The field is
218+
* actually an array of extents sent by the client. It also checks that
219+
* the offset and length of each extent are aligned by @block_size.
220+
*
221+
* Return values:
222+
* %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
223+
* %nfserr_bad_xdr: The encoded array in @p is invalid
224+
* %nfserr_inval: An unaligned extent found
225+
* %nfserr_delay: Failed to allocate memory for @iomapp
226+
*/
227+
__be32
188228
nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
189-
u32 block_size)
229+
int *nr_iomapsp, u32 block_size)
190230
{
191231
struct iomap *iomaps;
192232
u32 nr_iomaps, expected, i;
193233

194234
if (len < sizeof(u32)) {
195235
dprintk("%s: extent array too small: %u\n", __func__, len);
196-
return -EINVAL;
236+
return nfserr_bad_xdr;
197237
}
198238

199239
nr_iomaps = be32_to_cpup(p++);
200240
expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
201241
if (len != expected) {
202242
dprintk("%s: extent array size mismatch: %u/%u\n",
203243
__func__, len, expected);
204-
return -EINVAL;
244+
return nfserr_bad_xdr;
205245
}
206246

207247
iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
208248
if (!iomaps) {
209249
dprintk("%s: failed to allocate extent array\n", __func__);
210-
return -ENOMEM;
250+
return nfserr_delay;
211251
}
212252

213253
for (i = 0; i < nr_iomaps; i++) {
@@ -229,8 +269,9 @@ nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
229269
}
230270

231271
*iomapp = iomaps;
232-
return nr_iomaps;
272+
*nr_iomapsp = nr_iomaps;
273+
return nfs_ok;
233274
fail:
234275
kfree(iomaps);
235-
return -EINVAL;
276+
return nfserr_inval;
236277
}

fs/nfsd/blocklayoutxdr.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
5454
const struct nfsd4_getdeviceinfo *gdp);
5555
__be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
5656
const struct nfsd4_layoutget *lgp);
57-
int nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
58-
u32 block_size);
59-
int nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
60-
u32 block_size);
57+
__be32 nfsd4_block_decode_layoutupdate(__be32 *p, u32 len,
58+
struct iomap **iomapp, int *nr_iomapsp, u32 block_size);
59+
__be32 nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len,
60+
struct iomap **iomapp, int *nr_iomapsp, u32 block_size);
6161

6262
#endif /* _NFSD_BLOCKLAYOUTXDR_H */

fs/nfsd/nfsd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ void nfsd_lockd_shutdown(void);
286286
#define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN)
287287
#define nfserr_locked cpu_to_be32(NFSERR_LOCKED)
288288
#define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC)
289+
#define nfserr_delay cpu_to_be32(NFS4ERR_DELAY)
289290
#define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE)
290291
#define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT)
291292
#define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST)

0 commit comments

Comments
 (0)