]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: fix inode_cluster_size rounding mayhem
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 28 Aug 2019 16:08:08 +0000 (12:08 -0400)
committerEric Sandeen <sandeen@redhat.com>
Wed, 28 Aug 2019 16:08:08 +0000 (12:08 -0400)
Source kernel commit: 490d451fa5188975c21246f7f8f4914cd3f2d6f2

inode_cluster_size is supposed to represent the size (in bytes) of an
inode cluster buffer.  We avoid having to handle multiple clusters per
filesystem block on filesystems with large blocks by openly rounding
this value up to 1 FSB when necessary.  However, we never reset
inode_cluster_size to reflect this new rounded value, which adds to the
potential for mistakes in calculating geometries.

Fix this by setting inode_cluster_size to reflect the rounded-up size if
needed, and special-case the few places in the sparse inodes code where
we actually need the smaller value to validate on-disk metadata.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_format.h
libxfs/xfs_ialloc.c
libxfs/xfs_trans_resv.c

index 38c9f3d81e1ee204fb9185c27283dfff6069d589..907407f6fa9bfcfe02c2005390131b6a69b2a27a 100644 (file)
@@ -1698,11 +1698,16 @@ struct xfs_ino_geometry {
        /* Maximum inode count in this filesystem. */
        uint64_t        maxicount;
 
+       /* Actual inode cluster buffer size, in bytes. */
+       unsigned int    inode_cluster_size;
+
        /*
         * Desired inode cluster buffer size, in bytes.  This value is not
-        * rounded up to at least one filesystem block.
+        * rounded up to at least one filesystem block, which is necessary for
+        * the sole purpose of validating sb_spino_align.  Runtime code must
+        * only ever use inode_cluster_size.
         */
-       unsigned int    inode_cluster_size;
+       unsigned int    inode_cluster_size_raw;
 
        /* Inode cluster sizes, adjusted to be at least 1 fsb. */
        unsigned int    inodes_per_cluster;
index acf9e55e2df8a10b9d2529d989a39fce2ece7fc9..7a86a3fd41d0eaf827921f1fb35ea7204f58b996 100644 (file)
@@ -2799,21 +2799,32 @@ xfs_ialloc_setup_geometry(
                igeo->maxicount = 0;
        }
 
-       igeo->inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
+       /*
+        * Compute the desired size of an inode cluster buffer size, which
+        * starts at 8K and (on v5 filesystems) scales up with larger inode
+        * sizes.
+        *
+        * Preserve the desired inode cluster size because the sparse inodes
+        * feature uses that desired size (not the actual size) to compute the
+        * sparse inode alignment.  The mount code validates this value, so we
+        * cannot change the behavior.
+        */
+       igeo->inode_cluster_size_raw = XFS_INODE_BIG_CLUSTER_SIZE;
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
-               int     new_size = igeo->inode_cluster_size;
+               int     new_size = igeo->inode_cluster_size_raw;
 
                new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE;
                if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size))
-                       igeo->inode_cluster_size = new_size;
+                       igeo->inode_cluster_size_raw = new_size;
        }
 
        /* Calculate inode cluster ratios. */
-       if (igeo->inode_cluster_size > mp->m_sb.sb_blocksize)
+       if (igeo->inode_cluster_size_raw > mp->m_sb.sb_blocksize)
                igeo->blocks_per_cluster = XFS_B_TO_FSBT(mp,
-                               igeo->inode_cluster_size);
+                               igeo->inode_cluster_size_raw);
        else
                igeo->blocks_per_cluster = 1;
+       igeo->inode_cluster_size = XFS_FSB_TO_B(mp, igeo->blocks_per_cluster);
        igeo->inodes_per_cluster = XFS_FSB_TO_INO(mp, igeo->blocks_per_cluster);
 
        /* Calculate inode cluster alignment. */
index 182e2c4f555219dadbb3832d2e5ec4de1ffc0681..2dbfee127d91ae618f2073db01ad3fadbf4578e9 100644 (file)
@@ -307,8 +307,7 @@ xfs_calc_iunlink_remove_reservation(
        struct xfs_mount        *mp)
 {
        return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-              2 * max_t(uint, XFS_FSB_TO_B(mp, 1),
-                        M_IGEO(mp)->inode_cluster_size);
+              2 * M_IGEO(mp)->inode_cluster_size;
 }
 
 /*
@@ -346,8 +345,7 @@ STATIC uint
 xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
 {
        return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-                       max_t(uint, XFS_FSB_TO_B(mp, 1),
-                             M_IGEO(mp)->inode_cluster_size);
+                       M_IGEO(mp)->inode_cluster_size;
 }
 
 /*