fix: align the Linux fsync error with macOS, and clear three stale docs
Round 9 findings, triaged and verified against the pinned tree.
writeback_file: a bounded-fsync WorkerLost returned bare ErrorKind::Other
on Linux where macOS returns EIO. Round 8 fixed the Linux arm to return
Err at all — the right fix — but stopped short of matching the value, so
a consumer distinguishing timeout / halt / lost-worker had nothing to
branch on for the third case on one platform. Now EIO on both.
Three doc comments described the pre-fix behaviour, one of them for
longer than the bug existed:
linux.rs durable_sync still said "all three fallbacks return Ok(())"
mod.rs sync_all still said Linux silently swallows fsync failures and
callers must not treat Ok(()) as a durability barrier
mod.rs SequentialSink::finish repeated the same caveat
All three now say what the code does: a bounded-fsync failure is an Err
on every platform, so Ok(()) IS a durability barrier. A doc that
describes a fixed bug is worse than no doc — it tells a caller to write
a workaround for something that no longer exists.
au_assembly: discard_gap_before duplicated drop_marks_before's
mark-retirement body verbatim and added one statement. Mine, from
earlier today. It now calls it. Two copies of the same retirement loop
is exactly how the two call sites would drift back together.
clpi: ClpiStream's audio_format / audio_rate / video_format / video_rate
are decoded from untrusted on-disc bytes on every parse and read by
nothing. The identically-named fields consumed in disc/bluray.rs belong
to mpls::StreamEntry, not to this struct — checked, because an earlier
round wrongly called a live function dead. Deleted, along with the seven
test assertions that pinned them; the tests that pin pid, coding_type
and language remain. Also removed a section-header comment orphaned by
the get_extents deletion, describing a fixture that no longer exists.
This commit is contained in:
@@ -30,14 +30,15 @@ pub(super) fn preallocate(file: &File, size_bytes: u64) {
|
||||
);
|
||||
}
|
||||
|
||||
/// Run `fsync` on `file` with a 60 s deadline. On timeout — and
|
||||
/// likewise on halt or a lost worker — we log and return `Ok(())`: the
|
||||
/// kernel will still flush on close, so the data is best-effort durable.
|
||||
/// The alternative (trap the thread for the rest of the rip, or return
|
||||
/// an error that aborts an otherwise-complete mux) is worse, so all
|
||||
/// three fallbacks return `Ok(())`. `Ok(())` from these paths is NOT a
|
||||
/// durability barrier — the durable flush did not complete; only the
|
||||
/// hang is bounded.
|
||||
/// Run `fsync` on `file` with a 60 s deadline. On timeout, halt or a lost
|
||||
/// worker we log and return `Err` — matching macOS. POSIX gives `fsync`
|
||||
/// exactly one way to say "the data is on stable storage" and that is a zero
|
||||
/// return; a call that never reached the device has not earned it, so `Ok(())`
|
||||
/// from here means the flush completed and nothing else.
|
||||
///
|
||||
/// The kernel will still flush on close, so the data is usually durable
|
||||
/// anyway — but that is a probability, not a barrier, and a caller that needs
|
||||
/// crash-consistency has to be able to tell the difference.
|
||||
///
|
||||
/// ## fd-reuse safety
|
||||
///
|
||||
@@ -162,7 +163,10 @@ fn bounded_failure_to_result(e: crate::io::bounded::BoundedError) -> io::Result<
|
||||
target: "mux",
|
||||
"WritebackFile::sync_all fsync worker lost before completion; data NOT durably flushed, kernel will flush on close"
|
||||
);
|
||||
Err(io::Error::from(std::io::ErrorKind::Other))
|
||||
// EIO, matching the macOS sibling: a consumer distinguishing these
|
||||
// three failures does so on the same value on every platform.
|
||||
// ErrorKind::Other carries nothing a caller can branch on.
|
||||
Err(io::Error::from_raw_os_error(libc::EIO))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,15 +178,15 @@ impl WritebackFile {
|
||||
/// is left to the kernel's normal flush-on-close path — best
|
||||
/// effort, but bounded.
|
||||
///
|
||||
/// IMPORTANT — platform difference. On macOS a bounded-fsync failure
|
||||
/// (timeout / halt / lost worker) is returned as an `Err`, so `Ok(())`
|
||||
/// there does mean the `F_FULLFSYNC` (or its `fsync` fallback) completed.
|
||||
/// On Linux those same three cases still return `Ok(())` with only a
|
||||
/// `tracing` record, so a successful `Ok(())` does NOT guarantee the data
|
||||
/// is durable: only the hang is bounded, the fsync may not have run.
|
||||
/// Callers needing crash-consistency on Linux (e.g. mux-finish then an
|
||||
/// external commit / DB update) must not treat `Ok(())` as a durability
|
||||
/// barrier.
|
||||
/// A bounded-fsync failure (timeout / halt / lost worker) is returned as
|
||||
/// an `Err` on BOTH macOS and Linux, with the same `ErrorKind` per case and
|
||||
/// `EIO` for the lost worker. So `Ok(())` means the `F_FULLFSYNC` (macOS)
|
||||
/// or `fsync` (Linux) completed, on either platform, and a caller needing
|
||||
/// crash-consistency can treat it as a durability barrier.
|
||||
///
|
||||
/// Linux used to return `Ok(())` for all three failures with only a
|
||||
/// `tracing` record; that was fixed, and this doc said otherwise for
|
||||
/// longer than the bug existed.
|
||||
pub fn sync_all(&mut self) -> io::Result<()> {
|
||||
if self.seek_count > 0 {
|
||||
tracing::debug!(
|
||||
@@ -259,9 +259,8 @@ impl super::sink::SequentialSink for WritebackFile {
|
||||
/// the same work [`Self::sync_all`] does. Implemented explicitly (no
|
||||
/// blanket impl) so a `dyn SequentialSink` / `dyn RandomAccessSink`
|
||||
/// `finish()` actually finalises + fsyncs instead of hitting a no-op
|
||||
/// default. Note the bounded-fsync caveat from [`Self::sync_all`]
|
||||
/// applies: on Linux `Ok(())` is not a durability barrier if the fsync
|
||||
/// timed out or was halted.
|
||||
/// default. A bounded-fsync failure surfaces as an `Err` here, on every
|
||||
/// platform, exactly as it does from [`Self::sync_all`].
|
||||
fn finish(&mut self) -> io::Result<()> {
|
||||
self.sync_all()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user