Linux Btrfs filesystem development
 help / color / mirror / Atom feed
* [PATCH RFC] btrfs: wait for encoded writes in fast fsync
@ 2026-11-04  7:10 Qu Wenruo
  2026-11-04  8:11 ` Christoph Hellwig
  2026-11-04 11:57 ` Filipe Manana
  0 siblings, 2 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-11-04  7:10 UTC (permalink / raw)
  To: linux-btrfs

[BUG REPORT]
Sashiko reported a bug that encoded writes can have its file extents
recorded before their data reaches disks.

[CAUSE]
An encoded write returns to the caller as soon as its bio is submitted,
and its folios are not in the inode's page cache:

  btrfs_ioctl_encoded_write()
   \- btrfs_do_encoded_write()
       |- btrfs_alloc_ordered_extent()
       \- btrfs_submit_compressed_write()   <- returns before the bio ends

A fast fsync only waits for writeback of the folios in the page cache,
so it has nothing to wait for on such an ordered extent:

  btrfs_sync_file()
   |- btrfs_get_ordered_extents_for_logging()
   |- filemap_fdatawait_range()             <- no folio under writeback
   \- btrfs_log_dentry_safe()
       \- ...
           \- log_extent_csums()
               \- log_csums()               <- csum_list may be in flight

This has two problems:

- fsync can return before the data of the encoded write is on disk, while
  the log tree describing it is already persisted.

- With async data checksum generation, the sums are attached to
  ordered->csum_list by btrfs_csum_one_bio() before the checksums are
  calculated.  log_extent_csums() can then log zeroed or partially
  calculated checksums.

For buffered writes this is not a problem, as writeback of a folio ends
after the bio endio, which in turn runs after the checksums are
generated.

[FIX]
Fix it by waiting for the encoded ordered extents in the fast fsync path
before waiting for writeback.

And if the encoded OE failed, also fail the whole fsync early.

Such an ordered extent can only complete after its bio is finished,
meaning the data is on disk and the checksums are fully generated.

Link: https://sashiko.dev/#/patchset/8eb322321cac98013cc46dfe8d89fa58c1ad3dee.1793766229.git.wqu%40suse.com
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
Reason for RFC:

This is only covering encoded IO, not direct IO.

As we should not mix direct and buffered IO in the first place, fsync()
definitely counts as a function in the buffered IO family.

The problem is whether we should treat encoded IOs as buffered or direct?

The encoded write itself doesn't wait for write to finish, so it looks
like buffered, but on the other hand it doesn't touch page cache at all,
which is similar to direct IO.

Personally speaking, I tend to treat encoded IO more like buffered, thus
that's why I sent the patch out, other than rejecting the Sashiko review
result.
---
 fs/btrfs/file.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 20e15dc30bfb..474bbb0adfef 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1629,12 +1629,31 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 		ret = btrfs_wait_ordered_range(inode, start, len);
 		clear_bit(BTRFS_INODE_COW_WRITE_ERROR, &inode->runtime_flags);
 	} else {
+		struct btrfs_ordered_extent *ordered;
+
 		/*
 		 * Get our ordered extents as soon as possible to avoid doing
 		 * checksum lookups in the csum tree, and use instead the
 		 * checksums attached to the ordered extents.
 		 */
 		btrfs_get_ordered_extents_for_logging(inode, &ctx.ordered_extents);
+
+		/*
+		 * Encoded writes don't mark any folio of the inode as writeback,
+		 * thus the fdatawait below can't wait for them.  Wait for them
+		 * explicitly, so that their data is on disk and their checksums
+		 * are fully generated before we log them.
+		 */
+		list_for_each_entry(ordered, &ctx.ordered_extents, log_list) {
+			if (test_bit(BTRFS_ORDERED_ENCODED, &ordered->flags)) {
+				btrfs_start_ordered_extent(ordered);
+				if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) {
+					ret = -EIO;
+					goto out_release_extents;
+				}
+			}
+		}
+
 		ret = filemap_fdatawait_range(inode->vfs_inode.i_mapping, start, end);
 		if (ret)
 			goto out_release_extents;
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-11-04 11:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04  7:10 [PATCH RFC] btrfs: wait for encoded writes in fast fsync Qu Wenruo
2026-11-04  8:11 ` Christoph Hellwig
2026-11-04  8:14   ` Qu Wenruo
2026-11-04  8:46     ` Christoph Hellwig
2026-11-04 11:59     ` Filipe Manana
2026-11-04 11:57 ` Filipe Manana

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox