Skip to content

Commit

Permalink
xfs: fix allocation length overflow in xfs_bmapi_write()
Browse files Browse the repository at this point in the history
When testing the new xfstests --large-fs option that does very large
file preallocations, this assert was tripped deep in
xfs_alloc_vextent():

XFS: Assertion failed: args->minlen <= args->maxlen, file: fs/xfs/xfs_alloc.c, line: 2239

The allocation was trying to allocate a zero length extent because
the lower 32 bits of the allocation length was zero. The remaining
length of the allocation to be done was an exact multiple of 2^32 -
the first case I saw was at 496TB remaining to be allocated.

This turns out to be an overflow when converting the allocation
length (a 64 bit quantity) into the extent length to allocate (a 32
bit quantity), and it requires the length to be allocated an exact
multiple of 2^32 blocks to trip the assert.

Fix it by limiting the extent lenth to allocate to MAXEXTLEN.

Signed-off-by: Dave Chinner <[email protected]>
Signed-off-by: Ben Myers <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Dec 2, 2011
1 parent 4c393a6 commit a99ebf4
Showing 1 changed file with 19 additions and 1 deletion.
20 changes: 19 additions & 1 deletion fs/xfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,8 @@ xfs_bmap_btalloc(
int tryagain;
int error;

ASSERT(ap->length);

mp = ap->ip->i_mount;
align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0;
if (unlikely(align)) {
Expand Down Expand Up @@ -4629,6 +4631,8 @@ xfs_bmapi_allocate(
int error;
int rt;

ASSERT(bma->length > 0);

rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip);

/*
Expand Down Expand Up @@ -4849,6 +4853,7 @@ xfs_bmapi_write(
ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
ASSERT(!(flags & XFS_BMAPI_IGSTATE));
ASSERT(tp != NULL);
ASSERT(len > 0);

whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
Expand Down Expand Up @@ -4918,9 +4923,22 @@ xfs_bmapi_write(
bma.eof = eof;
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
bma.wasdel = wasdelay;
bma.length = len;
bma.offset = bno;

/*
* There's a 32/64 bit type mismatch between the
* allocation length request (which can be 64 bits in
* length) and the bma length request, which is
* xfs_extlen_t and therefore 32 bits. Hence we have to
* check for 32-bit overflows and handle them here.
*/
if (len > (xfs_filblks_t)MAXEXTLEN)
bma.length = MAXEXTLEN;
else
bma.length = len;

ASSERT(len > 0);
ASSERT(bma.length > 0);
error = xfs_bmapi_allocate(&bma, flags);
if (error)
goto error0;
Expand Down

0 comments on commit a99ebf4

Please sign in to comment.