Bug #121474 ndbxfrm returns success after destination fsync fails with EIO
Submitted: 10 Oct 8:38
Reporter: Wwwwing Wwwwing Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Cluster: Cluster (NDB) storage engine Severity:S2 (Serious)
Version:MySQL/NDB 8.4.11 source, commit `99960bf OS:Any
Assigned to: CPU Architecture:Any

[10 Oct 8:38] Wwwwing Wwwwing
Description:
After copying or transforming a file, `ndbxfrm` calls the destination
transform close, destination `fsync`, and destination OS close functions, but
discards all three return values. If streaming and source finalization have
succeeded, the command returns the earlier zero result even when destination
finalization fails.

This was reproduced by returning EIO only from the first `fsync()` whose file
descriptor resolved to the exact destination path. The injector printed a
marker proving that the failure was delivered. `ndbxfrm` nevertheless exited
with status 0 and retained the destination file.

How to repeat:
Create a disposable directory, copy the attached injector into it, and compile
the path-restricted fault library:

```bash
mkdir /tmp/my44-repro
cp /path/to/ndbxfrm_fsync_fault.c /tmp/my44-repro/
cd /tmp/my44-repro
gcc -shared -fPIC -O2 -Wall -Wextra -Werror \
  ndbxfrm_fsync_fault.c -ldl -o ndbxfrm_fsync_fault.so
```

Use a source-built MySQL/NDB 8.4.11 `ndbxfrm`. The control and fault runs use
separate, previously nonexistent output paths:

```bash
NDBXFRM=/path/to/mysql-build/runtime_output_directory/ndbxfrm
printf 'ndbxfrm destination fsync reproducer\n' > plain.txt

"$NDBXFRM" --no-defaults \
  --encrypt-password=repro-only --encrypt-kdf-iter-count=1 \
  --encrypt-cipher=1 --encrypt-block-size=0 --file-block-size=512 \
  plain.txt control.ndbxfrm
echo "control_exit=$?"

export LD_PRELOAD="$PWD/ndbxfrm_fsync_fault.so"
export NDBXFRM_FAULT_TARGET="$PWD/fsync-eio.ndbxfrm"
"$NDBXFRM" --no-defaults \
  --encrypt-password=repro-only --encrypt-kdf-iter-count=1 \
  --encrypt-cipher=1 --encrypt-block-size=0 --file-block-size=512 \
  plain.txt "$NDBXFRM_FAULT_TARGET"
echo "fault_exit=$?"
test -f "$NDBXFRM_FAULT_TARGET" && echo 'fault_output_retained=yes'
```

The interposer delegates every other `fsync` call. It activates once, only
when `/proc/self/fd/FD` exactly equals `NDBXFRM_FAULT_TARGET`.

## Actual result

The observed fault output was:

```text
NDBXFRM_FAULT_INJECTED fsync fd=4 path=/tmp/my44-repro/fsync-eio.ndbxfrm errno=EIO
fault_exit=0
fault_output_retained=yes
```

The control also returned 0 but printed no injection marker. The fault output
happened to remain readable from the page cache; that does not make the failed
durability operation successful. This reproduction proves false success after
EIO, not visible corruption in this particular run.

## Expected result

If destination transform close, `fsync`, or OS close fails, `ndbxfrm` should:

1. print an error identifying destination finalization;
2. return a nonzero exit status; and
3. remove the incomplete output, or clearly preserve it only as an invalid
   artifact that automation cannot mistake for success.