]> git.hungrycats.org Git - linux/commitdiff
btrfs: stripe_alloc: DEBUG: on a live metadata write-hole hit, print the written...
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sun, 6 Sep 2026 13:02:29 +0000 (09:02 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sun, 6 Sep 2026 13:02:29 +0000 (09:02 -0400)
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
fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/raid56.c

index ff894c56d12841dedcbd01d9e5cc38aa3563f903..f2e0b76482367c547e321c228ce9e2105e7b9abb 100644 (file)
@@ -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)
 {
index 44eee7e5e740dbe7bba89f360a671261176e4bd1..25f9cca2fbf82104b8429d6774ea3c6556a610f1 100644 (file)
@@ -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);
index 7ebeb08f77615d90370bd107acc32966c9bd5e20..ef7ac9aefa922a9934fc4b87bdaca70d39a0e379 100644 (file)
@@ -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);
+                       }
                }
        }
 }