Skip to content

Commit 61d7307

Browse files
adam900710kdave
authored andcommitted
btrfs: subpage: dump the involved bitmap when ASSERT() failed
For btrfs_folio_assert_not_dirty() and btrfs_folio_set_lock(), we call bitmap_test_range_all_zero() to ensure the involved range has no dirty/lock bit already set. However with my recent enhanced delalloc range error handling, I was hitting the ASSERT() inside btrfs_folio_set_lock(), and it turns out that some error handling path is not properly updating the folio flags. So add some extra dumping for the ASSERTs to dump the involved bitmap to help debug. Reviewed-by: Boris Burkov <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 396294d commit 61d7307

File tree

1 file changed

+30
-11
lines changed

1 file changed

+30
-11
lines changed

fs/btrfs/subpage.c

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,28 @@ IMPLEMENT_BTRFS_PAGE_OPS(ordered, folio_set_ordered, folio_clear_ordered,
635635
IMPLEMENT_BTRFS_PAGE_OPS(checked, folio_set_checked, folio_clear_checked,
636636
folio_test_checked);
637637

638+
#define GET_SUBPAGE_BITMAP(subpage, fs_info, name, dst) \
639+
{ \
640+
const int sectors_per_page = fs_info->sectors_per_page; \
641+
\
642+
ASSERT(sectors_per_page < BITS_PER_LONG); \
643+
*dst = bitmap_read(subpage->bitmaps, \
644+
sectors_per_page * btrfs_bitmap_nr_##name, \
645+
sectors_per_page); \
646+
}
647+
648+
#define SUBPAGE_DUMP_BITMAP(fs_info, folio, name, start, len) \
649+
{ \
650+
const struct btrfs_subpage *subpage = folio_get_private(folio); \
651+
unsigned long bitmap; \
652+
\
653+
GET_SUBPAGE_BITMAP(subpage, fs_info, name, &bitmap); \
654+
btrfs_warn(fs_info, \
655+
"dumpping bitmap start=%llu len=%u folio=%llu " #name "_bitmap=%*pbl", \
656+
start, len, folio_pos(folio), \
657+
fs_info->sectors_per_page, &bitmap); \
658+
}
659+
638660
/*
639661
* Make sure not only the page dirty bit is cleared, but also subpage dirty bit
640662
* is cleared.
@@ -660,6 +682,10 @@ void btrfs_folio_assert_not_dirty(const struct btrfs_fs_info *fs_info,
660682
subpage = folio_get_private(folio);
661683
ASSERT(subpage);
662684
spin_lock_irqsave(&subpage->lock, flags);
685+
if (unlikely(!bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits))) {
686+
SUBPAGE_DUMP_BITMAP(fs_info, folio, dirty, start, len);
687+
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
688+
}
663689
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
664690
spin_unlock_irqrestore(&subpage->lock, flags);
665691
}
@@ -689,23 +715,16 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
689715
nbits = len >> fs_info->sectorsize_bits;
690716
spin_lock_irqsave(&subpage->lock, flags);
691717
/* Target range should not yet be locked. */
692-
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
718+
if (unlikely(!bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits))) {
719+
SUBPAGE_DUMP_BITMAP(fs_info, folio, locked, start, len);
720+
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
721+
}
693722
bitmap_set(subpage->bitmaps, start_bit, nbits);
694723
ret = atomic_add_return(nbits, &subpage->nr_locked);
695724
ASSERT(ret <= fs_info->sectors_per_page);
696725
spin_unlock_irqrestore(&subpage->lock, flags);
697726
}
698727

699-
#define GET_SUBPAGE_BITMAP(subpage, fs_info, name, dst) \
700-
{ \
701-
const int sectors_per_page = fs_info->sectors_per_page; \
702-
\
703-
ASSERT(sectors_per_page < BITS_PER_LONG); \
704-
*dst = bitmap_read(subpage->bitmaps, \
705-
sectors_per_page * btrfs_bitmap_nr_##name, \
706-
sectors_per_page); \
707-
}
708-
709728
void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
710729
struct folio *folio, u64 start, u32 len)
711730
{

0 commit comments

Comments
 (0)