Commit fabcdd2d authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Long Li
Browse files

fs: xfs: Introduce FORCEALIGN inode flag

maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9VTE3
CVE: NA

Reference: https://lore.kernel.org/all/20240326133813.3224593-1-john.g.garry@oracle.com/



--------------------------------

Add a new inode flag to require that all file data extent mappings must
be aligned (both the file offset range and the allocated space itself)
to the extent size hint.  Having a separate COW extent size hint is no
longer allowed.

The goal here is to enable sysadmins and users to mandate that all space
mappings in a file must have a startoff/blockcount that are aligned to
(say) a 2MB alignment and that the startblock/blockcount will follow the
same alignment.

jpg: Enforce extsize is a power-of-2 for forcealign
Signed-off-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
Co-developed-by: default avatarJohn Garry <john.g.garry@oracle.com>
Signed-off-by: default avatarJohn Garry <john.g.garry@oracle.com>
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent c56fdc3c
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -353,6 +353,7 @@ xfs_sb_has_compat_feature(
#define XFS_SB_FEAT_RO_COMPAT_RMAPBT   (1 << 1)		/* reverse map btree */
#define XFS_SB_FEAT_RO_COMPAT_REFLINK  (1 << 2)		/* reflinked files */
#define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3)		/* inobt block counts */
#define XFS_SB_FEAT_RO_COMPAT_FORCEALIGN (1 << 30)	/* aligned file data extents */
#define XFS_SB_FEAT_RO_COMPAT_ALL \
		(XFS_SB_FEAT_RO_COMPAT_FINOBT | \
		 XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
@@ -972,15 +973,18 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
#define XFS_DIFLAG2_REFLINK_BIT	1	/* file's blocks may be shared */
#define XFS_DIFLAG2_COWEXTSIZE_BIT   2  /* copy on write extent size hint */
#define XFS_DIFLAG2_BIGTIME_BIT	3	/* big timestamps */
/* data extent mappings for regular files must be aligned to extent size hint */
#define XFS_DIFLAG2_FORCEALIGN_BIT 5

#define XFS_DIFLAG2_DAX		(1 << XFS_DIFLAG2_DAX_BIT)
#define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
#define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
#define XFS_DIFLAG2_BIGTIME	(1 << XFS_DIFLAG2_BIGTIME_BIT)
#define XFS_DIFLAG2_FORCEALIGN	(1 << XFS_DIFLAG2_FORCEALIGN_BIT)

#define XFS_DIFLAG2_ANY \
	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
	 XFS_DIFLAG2_BIGTIME)
	 XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_FORCEALIGN)

static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
{
+40 −0
Original line number Diff line number Diff line
@@ -574,6 +574,14 @@ xfs_dinode_verify(
	    !xfs_has_bigtime(mp))
		return __this_address;

	if (flags2 & XFS_DIFLAG2_FORCEALIGN) {
		fa = xfs_inode_validate_forcealign(mp, mode, flags,
				be32_to_cpu(dip->di_extsize),
				be32_to_cpu(dip->di_cowextsize));
		if (fa)
			return fa;
	}

	return NULL;
}

@@ -699,3 +707,35 @@ xfs_inode_validate_cowextsize(

	return NULL;
}

/* Validate the forcealign inode flag */
xfs_failaddr_t
xfs_inode_validate_forcealign(
	struct xfs_mount	*mp,
	uint16_t		mode,
	uint16_t		flags,
	uint32_t		extsize,
	uint32_t		cowextsize)
{
	/* superblock rocompat feature flag */
	if (!xfs_has_forcealign(mp))
		return __this_address;

	/* Only regular files and directories */
	if (!S_ISDIR(mode) && !S_ISREG(mode))
		return __this_address;

	/* Doesn't apply to realtime files */
	if (flags & XFS_DIFLAG_REALTIME)
		return __this_address;

	/* Requires a non-zero power-of-2 extent size hint */
	if (extsize == 0 || !is_power_of_2(extsize))
		return __this_address;

	/* Requires no cow extent size hint */
	if (cowextsize != 0)
		return __this_address;

	return NULL;
}
+3 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
		uint32_t cowextsize, uint16_t mode, uint16_t flags,
		uint64_t flags2);
xfs_failaddr_t xfs_inode_validate_forcealign(struct xfs_mount *mp,
		uint16_t mode, uint16_t flags, uint32_t extsize,
		uint32_t cowextsize);

static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
{
+2 −0
Original line number Diff line number Diff line
@@ -116,6 +116,8 @@ xfs_sb_version_to_features(
		features |= XFS_FEAT_REFLINK;
	if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_INOBTCNT)
		features |= XFS_FEAT_INOBTCNT;
	if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FORCEALIGN)
		features |= XFS_FEAT_FORCEALIGN;
	if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE)
		features |= XFS_FEAT_FTYPE;
	if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES)
+14 −0
Original line number Diff line number Diff line
@@ -643,6 +643,8 @@ _xfs_dic2xflags(
			flags |= FS_XFLAG_DAX;
		if (di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
			flags |= FS_XFLAG_COWEXTSIZE;
		if (di_flags2 & XFS_DIFLAG2_FORCEALIGN)
			flags |= FS_XFLAG_FORCEALIGN;
	}

	if (has_attr)
@@ -759,6 +761,18 @@ xfs_inode_inherit_flags2(
	}
	if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
		ip->i_d.di_flags2 |= XFS_DIFLAG2_DAX;
	if (pip->i_d.di_flags2 & XFS_DIFLAG2_FORCEALIGN)
		ip->i_d.di_flags2 |= XFS_DIFLAG2_FORCEALIGN;

	if (ip->i_d.di_flags2 & XFS_DIFLAG2_FORCEALIGN) {
		xfs_failaddr_t		failaddr;

		failaddr = xfs_inode_validate_forcealign(ip->i_mount,
				VFS_I(ip)->i_mode, ip->i_d.di_flags, ip->i_d.di_extsize,
				ip->i_d.di_cowextsize);
		if (failaddr)
			ip->i_d.di_flags2 &= ~XFS_DIFLAG2_FORCEALIGN;
	}
}

/*
Loading