]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: detect and repair misaligned rtinherit directory cowextsize hints
authorDarrick J. Wong <djwong@kernel.org>
Mon, 23 Sep 2024 20:42:47 +0000 (13:42 -0700)
committerChristoph Hellwig <hch@lst.de>
Wed, 9 Oct 2024 13:55:50 +0000 (15:55 +0200)
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>
fs/xfs/scrub/inode.c
fs/xfs/scrub/inode_repair.c

index ca1f1adc5f7996417786eccc92128cab3daff824..a5dc1b055b963055c39150b1338a740ec1a5ddb7 100644 (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. */
index 2ad2d7c2c7cca2c299b00f00ddd5bff039af9871..faca8e37aa799114b5a04967aee6b5d7382fe72e 100644 (file)
@@ -1878,6 +1878,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(
@@ -1901,6 +1915,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);