xfs: detect and repair misaligned rtinherit directory cowextsize hints

If we encounter a directory that has been configured to pass on a CoW
extent size hint to a new realtime file and the hint isn't an integer
multiple of the rt extent size, we should flag the hint for
administrative review and/or turn it off because that is a
misconfiguration.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2024-11-20 16:21:09 -08:00
parent 48bc170f2c
commit a9600db96f
2 changed files with 32 additions and 9 deletions

View File

@ -260,12 +260,7 @@ xchk_inode_extsize(
xchk_ino_set_warning(sc, ino);
}
/*
* Validate di_cowextsize hint.
*
* The rules are documented at xfs_ioctl_setattr_check_cowextsize().
* These functions must be kept in sync with each other.
*/
/* Validate di_cowextsize hint. */
STATIC void
xchk_inode_cowextsize(
struct xfs_scrub *sc,
@ -276,12 +271,25 @@ xchk_inode_cowextsize(
uint64_t flags2)
{
xfs_failaddr_t fa;
uint32_t value = be32_to_cpu(dip->di_cowextsize);
fa = xfs_inode_validate_cowextsize(sc->mp,
be32_to_cpu(dip->di_cowextsize), mode, flags,
flags2);
fa = xfs_inode_validate_cowextsize(sc->mp, value, mode, flags, flags2);
if (fa)
xchk_ino_set_corrupt(sc, ino);
/*
* XFS allows a sysadmin to change the rt extent size when adding a rt
* section to a filesystem after formatting. If there are any
* directories with cowextsize and rtinherit set, the hint could become
* misaligned with the new rextsize. The verifier doesn't check this,
* because we allow rtinherit directories even without an rt device.
* Flag this as an administrative warning since we will clean this up
* eventually.
*/
if ((flags & XFS_DIFLAG_RTINHERIT) &&
(flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
value % sc->mp->m_sb.sb_rextsize > 0)
xchk_ino_set_warning(sc, ino);
}
/* Make sure the di_flags make sense for the inode. */

View File

@ -1903,6 +1903,20 @@ xrep_inode_pptr(
sizeof(struct xfs_attr_sf_hdr), true);
}
/* Fix COW extent size hint problems. */
STATIC void
xrep_inode_cowextsize(
struct xfs_scrub *sc)
{
/* Fix misaligned CoW extent size hints on a directory. */
if ((sc->ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
(sc->ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) &&
sc->ip->i_extsize % sc->mp->m_sb.sb_rextsize > 0) {
sc->ip->i_cowextsize = 0;
sc->ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
}
}
/* Fix any irregularities in an inode that the verifiers don't catch. */
STATIC int
xrep_inode_problems(
@ -1926,6 +1940,7 @@ xrep_inode_problems(
if (S_ISDIR(VFS_I(sc->ip)->i_mode))
xrep_inode_dir_size(sc);
xrep_inode_extsize(sc);
xrep_inode_cowextsize(sc);
trace_xrep_inode_fixed(sc);
xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);