]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: fix totally broken unit conversion in directory invalidation
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 30 Jan 2020 18:41:01 +0000 (13:41 -0500)
committerEric Sandeen <sandeen@sandeen.net>
Thu, 30 Jan 2020 18:41:01 +0000 (13:41 -0500)
Your humble author forgot that xfs_dablk_t has the same units as
xfs_fileoff_t, and totally screwed up the directory buffer invalidation
loop in dir_binval.  Not only is there an off-by-one error in the loop
conditional, but the unit conversions are wrong.

The pre-5.5 xfs_da_get_buf implementation mostly hides the off-by-one
error because dir_binval turns on "don't complain if no mapping" mode,
but on dirblocksize > fsblocksize filesystems the incorrect units can
cause us to miss invalidating some blocks, which can lead to other
buffer cache errors later.

Fixes: f9c559f4e4fb4 ("xfs_repair: invalidate dirty dir buffers when we zap a directory")
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>
repair/phase6.c

index 76709f73a4258cc3e29fe6645364c3198e157753..0874b649bdc204eb82da4da2976e1886699add73 100644 (file)
@@ -1273,7 +1273,7 @@ dir_binval(
        struct xfs_ifork        *ifp;
        struct xfs_da_geometry  *geo;
        struct xfs_buf          *bp;
-       xfs_dablk_t             dabno, end_dabno;
+       xfs_dablk_t             dabno;
        int                     error = 0;
 
        if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
@@ -1283,11 +1283,9 @@ dir_binval(
        geo = tp->t_mountp->m_dir_geo;
        ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
        for_each_xfs_iext(ifp, &icur, &rec) {
-               dabno = xfs_dir2_db_to_da(geo, rec.br_startoff +
-                               geo->fsbcount - 1);
-               end_dabno = xfs_dir2_db_to_da(geo, rec.br_startoff +
-                               rec.br_blockcount);
-               for (; dabno <= end_dabno; dabno += geo->fsbcount) {
+               for (dabno = roundup(rec.br_startoff, geo->fsbcount);
+                    dabno < rec.br_startoff + rec.br_blockcount;
+                    dabno += geo->fsbcount) {
                        bp = NULL;
                        error = -libxfs_da_get_buf(tp, ip, dabno, &bp,
                                        whichfork);