]> git.hungrycats.org Git - linux/commitdiff
btrfs: stripe_alloc: count nocow run lifecycles and stranded stripes in sysfs
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Fri, 11 Sep 2026 13:27:32 +0000 (09:27 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 16 Sep 2026 21:40:06 +0000 (17:40 -0400)
Add a stripe_run_stats file beside stripe_park_stats with lifetime
counters for the paths the previous two patches touched, so a test can
show that it exercised them rather than merely passed: private NOCOW
runs opened, claim candidates refused for overlapping a live run, bytes
of whole stripes the scans found stranded behind live runs, and rescans
requested by a freed run to credit its stripes back.

Assisted-by: Claude:claude-fable-5
fs/btrfs/block-group.c
fs/btrfs/fs.h
fs/btrfs/sysfs.c

index 8eaad6f0fa2bbf9f4fb3b784c71350fc18c3721a..5784481aafed2964a65b88d61a1813bdbbcb7cef 100644 (file)
@@ -665,8 +665,10 @@ static void free_open_stripe_run(struct btrfs_block_group *bg,
         * with the run gone they are claimable again, so have the next commit
         * rescan the group and credit them back.
         */
-       if (READ_ONCE(bg->stripe_unusable_ready))
+       if (READ_ONCE(bg->stripe_unusable_ready)) {
                set_bit(BLOCK_GROUP_FLAG_STRIPE_UNUSABLE_DIRTY, &bg->runtime_flags);
+               atomic64_inc(&bg->fs_info->stripe_run_stats.strand_rescan_marks);
+       }
        wake_up_var(&bg->open_stripe_runs);
 }
 
@@ -1194,6 +1196,8 @@ install:
                              (btrfs_stripe_allow_rmw(fs_info) &
                               (BTRFS_STRIPE_RMW_NODATACOW |
                                BTRFS_STRIPE_RMW_PREALLOC));
+       if (class == BTRFS_STRIPE_RUN_NOCOW)
+               atomic64_inc(&fs_info->stripe_run_stats.nocow_run_opened);
        new_run->owner = ino;
        new_run->start = start;
        new_run->end = start + len;
@@ -1247,8 +1251,10 @@ bool btrfs_stripe_run_range_usable(struct btrfs_block_group *bg,
                len = run->start - run_start;
        }
        spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
-       if (len < bg->full_stripe_len)
+       if (len < bg->full_stripe_len) {
+               atomic64_inc(&bg->fs_info->stripe_run_stats.claim_refused_live_run);
                return false;
+       }
        *run_len = len;
        return true;
 }
@@ -1290,6 +1296,8 @@ u64 btrfs_stripe_run_stranded_stripes(struct btrfs_block_group *bg, u32 *freep,
                }
        }
        spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
+       if (stranded)
+               atomic64_add(stranded, &bg->fs_info->stripe_run_stats.strand_scan_bytes);
        return stranded;
 }
 
index b25577bef4fbd7878b00f39d289f1c1ec6a5c240..f10ce9545cd568711562abf88b2e0fc2bbfb4764 100644 (file)
@@ -845,6 +845,21 @@ struct btrfs_fs_info {
                atomic64_t meta_rmw_free;
                atomic64_t congestion_short;
        } stripe_park_stats;
+       /*
+        * Stripe run lifecycle observability: lifetime counters exposed
+        * through sysfs stripe_run_stats, so a test can show it exercised
+        * the nocow private-run and stranded-stripe paths at all.
+        */
+       struct {
+               /* private NOCOW runs opened (they outlive commits) */
+               atomic64_t nocow_run_opened;
+               /* claim candidates refused for overlapping a live run */
+               atomic64_t claim_refused_live_run;
+               /* bytes of whole stripes the scans found stranded behind live runs */
+               atomic64_t strand_scan_bytes;
+               /* rescans requested by a freed run to credit its stripes back */
+               atomic64_t strand_rescan_marks;
+       } stripe_run_stats;
        /* BTRFS_STRIPE_RMW_* masks; see btrfs_stripe_allow_rmw(). */
        u32 stripe_rmw_opt;
        u32 stripe_rmw_prop;
index 96cc8b0d76f6e702e50f598419e1c465c7748f49..303ded65b8cd100a640da6efc14915b577a463a0 100644 (file)
@@ -1280,6 +1280,23 @@ static ssize_t btrfs_stripe_park_stats_show(struct kobject *kobj,
 }
 BTRFS_ATTR(, stripe_park_stats, btrfs_stripe_park_stats_show);
 
+static ssize_t btrfs_stripe_run_stats_show(struct kobject *kobj,
+                                          struct kobj_attribute *a, char *buf)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+
+       return sysfs_emit(buf,
+               "nocow_run_opened %lld\n"
+               "claim_refused_live_run %lld\n"
+               "strand_scan_bytes %lld\n"
+               "strand_rescan_marks %lld\n",
+               atomic64_read(&fs_info->stripe_run_stats.nocow_run_opened),
+               atomic64_read(&fs_info->stripe_run_stats.claim_refused_live_run),
+               atomic64_read(&fs_info->stripe_run_stats.strand_scan_bytes),
+               atomic64_read(&fs_info->stripe_run_stats.strand_rescan_marks));
+}
+BTRFS_ATTR(, stripe_run_stats, btrfs_stripe_run_stats_show);
+
 /*
  * Park deadlines, ms.  Writable so the constants can be swept against a
  * workload rather than rebuilt per data point; 0 disables parking for that
@@ -1729,6 +1746,7 @@ static const struct attribute *btrfs_attrs[] = {
        BTRFS_ATTR_PTR(, bg_reclaim_threshold),
        BTRFS_ATTR_PTR(, commit_stats),
        BTRFS_ATTR_PTR(, stripe_park_stats),
+       BTRFS_ATTR_PTR(, stripe_run_stats),
        BTRFS_ATTR_PTR(, stripe_park_timeout_ms),
        BTRFS_ATTR_PTR(, stripe_park_sync_timeout_ms),
        BTRFS_ATTR_PTR(, stripe_park_congestion),