diff options
| -rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 15 | ||||
| -rw-r--r-- | fs/xfs/xfs_iomap.c | 10 | 
2 files changed, 24 insertions, 1 deletions
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 4aa2f11ba56..3fc09cd8d51 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -1493,12 +1493,25 @@ xfs_bmbt_split(  	left = XFS_BUF_TO_BMBT_BLOCK(lbp);  	args.fsbno = cur->bc_private.b.firstblock;  	args.firstblock = args.fsbno; +	args.minleft = 0;  	if (args.fsbno == NULLFSBLOCK) {  		args.fsbno = lbno;  		args.type = XFS_ALLOCTYPE_START_BNO; +		/* +		 * Make sure there is sufficient room left in the AG to +		 * complete a full tree split for an extent insert.  If +		 * we are converting the middle part of an extent then +		 * we may need space for two tree splits. +		 * +		 * We are relying on the caller to make the correct block +		 * reservation for this operation to succeed.  If the +		 * reservation amount is insufficient then we may fail a +		 * block allocation here and corrupt the filesystem. +		 */ +		args.minleft = xfs_trans_get_block_res(args.tp);  	} else  		args.type = XFS_ALLOCTYPE_NEAR_BNO; -	args.mod = args.minleft = args.alignment = args.total = args.isfl = +	args.mod = args.alignment = args.total = args.isfl =  		args.userdata = args.minalignslop = 0;  	args.minlen = args.maxlen = args.prod = 1;  	args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 7edcde691d1..67f22b2b44b 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -889,6 +889,16 @@ xfs_iomap_write_unwritten(  	count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);  	count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); +	/* +	 * Reserve enough blocks in this transaction for two complete extent +	 * btree splits.  We may be converting the middle part of an unwritten +	 * extent and in this case we will insert two new extents in the btree +	 * each of which could cause a full split. +	 * +	 * This reservation amount will be used in the first call to +	 * xfs_bmbt_split() to select an AG with enough space to satisfy the +	 * rest of the operation. +	 */  	resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;  	do {  |