Repository navigation
Conversation
Under DLM with the writeback cache, a node's i_size only covers its own writes. When two nodes share a page at a block boundary, the lower writer's read before its partial write returns the upper writer's bytes from the server, but they lie past the local i_size. iomap_writeback_handle_eof() then zeroes them in the cached folio as if they were past EOF, the folio stays uptodate, and if i_size grows before the send is cropped the zeroes overwrite the other node's data on the server (RED-51747). A read reply proves the file extends at least to pos + res, since the server clips reads at its size. Raise i_size to cover those bytes in fuse_do_readfolio() and fuse_readpages_end(), so the folio tail is never treated as past EOF. The raise must not resurrect bytes a truncate removed while the read was in flight. attr_version cannot guard this, because every revoke bumps it, including the revoke of the range being read. Add fi->size_gen instead, bumped only by a local truncate and by a whole-file invalidate, which is how a remote truncate reaches the client, and drop the raise when it changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hbirth
merged commit Oct 16, 2026
92eee3c
into
DDNStorage:redfs-ubuntu-hwe-6.17.0-16.16-24.04.1
2 checks passed
|
Post-merge check on tyan-h3-u24: the deployed redfs.ko (DKMS 🤖 Generated with Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Under DLM with the writeback cache, a node's i_size covers only its own writes. When two nodes share a page at a block boundary, the lower writer reads the page before its partial write. The read returns the upper writer's bytes, but those bytes lie past the lower writer's local i_size. At writeback,
iomap_writeback_handle_eof()zeroes them in the cached folio as if they were past EOF, and the folio stays uptodate. If i_size grows before the send is cropped, the zeroes overwrite the other node's data on the server (RED-51747).A READ reply proves the file is at least
pos + resbytes long, because the server clips READ replies at its file size. This change raises i_size to cover the returned bytes, sohandle_eofnever zeroes them.Changes
fuse_dlm_read_extend_size()takesfi->lockand raises i_size topos + resonly when all of these hold:fc->dlm && fc->writeback_cache;FUSE_I_SIZE_UNSTABLEis clear;fi->size_genis unchanged since the READ was sent.When it raises i_size it also bumps
attr_version.It is called from
fuse_do_readfolio()(read_folio, and iomap's read before a partial write) and fromfuse_readpages_end()(readahead). O_DIRECT is untouched.New
fi->size_genguards against stale replies.attr_versioncannot do this job: every revoke bumps it, including the revoke of the range being read, which happened in the traced failure.size_genis bumped only in two places:fuse_do_setattr()for a truncate, whenFUSE_I_SIZE_UNSTABLEis set and at both places it is cleared;fuse_reverse_inval_inode()for a whole-file invalidate (offset <= 0 && len <= 0). This is the form a remote truncate takes on the client, because the server takes the sattr lock EX and that revokes the sattr locks of other clients.Relation to #264
This PR does not depend on #264 and applies to the 6.17 branch on its own. The raise is skipped in some cases: a short read, a whole-file invalidate racing the read, or a page that did not come from a READ reply. In those cases the folio tail is still zeroed, and only #264 (clamp the writeback send to
end_pos) keeps it from reaching the server. Merge both.redfs-ubuntu-resolute-7.0.0-14.14needs the same change.Testing
brlock_mh.pyran on tyan-h4-u7..u12: three writer hosts and three hosts that only verify, with kernel 6.17.0-40 and a DKMS build of red-client-fs 2.5.1~alpha.1. The stock module corrupted data at iteration 2596 in the untraced run and at iteration 86 in the traced run.--midsync, 1 h--midsynccallssync_file_rangeafter each pwrite while the grant is held. Each writer host then re-reads its own page cache before fsync, to catch a zeroed folio that stayed uptodate. That early check found 0 failures.🤖 Generated with Claude Code