From: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> Prefaulting the write source buffer incurs an extra userspace access in the common fast path. Make btrfs_buffered_write() consistent with generic_perform_write(): only touch userspace an extra time when copy_folio_from_iter_atomic() has failed to make progress. Signed-off-by: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> Cc: Chris Mason <clm@xxxxxx> Cc: Josef Bacik <josef@xxxxxxxxxxxxxx> Cc: David Sterba <dsterba@xxxxxxxx> Cc: linux-btrfs@xxxxxxxxxxxxxxx --- b/fs/btrfs/file.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff -puN fs/btrfs/file.c~btrfs-postfault fs/btrfs/file.c --- a/fs/btrfs/file.c~btrfs-postfault 2025-01-29 09:03:36.927756510 -0800 +++ b/fs/btrfs/file.c 2025-01-29 09:03:36.935757176 -0800 @@ -1164,15 +1164,6 @@ ssize_t btrfs_buffered_write(struct kioc int extents_locked; bool force_page_uptodate = false; - /* - * Fault pages before locking them in prepare_one_folio() - * to avoid recursive lock - */ - if (unlikely(fault_in_iov_iter_readable(i, write_bytes))) { - ret = -EFAULT; - break; - } - only_release_metadata = false; sector_offset = pos & (fs_info->sectorsize - 1); @@ -1314,6 +1305,17 @@ again: cond_resched(); + /* + * Fault pages in a slow path after dropping folio + * lock. This avoids the chance of deadlocking in + * the fault handler. + */ + if (unlikely(copied == 0) && + (fault_in_iov_iter_readable(i, write_bytes) == write_bytes)) { + ret = -EFAULT; + break; + } + pos += copied; num_written += copied; } _