diff options
| author | Boris Burkov <boris@bur.io> | 2026-09-15 10:58:31 -0700 |
|---|---|---|
| committer | David Sterba <dsterba@suse.com> | 2026-10-12 19:16:21 +0200 |
| commit | 220c44b1b90fbff746472cbb3dde778b02afbef9 (patch) | |
| tree | 326e2edd82a3a4c3bfa16047e1dd1f34efe6890b /tools/perf/scripts/python/stackcollapse.py | |
| parent | 3bb5ed05c1ead17a12456d77591c773e1032c16a (diff) | |
| download | linux-220c44b1b90fbff746472cbb3dde778b02afbef9.tar.gz linux-220c44b1b90fbff746472cbb3dde778b02afbef9.zip | |
btrfs: pre-flush reflink source before taking inode locks
Consider the following sketch of a shell script:
dd if=/dev/urandom of=/mnt/src bs=1M count=4096
cp --reflink=always /mnt/src /mnt/dst &
sleep 0.1 # let the clone reach its flush
time dd if=/mnt/src of=/dev/null bs=4K count=1 iflag=direct
The current logic in reflink ensures the existence and stability of both
the src and destination inode by locking them both and then flushing all
dirty pages / ordered_extents under the inode lock. This blocks
concurrent usage by even readers of the inode locks, like direct reads
or seeks for the duration of writeback on the entirety of the two files.
We observe this particular contention frequently in the Meta fleet.
It is also a relatively common pattern to write the src file, then reflink
it while it is still dirty, so that typical path naturally hits this
contention. This workload motivates a relatively simple optimization:
trigger the unavoidable src flushing outside the locked region.
Therefore, do an optimistic btrfs_wait_ordered_range() without the locks
while relying on the calls to btrfs_wait_ordered_range() under the
locks in btrfs_remap_file_range_prep() to ensure correctness. In the
worst case with concurrent writes while unlocked, we can end up doing
the writeback twice, which I think is a reasonable price to pay to avoid
victimizing innocent readers in a common case.
With and without this patch, the above reproducer runs the reflink in
the same ~0.5s on my system. Without the patch, the direct read blocks
for basically the full duration of the reflink while with the patch it
returns in a few milliseconds.
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'tools/perf/scripts/python/stackcollapse.py')
0 files changed, 0 insertions, 0 deletions
