recovery: parameterize the read primitive with ReadParams (speed/FUA/timeout)
Add ReadParams { speed: SpeedPref, fua: bool, timeout: TimeoutPref } and
thread it through read_span so every wedge-safe handler read can request a
spindle speed (SET CD SPEED issued only on change, restored to max when the
handler exits), set the READ(10) FUA bit, and pick the 10s vs 60s timeout.
- SectorSource gains read_sectors_fua (default ignores fua); Drive sets the
CDB bit, DecryptingSectorSource threads fua to its inner read.
- recovery_read gains a fua param.
- Linear becomes { direction, params }; Bisect/Jump take params. Existing
tier-0/1 instances keep identical behavior (max speed, no FUA, fast/deep).
- Scoreboard keys on the full-config String name (linear:fwd:max:fast, ...).
- FakeDisc observes speed + FUA + approach so specialist techniques are
provably exercised in later commits.
cargo test -p libfreemkv green (2193 passed).
This commit is contained in:
@@ -470,6 +470,20 @@ impl<S: SectorSource> SectorSource for DecryptingSectorSource<S> {
|
||||
count: u16,
|
||||
buf: &mut [u8],
|
||||
recovery: bool,
|
||||
) -> Result<usize> {
|
||||
// Bulk path: no Force Unit Access (the cache IS the streaming
|
||||
// throughput). FUA is a Pass-N recovery lever threaded through
|
||||
// `read_sectors_fua`.
|
||||
self.read_sectors_fua(lba, count, buf, recovery, false)
|
||||
}
|
||||
|
||||
fn read_sectors_fua(
|
||||
&mut self,
|
||||
lba: u32,
|
||||
count: u16,
|
||||
buf: &mut [u8],
|
||||
recovery: bool,
|
||||
fua: bool,
|
||||
) -> Result<usize> {
|
||||
// Defense-in-depth: AACS aligned units are 3 sectors (6144 bytes) and
|
||||
// `decrypt_sectors` anchors units at buffer offset 0. A read that does
|
||||
@@ -488,7 +502,9 @@ impl<S: SectorSource> SectorSource for DecryptingSectorSource<S> {
|
||||
return Err(crate::error::Error::DecryptFailed);
|
||||
}
|
||||
let read_t0 = std::time::Instant::now();
|
||||
let n = self.inner.read_sectors(lba, count, buf, recovery)?;
|
||||
let n = self
|
||||
.inner
|
||||
.read_sectors_fua(lba, count, buf, recovery, fua)?;
|
||||
let read_ms = read_t0.elapsed().as_millis() as u64;
|
||||
// Decrypt the bytes just read. Scheme-agnostic: `decrypt_sectors*`
|
||||
// dispatches on the keys (None / CSS / AACS) and returns the count of
|
||||
|
||||
@@ -53,6 +53,33 @@ pub trait SectorSource: Send {
|
||||
recovery: bool,
|
||||
) -> Result<usize>;
|
||||
|
||||
/// Like [`read_sectors`], but with an explicit Force Unit Access request.
|
||||
///
|
||||
/// `fua = true` asks the drive to bypass its readahead cache and physically
|
||||
/// re-fetch the medium — a Pass-N marginal-sector lever: a cached hit can
|
||||
/// mask a *stochastic* sector that would land differently off the platter on
|
||||
/// each physical read, so FuaRetry re-reads it FUA. It is never blanket-
|
||||
/// applied to the bulk path (forcing every sequential read past the cache
|
||||
/// collapses streaming throughput ~10×).
|
||||
///
|
||||
/// The default ignores `fua` and delegates to [`read_sectors`]: only a live
|
||||
/// [`Drive`] sets the CDB bit; file- / memory-backed sources have no drive
|
||||
/// cache to bypass, so FUA is meaningless to them.
|
||||
///
|
||||
/// [`read_sectors`]: SectorSource::read_sectors
|
||||
/// [`Drive`]: crate::drive::Drive
|
||||
fn read_sectors_fua(
|
||||
&mut self,
|
||||
lba: u32,
|
||||
count: u16,
|
||||
buf: &mut [u8],
|
||||
recovery: bool,
|
||||
fua: bool,
|
||||
) -> Result<usize> {
|
||||
let _ = fua;
|
||||
self.read_sectors(lba, count, buf, recovery)
|
||||
}
|
||||
|
||||
/// Optional speed control for sources that map to a physical
|
||||
/// drive. No-op for everything else.
|
||||
fn set_speed(&mut self, _kbs: u16) {}
|
||||
@@ -87,6 +114,17 @@ impl SectorSource for Box<dyn SectorSource> {
|
||||
(**self).read_sectors(lba, count, buf, recovery)
|
||||
}
|
||||
|
||||
fn read_sectors_fua(
|
||||
&mut self,
|
||||
lba: u32,
|
||||
count: u16,
|
||||
buf: &mut [u8],
|
||||
recovery: bool,
|
||||
fua: bool,
|
||||
) -> Result<usize> {
|
||||
(**self).read_sectors_fua(lba, count, buf, recovery, fua)
|
||||
}
|
||||
|
||||
fn set_speed(&mut self, kbs: u16) {
|
||||
(**self).set_speed(kbs)
|
||||
}
|
||||
@@ -107,6 +145,17 @@ impl SectorSource for &mut (dyn SectorSource + '_) {
|
||||
(**self).read_sectors(lba, count, buf, recovery)
|
||||
}
|
||||
|
||||
fn read_sectors_fua(
|
||||
&mut self,
|
||||
lba: u32,
|
||||
count: u16,
|
||||
buf: &mut [u8],
|
||||
recovery: bool,
|
||||
fua: bool,
|
||||
) -> Result<usize> {
|
||||
(**self).read_sectors_fua(lba, count, buf, recovery, fua)
|
||||
}
|
||||
|
||||
fn set_speed(&mut self, kbs: u16) {
|
||||
(**self).set_speed(kbs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user