]> git.hungrycats.org Git - linux/commitdiff
btrfs: raid56: do not park sync writes into nocow runs
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Fri, 31 Jul 2026 05:08:44 +0000 (01:08 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Fri, 18 Sep 2026 21:36:23 +0000 (17:36 -0400)
An in-place overwrite of a nodatacow file under stripe_alloc parked
like any partial write, but with a waiter behind it and nothing worth
merging: in-place overwrites arrive one fsync at a time, and unlike
the datacow fsync path nothing kicks the parked rbio before the page
writeback wait, so every fsync ate the full sync park deadline.
Measured against stock nodatacow on the same rig, that deadline was
the bulk of a ~3.7ms per-fsync regression.  Skip parking for sync
writes whose stripe belongs to a NOCOW-class run; async writeback
still parks and merges there.

Assisted-by: Claude:claude-fable-5
fs/btrfs/raid56.c

index 9d0db46399fe5170a1ee03e93be0563fb9f206c3..3211b60ecb4759bad01d3a962aa9f106074b9eda 100644 (file)
@@ -779,8 +779,11 @@ static bool rbio_try_park(struct btrfs_raid_bio *rbio)
        struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
        struct btrfs_stripe_hash_table *table = fs_info->stripe_hash_table;
        unsigned int timeout_ms = BTRFS_RBIO_PARK_TIMEOUT_MS;
+       enum btrfs_stripe_run_class class;
 
-       if (!btrfs_stripe_in_open_run(fs_info, rbio->bioc->full_stripe_logical))
+       if (!btrfs_stripe_open_run_class(fs_info,
+                                        rbio->bioc->full_stripe_logical,
+                                        &class))
                return false;
 
        spin_lock(&rbio->bio_list_lock);
@@ -788,6 +791,17 @@ static bool rbio_try_park(struct btrfs_raid_bio *rbio)
                timeout_ms = BTRFS_RBIO_PARK_SYNC_TIMEOUT_MS;
        spin_unlock(&rbio->bio_list_lock);
 
+       /*
+        * A sync write into a nodatacow inode's private run has a waiter
+        * behind it and nothing worth waiting to merge with: in-place
+        * overwrites arrive one fsync at a time, and the plain (unparked)
+        * write path is what stock nodatacow latency looks like.  Park only
+        * async writeback there.
+        */
+       if (class == BTRFS_STRIPE_RUN_NOCOW &&
+           timeout_ms == BTRFS_RBIO_PARK_SYNC_TIMEOUT_MS)
+               return false;
+
        spin_lock(&table->parked_lock);
        set_bit(RBIO_PARKED_BIT, &rbio->flags);
        rbio->park_deadline = jiffies + msecs_to_jiffies(timeout_ms);