* [PATCH 0/3] btrfs: some improvements around nocow checking
@ 2025-07-09 20:20 fdmanana
2025-07-09 20:20 ` [PATCH 1/3] btrfs: update function comment for btrfs_check_nocow_lock() fdmanana
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: fdmanana @ 2025-07-09 20:20 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
Improve nocow write checking to avoid less iterations and less work when
doing buffered writes by checking multiple consecutive extents, plus a
couple cleanups.
Filipe Manana (3):
btrfs: update function comment for btrfs_check_nocow_lock()
btrfs: assert we can NOCOW the range in btrfs_truncate_block()
btrfs: make btrfs_check_nocow_lock() check more than one extent
fs/btrfs/file.c | 43 +++++++++++++++++++++++++++++++++----------
fs/btrfs/inode.c | 7 +++++--
2 files changed, 38 insertions(+), 12 deletions(-)
--
2.47.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] btrfs: update function comment for btrfs_check_nocow_lock()
2025-07-09 20:20 [PATCH 0/3] btrfs: some improvements around nocow checking fdmanana
@ 2025-07-09 20:20 ` fdmanana
2025-07-09 20:20 ` [PATCH 2/3] btrfs: assert we can NOCOW the range in btrfs_truncate_block() fdmanana
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: fdmanana @ 2025-07-09 20:20 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
The documentation for the @nowait parameter is missing, so add it.
The @nowait parameter was added in commit 80f9d24130e4 ("btrfs: make
btrfs_check_nocow_lock nowait compatible"), which forgot to update the
function comment.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
fs/btrfs/file.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 37bf473f2132..c2e83babdb8d 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -962,6 +962,7 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct folio *folio,
* @pos: File offset.
* @write_bytes: The length to write, will be updated to the nocow writeable
* range.
+ * @nowait: Indicate if we can block or not (non-blocking IO context).
*
* This function will flush ordered extents in the range to ensure proper
* nocow checks.
@@ -970,7 +971,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct folio *folio,
* > 0 If we can nocow, and updates @write_bytes.
* 0 If we can't do a nocow write.
* -EAGAIN If we can't do a nocow write because snapshoting of the inode's
- * root is in progress.
+ * root is in progress or because we are in a non-blocking IO
+ * context and need to block (@nowait is true).
* < 0 If an error happened.
*
* NOTE: Callers need to call btrfs_check_nocow_unlock() if we return > 0.
--
2.47.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] btrfs: assert we can NOCOW the range in btrfs_truncate_block()
2025-07-09 20:20 [PATCH 0/3] btrfs: some improvements around nocow checking fdmanana
2025-07-09 20:20 ` [PATCH 1/3] btrfs: update function comment for btrfs_check_nocow_lock() fdmanana
@ 2025-07-09 20:20 ` fdmanana
2025-07-09 20:20 ` [PATCH 3/3] btrfs: make btrfs_check_nocow_lock() check more than one extent fdmanana
2025-07-09 22:38 ` [PATCH 0/3] btrfs: some improvements around nocow checking Boris Burkov
3 siblings, 0 replies; 5+ messages in thread
From: fdmanana @ 2025-07-09 20:20 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
We call btrfs_check_nocow_lock() to see if we can NOCOW a block sized
range but we don't check later if we can NOCOW the whole range.
It's unexpected to be able to NOCOW a range smaller than blocksize, so
add an assertion to check the NOCOW range matches the blocksize.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
fs/btrfs/inode.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d060a64f8808..6aa1e66448fa 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4847,7 +4847,6 @@ int btrfs_truncate_block(struct btrfs_inode *inode, u64 offset, u64 start, u64 e
pgoff_t index = (offset >> PAGE_SHIFT);
struct folio *folio;
gfp_t mask = btrfs_alloc_write_mask(mapping);
- size_t write_bytes = blocksize;
int ret = 0;
const bool in_head_block = is_inside_block(offset, round_down(start, blocksize),
blocksize);
@@ -4899,8 +4898,12 @@ int btrfs_truncate_block(struct btrfs_inode *inode, u64 offset, u64 start, u64 e
ret = btrfs_check_data_free_space(inode, &data_reserved, block_start,
blocksize, false);
if (ret < 0) {
+ size_t write_bytes = blocksize;
+
if (btrfs_check_nocow_lock(inode, block_start, &write_bytes, false) > 0) {
- /* For nocow case, no need to reserve data space */
+ /* For nocow case, no need to reserve data space. */
+ ASSERT(write_bytes == blocksize, "write_bytes=%zu blocksize=%u",
+ write_bytes, blocksize);
only_release_metadata = true;
} else {
goto out;
--
2.47.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] btrfs: make btrfs_check_nocow_lock() check more than one extent
2025-07-09 20:20 [PATCH 0/3] btrfs: some improvements around nocow checking fdmanana
2025-07-09 20:20 ` [PATCH 1/3] btrfs: update function comment for btrfs_check_nocow_lock() fdmanana
2025-07-09 20:20 ` [PATCH 2/3] btrfs: assert we can NOCOW the range in btrfs_truncate_block() fdmanana
@ 2025-07-09 20:20 ` fdmanana
2025-07-09 22:38 ` [PATCH 0/3] btrfs: some improvements around nocow checking Boris Burkov
3 siblings, 0 replies; 5+ messages in thread
From: fdmanana @ 2025-07-09 20:20 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
Currently btrfs_check_nocow_lock() stops at the first extent it finds and
that extent may be smaller than the target range we want to NOCOW into.
But we can have multiple consecutive extents which we can NOCOW into, so
by stopping at the first one we find we just make the caller do more work
by splitting the write into multiple ones, or in the case of mmap writes
with large folios we fail with -ENOSPC in case the folio's range is
covered by more than one extent (the fallback to NOCOW for mmap writes in
case there's no available data space to reserve/allocate was recently
added by the patch "btrfs: fix -ENOSPC mmap write failure on NOCOW
files/extents").
Improve on this by checking for multiple consecutive extents.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
fs/btrfs/file.c | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index c2e83babdb8d..bc1e00db96c9 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -984,8 +984,8 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
struct btrfs_root *root = inode->root;
struct extent_state *cached_state = NULL;
u64 lockstart, lockend;
- u64 num_bytes;
- int ret;
+ u64 cur_offset;
+ int ret = 0;
if (!(inode->flags & (BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)))
return 0;
@@ -996,7 +996,6 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
lockstart = round_down(pos, fs_info->sectorsize);
lockend = round_up(pos + *write_bytes,
fs_info->sectorsize) - 1;
- num_bytes = lockend - lockstart + 1;
if (nowait) {
if (!btrfs_try_lock_ordered_range(inode, lockstart, lockend,
@@ -1008,14 +1007,36 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
btrfs_lock_and_flush_ordered_range(inode, lockstart, lockend,
&cached_state);
}
- ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, nowait);
- if (ret <= 0)
- btrfs_drew_write_unlock(&root->snapshot_lock);
- else
- *write_bytes = min_t(size_t, *write_bytes ,
- num_bytes - pos + lockstart);
+
+ cur_offset = lockstart;
+ while (cur_offset < lockend) {
+ u64 num_bytes = lockend - cur_offset + 1;
+
+ ret = can_nocow_extent(inode, cur_offset, &num_bytes, NULL, nowait);
+ if (ret <= 0) {
+ /*
+ * If cur_offset == lockstart it means we haven't found
+ * any extent against which we can NOCOW, so unlock the
+ * snapshot lock.
+ */
+ if (cur_offset == lockstart)
+ btrfs_drew_write_unlock(&root->snapshot_lock);
+ break;
+ }
+ cur_offset += num_bytes;
+ }
+
btrfs_unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
+ /*
+ * cur_offset > lockstart means there's at least a partial range we can
+ * NOCOW, and that range can cover one or more extents.
+ */
+ if (cur_offset > lockstart) {
+ *write_bytes = min_t(size_t, *write_bytes, cur_offset - pos);
+ return 1;
+ }
+
return ret;
}
--
2.47.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] btrfs: some improvements around nocow checking
2025-07-09 20:20 [PATCH 0/3] btrfs: some improvements around nocow checking fdmanana
` (2 preceding siblings ...)
2025-07-09 20:20 ` [PATCH 3/3] btrfs: make btrfs_check_nocow_lock() check more than one extent fdmanana
@ 2025-07-09 22:38 ` Boris Burkov
3 siblings, 0 replies; 5+ messages in thread
From: Boris Burkov @ 2025-07-09 22:38 UTC (permalink / raw)
To: fdmanana; +Cc: linux-btrfs
On Wed, Jul 09, 2025 at 09:20:27PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
>
> Improve nocow write checking to avoid less iterations and less work when
> doing buffered writes by checking multiple consecutive extents, plus a
> couple cleanups.
Reviewed-by: Boris Burkov <boris@bur.io>
>
> Filipe Manana (3):
> btrfs: update function comment for btrfs_check_nocow_lock()
> btrfs: assert we can NOCOW the range in btrfs_truncate_block()
> btrfs: make btrfs_check_nocow_lock() check more than one extent
>
> fs/btrfs/file.c | 43 +++++++++++++++++++++++++++++++++----------
> fs/btrfs/inode.c | 7 +++++--
> 2 files changed, 38 insertions(+), 12 deletions(-)
>
> --
> 2.47.2
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-07-09 22:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-09 20:20 [PATCH 0/3] btrfs: some improvements around nocow checking fdmanana
2025-07-09 20:20 ` [PATCH 1/3] btrfs: update function comment for btrfs_check_nocow_lock() fdmanana
2025-07-09 20:20 ` [PATCH 2/3] btrfs: assert we can NOCOW the range in btrfs_truncate_block() fdmanana
2025-07-09 20:20 ` [PATCH 3/3] btrfs: make btrfs_check_nocow_lock() check more than one extent fdmanana
2025-07-09 22:38 ` [PATCH 0/3] btrfs: some improvements around nocow checking Boris Burkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox