Commit 83a21c18 authored by Chandan Babu R's avatar Chandan Babu R
Browse files

xfs: Directory's data fork extent counter can never overflow



The maximum file size that can be represented by the data fork extent counter
in the worst case occurs when all extents are 1 block in length and each block
is 1KB in size.

With XFS_MAX_EXTCNT_DATA_FORK_SMALL representing maximum extent count and with
1KB sized blocks, a file can reach upto,
(2^31) * 1KB = 2TB

This is much larger than the theoretical maximum size of a directory
i.e. XFS_DIR2_SPACE_SIZE * 3 = ~96GB.

Since a directory's inode can never overflow its data fork extent counter,
this commit removes all the overflow checks associated with
it. xfs_dinode_verify() now performs a rough check to verify if a diretory's
data fork is larger than 96GB.

Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandan.babu@oracle.com>
parent 52a4a148
Loading
Loading
Loading
Loading
+0 −20
Original line number Diff line number Diff line
@@ -5147,26 +5147,6 @@ xfs_bmap_del_extent_real(
		 * Deleting the middle of the extent.
		 */

		/*
		 * For directories, -ENOSPC is returned since a directory entry
		 * remove operation must not fail due to low extent count
		 * availability. -ENOSPC will be handled by higher layers of XFS
		 * by letting the corresponding empty Data/Free blocks to linger
		 * until a future remove operation. Dabtree blocks would be
		 * swapped with the last block in the leaf space and then the
		 * new last block will be unmapped.
		 *
		 * The above logic also applies to the source directory entry of
		 * a rename operation.
		 */
		error = xfs_iext_count_may_overflow(ip, whichfork, 1);
		if (error) {
			ASSERT(S_ISDIR(VFS_I(ip)->i_mode) &&
				whichfork == XFS_DATA_FORK);
			error = -ENOSPC;
			goto done;
		}

		old = got;

		got.br_blockcount = del->br_startoff - got.br_startoff;
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ struct xfs_da_geometry {
	unsigned int	free_hdr_size;	/* dir2 free header size */
	unsigned int	free_max_bests;	/* # of bests entries in dir2 free */
	xfs_dablk_t	freeblk;	/* blockno of free data v2 */
	xfs_extnum_t	max_extents;	/* Max. extents in corresponding fork */

	xfs_dir2_data_aoff_t data_first_offset;
	size_t		data_entry_offset;
+1 −0
Original line number Diff line number Diff line
@@ -277,6 +277,7 @@ xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr)
 * Directory address space divided into sections,
 * spaces separated by 32GB.
 */
#define	XFS_DIR2_MAX_SPACES	3
#define	XFS_DIR2_SPACE_SIZE	(1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
#define	XFS_DIR2_DATA_SPACE	0
#define	XFS_DIR2_DATA_OFFSET	(XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE)
+8 −0
Original line number Diff line number Diff line
@@ -150,6 +150,8 @@ xfs_da_mount(
	dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
				(uint)sizeof(xfs_da_node_entry_t);
	dageo->max_extents = (XFS_DIR2_MAX_SPACES * XFS_DIR2_SPACE_SIZE) >>
					mp->m_sb.sb_blocklog;
	dageo->magicpct = (dageo->blksize * 37) / 100;

	/* set up attribute geometry - single fsb only */
@@ -161,6 +163,12 @@ xfs_da_mount(
	dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
				(uint)sizeof(xfs_da_node_entry_t);

	if (xfs_has_large_extent_counts(mp))
		dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_LARGE;
	else
		dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_SMALL;

	dageo->magicpct = (dageo->blksize * 37) / 100;
	return 0;
}
+13 −0
Original line number Diff line number Diff line
@@ -915,6 +915,19 @@ enum xfs_dinode_fmt {
 *
 * Rounding up 47 to the nearest multiple of bits-per-byte results in 48. Hence
 * 2^48 was chosen as the maximum data fork extent count.
 *
 * The maximum file size that can be represented by the data fork extent counter
 * in the worst case occurs when all extents are 1 block in length and each
 * block is 1KB in size.
 *
 * With XFS_MAX_EXTCNT_DATA_FORK_SMALL representing maximum extent count and
 * with 1KB sized blocks, a file can reach upto,
 * 1KB * (2^31) = 2TB
 *
 * This is much larger than the theoretical maximum size of a directory
 * i.e. XFS_DIR2_SPACE_SIZE * XFS_DIR2_MAX_SPACES = ~96GB.
 *
 * Hence, a directory inode can never overflow its data fork extent counter.
 */
#define XFS_MAX_EXTCNT_DATA_FORK_LARGE	((xfs_extnum_t)((1ULL << 48) - 1))
#define XFS_MAX_EXTCNT_ATTR_FORK_LARGE	((xfs_extnum_t)((1ULL << 32) - 1))
Loading