]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: detect and fix bad summary counts at mount
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 5 Oct 2018 02:36:10 +0000 (21:36 -0500)
committerEric Sandeen <sandeen@redhat.com>
Fri, 5 Oct 2018 02:36:10 +0000 (21:36 -0500)
Source kernel commit: 2e9e6481e2a78de3a85083beccfbf6eda2689922

Filippo Giunchedi complained that xfs doesn't even perform basic sanity
checks of the fs summary counters at mount time.  Therefore, recalculate
the summary counters from the AGFs after log recovery if the counts were
bad (or we had to recover the fs).  Enhance the recalculation routine to
fail the mount entirely if the new values are also obviously incorrect.

We use a mount state flag to record the "bad summary count" state so
that the (subsequent) online fsck patches can detect subtlely incorrect
counts and set the flag; clear it userspace asks for a repair; or force
a recalculation at the next mount if nobody fixes it by unmount time.

Reported-by: Filippo Giunchedi <fgiunchedi@wikimedia.org>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/libxfs_priv.h
libxfs/xfs_sb.c

index da050abada2dda1803b54e6687460af9722c49c9..969ebd1cdfd7a435208a9bf1c845d62bc76483c6 100644 (file)
@@ -399,7 +399,7 @@ roundup_64(uint64_t x, uint32_t y)
 #define XFS_MOUNT_IKEEP                        0       /* ignored in userspace */
 #define XFS_MOUNT_SWALLOC              0       /* ignored in userspace */
 #define XFS_MOUNT_RDONLY               0       /* ignored in userspace */
-
+#define XFS_MOUNT_BAD_SUMMARY          0       /* ignored in userspace */
 
 #define xfs_trans_set_sync(tp)         ((void) 0)
 #define        xfs_trans_agblocks_delta(tp, d)
index e0513f69996901120172c8616a0020db26ced1f6..9a48d9301355172ea0226c813b677032bed493ca 100644 (file)
@@ -786,6 +786,7 @@ xfs_initialize_perag_data(
        uint64_t        bfree = 0;
        uint64_t        bfreelst = 0;
        uint64_t        btree = 0;
+       uint64_t        fdblocks;
        int             error;
 
        for (index = 0; index < agcount; index++) {
@@ -809,17 +810,31 @@ xfs_initialize_perag_data(
                btree += pag->pagf_btreeblks;
                xfs_perag_put(pag);
        }
+       fdblocks = bfree + bfreelst + btree;
+
+       /*
+        * If the new summary counts are obviously incorrect, fail the
+        * mount operation because that implies the AGFs are also corrupt.
+        * Clear BAD_SUMMARY so that we don't unmount with a dirty log, which
+        * will prevent xfs_repair from fixing anything.
+        */
+       if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
+               xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
+               error = -EFSCORRUPTED;
+               goto out;
+       }
 
        /* Overwrite incore superblock counters with just-read data */
        spin_lock(&mp->m_sb_lock);
        sbp->sb_ifree = ifree;
        sbp->sb_icount = ialloc;
-       sbp->sb_fdblocks = bfree + bfreelst + btree;
+       sbp->sb_fdblocks = fdblocks;
        spin_unlock(&mp->m_sb_lock);
 
        xfs_reinit_percpu_counters(mp);
-
-       return 0;
+out:
+       mp->m_flags &= ~XFS_MOUNT_BAD_SUMMARY;
+       return error;
 }
 
 /*