Commit 26d05e1c authored by Sergey Bashirov's avatar Sergey Bashirov Committed by Chuck Lever
Browse files

nfsd: Use correct error code when decoding extents



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: default avatarSergey Bashirov <sergeybashirov@gmail.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 48aab160
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -178,11 +178,13 @@ nfsd4_block_proc_layoutcommit(struct inode *inode,
{
	struct iomap *iomaps;
	int nr_iomaps;
	__be32 nfserr;

	nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
			lcp->lc_up_len, &iomaps, i_blocksize(inode));
	if (nr_iomaps < 0)
		return nfserrno(nr_iomaps);
	nfserr = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
			lcp->lc_up_len, &iomaps, &nr_iomaps,
			i_blocksize(inode));
	if (nfserr != nfs_ok)
		return nfserr;

	return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
}
@@ -316,11 +318,13 @@ nfsd4_scsi_proc_layoutcommit(struct inode *inode,
{
	struct iomap *iomaps;
	int nr_iomaps;
	__be32 nfserr;

	nr_iomaps = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
			lcp->lc_up_len, &iomaps, i_blocksize(inode));
	if (nr_iomaps < 0)
		return nfserrno(nr_iomaps);
	nfserr = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
			lcp->lc_up_len, &iomaps, &nr_iomaps,
			i_blocksize(inode));
	if (nfserr != nfs_ok)
		return nfserr;

	return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps);
}
+56 −15
Original line number Diff line number Diff line
@@ -112,34 +112,54 @@ nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
	return 0;
}

int
/**
 * nfsd4_block_decode_layoutupdate - decode the block layout extent array
 * @p: pointer to the xdr data
 * @len: number of bytes to decode
 * @iomapp: pointer to store the decoded extent array
 * @nr_iomapsp: pointer to store the number of extents
 * @block_size: alignment of extent offset and length
 *
 * This function decodes the opaque field of the layoutupdate4 structure
 * in a layoutcommit request for the block layout driver. The field is
 * actually an array of extents sent by the client. It also checks that
 * the file offset, storage offset and length of each extent are aligned
 * by @block_size.
 *
 * Return values:
 *   %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
 *   %nfserr_bad_xdr: The encoded array in @p is invalid
 *   %nfserr_inval: An unaligned extent found
 *   %nfserr_delay: Failed to allocate memory for @iomapp
 */
__be32
nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
		u32 block_size)
		int *nr_iomapsp, u32 block_size)
{
	struct iomap *iomaps;
	u32 nr_iomaps, i;

	if (len < sizeof(u32)) {
		dprintk("%s: extent array too small: %u\n", __func__, len);
		return -EINVAL;
		return nfserr_bad_xdr;
	}
	len -= sizeof(u32);
	if (len % PNFS_BLOCK_EXTENT_SIZE) {
		dprintk("%s: extent array invalid: %u\n", __func__, len);
		return -EINVAL;
		return nfserr_bad_xdr;
	}

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

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

	for (i = 0; i < nr_iomaps; i++) {
@@ -178,22 +198,42 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
	}

	*iomapp = iomaps;
	return nr_iomaps;
	*nr_iomapsp = nr_iomaps;
	return nfs_ok;
fail:
	kfree(iomaps);
	return -EINVAL;
	return nfserr_inval;
}

int
/**
 * nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array
 * @p: pointer to the xdr data
 * @len: number of bytes to decode
 * @iomapp: pointer to store the decoded extent array
 * @nr_iomapsp: pointer to store the number of extents
 * @block_size: alignment of extent offset and length
 *
 * This function decodes the opaque field of the layoutupdate4 structure
 * in a layoutcommit request for the scsi layout driver. The field is
 * actually an array of extents sent by the client. It also checks that
 * the offset and length of each extent are aligned by @block_size.
 *
 * Return values:
 *   %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
 *   %nfserr_bad_xdr: The encoded array in @p is invalid
 *   %nfserr_inval: An unaligned extent found
 *   %nfserr_delay: Failed to allocate memory for @iomapp
 */
__be32
nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
		u32 block_size)
		int *nr_iomapsp, u32 block_size)
{
	struct iomap *iomaps;
	u32 nr_iomaps, expected, i;

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

	nr_iomaps = be32_to_cpup(p++);
@@ -201,13 +241,13 @@ nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
	if (len != expected) {
		dprintk("%s: extent array size mismatch: %u/%u\n",
			__func__, len, expected);
		return -EINVAL;
		return nfserr_bad_xdr;
	}

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

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

	*iomapp = iomaps;
	return nr_iomaps;
	*nr_iomapsp = nr_iomaps;
	return nfs_ok;
fail:
	kfree(iomaps);
	return -EINVAL;
	return nfserr_inval;
}
+4 −4
Original line number Diff line number Diff line
@@ -54,9 +54,9 @@ __be32 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
		const struct nfsd4_getdeviceinfo *gdp);
__be32 nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
		const struct nfsd4_layoutget *lgp);
int nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
		u32 block_size);
int nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
		u32 block_size);
__be32 nfsd4_block_decode_layoutupdate(__be32 *p, u32 len,
		struct iomap **iomapp, int *nr_iomapsp, u32 block_size);
__be32 nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len,
		struct iomap **iomapp, int *nr_iomapsp, u32 block_size);

#endif /* _NFSD_BLOCKLAYOUTXDR_H */
+1 −0
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ void nfsd_lockd_shutdown(void);
#define	nfserr_cb_path_down	cpu_to_be32(NFSERR_CB_PATH_DOWN)
#define	nfserr_locked		cpu_to_be32(NFSERR_LOCKED)
#define	nfserr_wrongsec		cpu_to_be32(NFSERR_WRONGSEC)
#define nfserr_delay			cpu_to_be32(NFS4ERR_DELAY)
#define nfserr_badiomode		cpu_to_be32(NFS4ERR_BADIOMODE)
#define nfserr_badlayout		cpu_to_be32(NFS4ERR_BADLAYOUT)
#define nfserr_bad_session_digest	cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST)