]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nfsd: Use correct error code when decoding extents
authorSergey Bashirov <sergeybashirov@gmail.com>
Thu, 12 Jun 2025 21:42:49 +0000 (00:42 +0300)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 14 Jul 2025 16:46:41 +0000 (12:46 -0400)
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 <sergeybashirov@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/blocklayoutxdr.h
fs/nfsd/nfsd.h

index 08a20e5bcf7fee0ea6ae6bd5a3fd7622c77977ed..19078a043e85c51a58764a2b94e190b47dd3ae1d 100644 (file)
@@ -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);
 }
index ce78f74715eeadf5f0b5ab6ae1c42c9fe5d2e532..669ff8e6e966e3ec49f3629fbefb3ec005378e82 100644 (file)
@@ -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;
 }
index 4e28ac8f11279746dd2f5b5d3ae42c00a2861e72..15b3569f3d9ad36834a0c8bd52f6aea2ccaec2ba 100644 (file)
@@ -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 */
index 54a96042f5ac6f277a859174be9cd1163e02e10d..1cd0bed57bc2f27248fd66a8efef692a5e9a390c 100644 (file)
@@ -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)