Repository navigation
Conversation
…cks as unwritten
The write path (transaction_extent_query_or_create) and fallocate's
preallocate_range_batch always marked freshly allocated blocks unwritten.
This backend has no unwritten-to-written conversion: the first append after
such an allocation is rejected by extent_right_spine_projection with
ENOTSUP, which surfaces as EOPNOTSUPP from write(2).
Applications with preallocation hit this immediately:
- sqlite's posix_fallocate + pwrite fails with SQLITE_IOERR_WRITE and
system errno 95 ("operation not supported");
- JVM / kafka startup fails when it preallocates and then writes.
Both allocation sites already zero-fill the block (allocate_initialized_data
/ initialize_allocated_range), so publishing them as written is safe:
- write path: the block gets the caller's data right after allocation, so
publish a normal written extent;
- fallocate: add preallocate_range_batch_initialized(..., initialized_upto)
and mark blocks written only when they fall inside the range that becomes
file data (grow: up to the new EOF); blocks beyond EOF (FALLOC_FL_KEEP_SIZE)
stay unwritten so e2fsck still sees a consistent inode size.
The kernel call site passes end for mode 0 and the current size for
KEEP_SIZE. The plain preallocate_range_batch keeps its previous
all-unwritten semantics.
Verified on DragonOS with 16 OCManager containers: three consecutive
asset inserts through api -> asset-manager succeed (ids 1,2,3), a duplicate
uuid returns the UNIQUE constraint, and "operation not supported" no longer
appears.
Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
|
Reviewed against current master and Linux 6.6.139, including an independent subagent review. I am skipping this PR rather than merging it. The original application symptom deserves a fix, but the stated premise that this backend has no unwritten-to-written conversion is no longer true: Publishing initialized extents during There is also concrete CI regression evidence: No changes have been pushed and this PR has not been merged. If the application failure can still be reproduced on current master, the follow-up should target that remaining write/conversion path and preserve ordered payload, extent and size publication. |
|
Agreed, closing. We independently verified this on current master ( |
|
Re-examined along the lines of your review; the patch as written is wrong and I am not defending it. What we found on our side is a port regression, not a master gap:
So the correct change is in our branch (add the missing The only remaining upstream candidate I can see is submit-time Please tell me which you prefer: (a) I close this PR and the fallback stays in our port branch, or (b) you point me at a base (e.g. the #2560/#2562 chain) where the submit-time path still fails, and I implement that fallback there with a test. |
|
Concrete evidence for the direction above — verified on our port branch, without the ext4 change this PR proposes:
So the application failure is fully fixed by the upstream fallback alone; this PR's change is not needed for it. Unless you prefer otherwise I will close this PR. If you would still like an upstream change, the only candidate I see is the submit-time |
…y#2568 v2, DragonOS-Community#2569 findings) Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
Problem
The write path (
transaction_extent_query_or_create) andfallocate'spreallocate_range_batchmarked every freshly allocated block as an unwrittenextent, but this backend has no unwritten → written conversion. Consequently the first
append after such an allocation is rejected by
extent_right_spine_projection(
extent.rs: "last extent is unwritten" →ENOTSUP), which surfaces fromwrite(2)as
EOPNOTSUPP("operation not supported").Real-world impact (occurs on DragonOS with OCManager containers):
posix_fallocate()followed bypwrite()fails withSQLITE_IOERR_WRITEand system errno 95; every later insert keeps failing;Copying the affected file to a new inode "fixes" it, because the copy gets written
extents — consistent with the report.
Fix
Both allocation sites already zero-fill the block before publishing the extent
(
allocate_initialized_data/initialize_allocated_range), so publishing them aswritten is safe:
transaction_extent_query_or_create)fallocate(preallocate_range_batch)preallocate_range_batch_initialized(…, initialized_upto); blocks inside the range that becomes file data (mode 0: up to the new EOF) are written, blocks beyond EOF (FALLOC_FL_KEEP_SIZE) stay unwritten soe2fsckstill sees a consistent inode sizeext4/inode.rsendfor mode 0 and the current size forKEEP_SIZEThe plain
preallocate_range_batch()keeps its previous all-unwritten semantics.Verification
make kernelpasses;cargo +nightly-2026-02-24 fmt --all -- --checkclean.assets/addthroughapi → asset-manager succeed (ids 1, 2, 3); a duplicate uuid returns
UNIQUE constraint failed: assets.uuid;disk I/O error: operation not supportedno longer appears.
Notes
fallocate/direct.rs,Edit::Allocate) still publishesunwritten extents; it is not used by the journaled mount that was tested and is left
unchanged to keep this fix reviewable.