summaryrefslogtreecommitdiff
path: root/fs/nfsd/blocklayout.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/blocklayout.c')
-rw-r--r--fs/nfsd/blocklayout.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 35a95501db63..6d29ea5e8623 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -88,9 +88,10 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
const struct svc_fh *fhp, struct nfsd4_layoutget *args)
{
struct nfsd4_layout_seg *seg = &args->lg_seg;
+ struct pnfs_block_layout *bl;
struct pnfs_block_extent *bex;
u64 length;
- u32 block_size = i_blocksize(inode);
+ u32 nr_extents_max = 1, block_size = i_blocksize(inode);
__be32 nfserr;
if (locks_in_grace(SVC_NET(rqstp)))
@@ -103,15 +104,32 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
}
/*
+ * RFC 8881, section 3.3.17:
+ * The layout4 data type defines a layout for a file.
+ *
+ * RFC 8881, section 18.43.3:
+ * The loga_maxcount field specifies the maximum layout size
+ * (in bytes) that the client can handle. If the size of the
+ * layout structure exceeds the size specified by maxcount,
+ * the metadata server will return the NFS4ERR_TOOSMALL error.
+ */
+ nfserr = nfserr_toosmall;
+ if (args->lg_maxcount < PNFS_BLOCK_LAYOUT4_SIZE +
+ PNFS_BLOCK_EXTENT_SIZE)
+ goto out_error;
+
+ /*
* Some clients barf on non-zero block numbers for NONE or INVALID
* layouts, so make sure to zero the whole structure.
*/
nfserr = nfserrno(-ENOMEM);
- bex = kzalloc(sizeof(*bex), GFP_KERNEL);
- if (!bex)
+ bl = kzalloc(struct_size(bl, extents, nr_extents_max), GFP_KERNEL);
+ if (!bl)
goto out_error;
- args->lg_content = bex;
+ bl->nr_extents = nr_extents_max;
+ args->lg_content = bl;
+ bex = &bl->extents[0];
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
seg->iomode, args->lg_minlength, bex);
if (nfserr != nfs_ok)