Skip to content

Commit 6fed827

Browse files
author
Darrick J. Wong
committed
xfs: fix the xattr scrub to detect freemap/entries array collisions
In the previous patches, we observed that it's possible for there to be freemap entries with zero size but a nonzero base. This isn't an inconsistency per se, but older kernels can get confused by this and corrupt the block, leading to corruption. If we see this, flag the xattr structure for optimization so that it gets rebuilt. Cc: <stable@vger.kernel.org> # v4.15 Fixes: 13791d3 ("xfs: scrub extended attribute leaf space") Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 27a0c41 commit 6fed827

1 file changed

Lines changed: 27 additions & 27 deletions

File tree

fs/xfs/scrub/attr.c

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -287,32 +287,6 @@ xchk_xattr_set_map(
287287
return ret;
288288
}
289289

290-
/*
291-
* Check the leaf freemap from the usage bitmap. Returns false if the
292-
* attr freemap has problems or points to used space.
293-
*/
294-
STATIC bool
295-
xchk_xattr_check_freemap(
296-
struct xfs_scrub *sc,
297-
struct xfs_attr3_icleaf_hdr *leafhdr)
298-
{
299-
struct xchk_xattr_buf *ab = sc->buf;
300-
unsigned int mapsize = sc->mp->m_attr_geo->blksize;
301-
int i;
302-
303-
/* Construct bitmap of freemap contents. */
304-
bitmap_zero(ab->freemap, mapsize);
305-
for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
306-
if (!xchk_xattr_set_map(sc, ab->freemap,
307-
leafhdr->freemap[i].base,
308-
leafhdr->freemap[i].size))
309-
return false;
310-
}
311-
312-
/* Look for bits that are set in freemap and are marked in use. */
313-
return !bitmap_intersects(ab->freemap, ab->usedmap, mapsize);
314-
}
315-
316290
/*
317291
* Check this leaf entry's relations to everything else.
318292
* Returns the number of bytes used for the name/value data.
@@ -403,6 +377,7 @@ xchk_xattr_block(
403377

404378
*last_checked = blk->blkno;
405379
bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
380+
bitmap_zero(ab->freemap, mp->m_attr_geo->blksize);
406381

407382
/* Check all the padding. */
408383
if (xfs_has_crc(ds->sc->mp)) {
@@ -449,6 +424,9 @@ xchk_xattr_block(
449424
if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
450425
xchk_da_set_corrupt(ds, level);
451426

427+
if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
428+
goto out;
429+
452430
buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
453431
for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
454432
/* Mark the leaf entry itself. */
@@ -467,7 +445,29 @@ xchk_xattr_block(
467445
goto out;
468446
}
469447

470-
if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
448+
/* Construct bitmap of freemap contents. */
449+
for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
450+
if (!xchk_xattr_set_map(ds->sc, ab->freemap,
451+
leafhdr.freemap[i].base,
452+
leafhdr.freemap[i].size))
453+
xchk_da_set_corrupt(ds, level);
454+
455+
/*
456+
* freemap entries with zero length and nonzero base can cause
457+
* problems with older kernels, so we mark these for preening
458+
* even though there's no inconsistency.
459+
*/
460+
if (leafhdr.freemap[i].size == 0 &&
461+
leafhdr.freemap[i].base > 0)
462+
xchk_da_set_preen(ds, level);
463+
464+
if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
465+
goto out;
466+
}
467+
468+
/* Look for bits that are set in freemap and are marked in use. */
469+
if (bitmap_intersects(ab->freemap, ab->usedmap,
470+
mp->m_attr_geo->blksize))
471471
xchk_da_set_corrupt(ds, level);
472472

473473
if (leafhdr.usedbytes != usedbytes)

0 commit comments

Comments
 (0)