From: Zygo Blaxell Date: Sun, 6 Sep 2026 13:02:29 +0000 (-0400) Subject: btrfs: stripe_alloc: DEBUG: on a live metadata write-hole hit, print the written... X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=580309ebd9563b652bd1694a549b64d3b141f00a;p=linux btrfs: stripe_alloc: DEBUG: on a live metadata write-hole hit, print the written blocks and the runs covering the stripe Candidate-only diagnostic for the 90 live old-generation hits outside the system chunk (dhive cand16): which owner wrote the new-generation blocks into a stripe that still holds committed blocks, and what open runs the allocator had over that stripe. Assisted-by: Claude:claude-fable-5 --- diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 8ee3a64dddb90..daa2404cb75ae 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -511,6 +511,42 @@ static void btrfs_dump_open_meta_runs(struct btrfs_block_group *bg) spin_unlock_irqrestore(&bg->stripe_run_lock, flags); } +/* DEBUG: every open run overlapping [logical, logical + len), any class. */ +void btrfs_stripe_dump_runs_at(struct btrfs_fs_info *fs_info, u64 logical, + u64 len) +{ + struct btrfs_block_group *bg = btrfs_lookup_block_group(fs_info, logical); + struct btrfs_open_stripe_run *run; + unsigned long flags; + int n = 0; + + if (!bg) { + btrfs_warn(fs_info, " no block group for %llu", logical); + return; + } + btrfs_warn(fs_info, +" bg %llu len %llu ro %d armed %d claimable %llu trapped %llu fsl %llu", + bg->start, bg->length, bg->ro, + READ_ONCE(bg->stripe_unusable_ready), + (u64)bg->stripe_claimable, (u64)bg->stripe_unusable, + (u64)bg->full_stripe_len); + spin_lock_irqsave(&bg->stripe_run_lock, flags); + list_for_each_entry(run, &bg->open_stripe_runs, list) { + if (run->end <= logical || run->start >= logical + len) + continue; + n++; + btrfs_warn(fs_info, +" run %llu..%llu frontier %llu open %d inflight %llu transid %llu class %d open_seq %llu", + run->start, run->end, run->offset, run->open, + run->inflight_bytes, run->transid, run->class, + run->open_seq); + } + spin_unlock_irqrestore(&bg->stripe_run_lock, flags); + if (!n) + btrfs_warn(fs_info, " no open run covers %llu", logical); + btrfs_put_block_group(bg); +} + static bool bg_has_undrained_meta_runs(struct btrfs_block_group *bg, u64 transid) { diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index 44eee7e5e740d..25f9cca2fbf82 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -508,6 +508,8 @@ void btrfs_log_settle_stripes(struct btrfs_inode *inode, u64 file_start, int btrfs_stripe_alloc_check_support(struct btrfs_fs_info *fs_info); int btrfs_enable_stripe_alloc(struct btrfs_fs_info *fs_info); void btrfs_disable_stripe_alloc(struct btrfs_fs_info *fs_info); +void btrfs_stripe_dump_runs_at(struct btrfs_fs_info *fs_info, u64 logical, + u64 len); void btrfs_retire_open_stripes(struct btrfs_fs_info *fs_info, struct btrfs_transaction *trans); void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg); diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 7ebeb08f77615..ef7ac9aefa922 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -2987,6 +2987,8 @@ static void audit_uncovered_rmw(struct btrfs_raid_bio *rbio) */ index_rbio_pages(rbio); + bool dumped = false; + /* The generation this write is putting into the stripe. */ for (u32 i = 0; i < nsectors; i += sectors_per_tree) { u64 gen; @@ -3040,6 +3042,29 @@ static void audit_uncovered_rmw(struct btrfs_raid_bio *rbio) "read-modify-write of stripe %llu rewrites parity over committed tree block %llu at generation %llu (refs %llu, extent generation %llu) while writing generation %llu: write hole", rbio->bioc->full_stripe_logical, logical, gen, refs, egen, write_gen); + /* DEBUG: who wrote here, and which run handed it out */ + if (!dumped) { + dumped = true; + for (u32 j = 0; j < nsectors; j += sectors_per_tree) { + struct btrfs_header *h; + void *ka; + + if (!rbio->bio_sectors[j].has_paddr) + continue; + ka = kmap_local_sector(&rbio->bio_sectors[j]); + h = ka; + btrfs_warn(fs_info, +" covered block %llu owner %llu generation %llu level %u (sector %u)", + btrfs_stack_header_bytenr(h), + btrfs_stack_header_owner(h), + btrfs_stack_header_generation(h), + (unsigned int)h->level, j); + kunmap_local(ka); + } + btrfs_stripe_dump_runs_at(fs_info, + rbio->bioc->full_stripe_logical, + (u64)rbio->nr_data * BTRFS_STRIPE_LEN); + } } } }