Skip to content

Commit de6200c

Browse files
committed
Actually verify md5 on the formatted lane, and only forgive it on GCP
Checked what the formatted lane was doing before claiming it was a weaker detector, and on k8s it was not a detector at all: _run_fio_dual's job config carries ioengine, direct, bs, iodepth, numjobs, rw, size, nrfiles -- and no verify of any kind. It moved IO and checked nothing. Only the docker path verified, through the --verify=md5 hardcoded inside run_fio_test, so the two platforms were never checking the same thing and the md5 severity work applied to one of them. _run_fio_dual now takes verify= and verify_fatal=, both off by default so every existing caller is untouched. The lblk formatted lane passes verify="md5". verify_fatal follows the hardware, which is the rule you set. Where a 4K atomic write is guaranteed a mismatch is a real defect and fails the job outright; on GCP's pd-balanced disks it can be an artefact of run_fio_test's own verify_backlog, so it is recorded and triaged rather than failing the run. Same decision as _md5_severity, derived from CLUSTER_ENV in both places. Rendered all three configs to confirm: existing callers get no verify line, atomic hardware gets verify=md5 plus verify_fatal=1, GCP gets verify=md5 without it. So the two lanes now genuinely differ in what they can prove, which was the point of running both: raw crc32c is unconditional and nothing can absorb a torn write, while md5-through-a-filesystem is trusted only where the hardware earns it.
1 parent 48f0e68 commit de6200c

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

‎e2e/e2e_tests/cluster_test_base.py‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,8 +1275,19 @@ def _connect_and_mount_dual(self, lvol_name, mount_path=None,
12751275
def _run_fio_dual(self, lvol_name, mount_path=None, log_path=None,
12761276
runtime=300, name=None, rw="randrw", size="1G",
12771277
bs="4K", iodepth=1, numjobs=2, nrfiles=8,
1278-
time_based=True, **kwargs):
1279-
"""Start FIO. Returns thread (Docker) or job_name str (K8s)."""
1278+
time_based=True, verify=None, verify_fatal=False,
1279+
**kwargs):
1280+
"""Start FIO. Returns thread (Docker) or job_name str (K8s).
1281+
1282+
verify: e.g. "md5" or "crc32c". Opt-in and off by default, so existing
1283+
callers are unaffected. It is worth knowing that WITHOUT it the k8s
1284+
job does no data verification at all -- it only moves IO -- while
1285+
the docker path has always had --verify=md5 hardcoded inside
1286+
run_fio_test. The two lanes were never checking the same thing.
1287+
verify_fatal: fail the FIO job itself on a mismatch. Leave False where
1288+
a mismatch should be reported but not fail the run, which is the
1289+
case on hardware with no 4K atomic-write guarantee.
1290+
"""
12801291
fio_name = name or f"fio_{lvol_name}"
12811292

12821293
if self.k8s_test:
@@ -1288,13 +1299,19 @@ def _run_fio_dual(self, lvol_name, mount_path=None, log_path=None,
12881299
cm_name = f"fiocfg-{job_name}"
12891300

12901301
time_cfg = f"time_based\nruntime={runtime}" if time_based else ""
1302+
verify_cfg = ""
1303+
if verify:
1304+
verify_cfg = f"verify={verify}\nverify_state_save=0\n"
1305+
if verify_fatal:
1306+
verify_cfg += "verify_fatal=1\n"
12911307
fio_config = (
12921308
f"[global]\n"
12931309
f"ioengine=libaio\n"
12941310
f"direct=1\n"
12951311
f"bs={bs}\n"
12961312
f"iodepth={iodepth}\n"
12971313
f"numjobs={numjobs}\n"
1314+
f"{verify_cfg}"
12981315
f"{time_cfg}\n"
12991316
f"\n"
13001317
f"[{self._k8s_normalize_name(fio_name)[:20]}]\n"

‎e2e/e2e_tests/lblk/test_lblk.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,10 +453,22 @@ def _fs_fio(self, lvol_name, mount, tag, runtime=60):
453453
if not self.k8s_test:
454454
log = f"{self.log_path}/fio_lblk_{tag}.log"
455455

456+
# verify=md5 explicitly. Without it the k8s FIO job moves IO and checks
457+
# nothing -- only the docker path had --verify=md5, buried inside
458+
# run_fio_test -- so the "formatted" lane was not a data check on k8s
459+
# at all.
460+
#
461+
# verify_fatal follows the hardware. Where a 4K atomic write IS
462+
# guaranteed a mismatch is a real defect and should fail the job
463+
# outright; on GCP's pd-balanced disks it can be an artefact of
464+
# run_fio_test's own verify_backlog, so the mismatch is recorded and
465+
# triaged instead of failing the run. Same rule as _md5_severity, one
466+
# decision expressed in both places.
467+
fatal = self._md5_severity == "error"
456468
handle = self._run_fio_dual(
457469
lvol_name, mount_path=mount, log_path=log, runtime=runtime,
458470
name=f"lblk{tag}", rw="randrw", bs="4K", numjobs=2, nrfiles=4,
459-
size="512M")
471+
size="512M", verify="md5", verify_fatal=fatal)
460472
if hasattr(handle, "join"):
461473
handle.join()
462474

0 commit comments

Comments
 (0)