Skip to content

Linux 6.17: fuse: extend i_size from a READ reply under DLM - #266

Closed
cryptosven76 wants to merge 1 commit into
redfs-ubuntu-hwe-6.17.0-16.16-24.04.1from
red-51747-read-extends-isize-6.17
Closed

cryptosven76 wants to merge 1 commit into
redfs-ubuntu-hwe-6.17.0-16.16-24.04.1from
red-51747-read-extends-isize-6.17

Conversation

@cryptosven76

Copy link
Copy Markdown

Second change for RED-51747, complementary to #264. It is independent of #264 (same base) so each can be reviewed on its own.

Problem

Under DLM with the writeback cache, i_size is only this node's view. Writers claim their own extension under fi->lock, and the server's size is applied only when a GETATTR reply happens to arrive. A partial EOF page can hold another node's bytes, read in by the read-modify-write READ under a write grant. iomap treats them as post-EOF:

Change

A READ reply proves the file reaches at least pos + res: redfsd returns a short count (nob=0 for a page past its EOF) and zero-filled pages for holes inside the file. In fuse_do_readfolio(), under fc->dlm && fc->writeback_cache, raise i_size to that end:

  • monotonically, under fi->lock;
  • bumping attr_version like fuse_read_update_size(), so an older in-flight GETATTR reply cannot shrink it back and truncate_pagecache() the data;
  • skipped while FUSE_I_SIZE_UNSTABLE marks a local truncate or size-changing setattr in progress.

With this, the read-modify-write read that pulls in another node's bytes also moves the local EOF past them, so iomap never zeroes them. #264 stays useful as a guard that writeback never sends bytes past the EOF it zeroed at.

Review points

  • Remote truncate: a truncate on another node revokes every grant above its new size before it proceeds, and the next attribute reply carries the smaller size. Can a READ reply that predates the truncate still raise i_size after the revoke? The attr_version bump would then make that stale size win over a GETATTR that started before the read completed. Worth checking against the -truncate branch.
  • Speculative-extension retract in fuse_cache_write_iter(): it shrinks i_size only if it still equals that writer's claimed end. A read-raised size is treated as a concurrent extender and kept, which looks right. A read-raised size equal to exactly that end would be retracted, which is harmless but imprecise.
  • Readahead (fuse_readpages_end()) is not changed. The kernel does not read ahead past the local i_size, so the RMW and read_folio paths through fuse_do_readfolio() are the ones that matter.

Testing

Compile-tested only: built as DKMS 20261016.readsize1 against Ubuntu 6.17.0-42 with no warnings. It has not been run yet. The RED-51747 reproducer (red/red PR 29256) on tyan-h3-u24 can test it alone and together with #264.

🤖 Generated with Claude Code

With DLM and the writeback cache, i_size is only this node's view of
the file: each writer claims its own extension under fi->lock, and the
server's size is applied only when a GETATTR reply happens to arrive.
Another node's data can therefore sit past the local i_size in the page
cache, read in by the read-modify-write READ of a partial page under a
write grant.

iomap treats those bytes as post-EOF. iomap_writeback_handle_eof()
zeroes them in the folio before writeback, and a concurrent local
extension of i_size can then let the zeros reach the server over the
other node's data (RED-51747). Even when they are not sent, the zeroed
tail stays in the clean, uptodate folio.

A READ reply proves the file reaches at least pos + bytes returned: the
server returns a short count past its EOF and zero-filled pages for
holes inside it. Under DLM with the writeback cache, raise i_size to
that end, monotonically under fi->lock, and bump attr_version as
fuse_read_update_size() does so that an older GETATTR reply cannot pull
it back down. Leave it alone while FUSE_I_SIZE_UNSTABLE marks a local
truncate in progress.

Signed-off-by: Sven Oehme <soehme@ddn.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cryptosven76

Copy link
Copy Markdown
Author

close in favor of #267

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant