# Pre5 Completion Report

Date: 2026-08-12

## Conclusion

| Area | Result | Notes |
|---|---|---|
| Planned source extraction | PASS | Both private cleanup helpers are present in `repo-pre-5/src/super.c`. |
| Static correctness review | PASS | No High or Medium findings; statement order and FreeBSD cleanup behavior are preserved. |
| Commit recoverability | PASS after correction | The initial split commits were non-destructively reverted and replaced by one independently revertible atomic source commit. |
| `WITH_ZSTDIO=0` build | PASS | Exit code 0, zero warnings, zero errors. |
| Module load | NOT RUN | The produced `erofs.ko` was not loaded. |
| QEMU functional testing | NOT RUN | No functional or regression test was run for Pre5. |
| Pre5 smoke test | DEFERRED | Deferred for a combined Pre5/Pre6 smoke run. |

Pre5 is complete for its planned source changes, static review, and required
build gate. This report does not claim runtime, feature, regression, or smoke
test coverage.

The final Pre5 source commit is
`4535cccaf1ca1837f0a2d1cca526e5f138a23c6d`. This report is created after that
commit and, when committed, its documentation commit will therefore follow the
final source commit.

## Scope

Pre5 directly modified `repo-pre-5`; no new repository snapshot was created.
The starting planning commit was:

```text
6421919003ecfab5317dfa70959ab81cd9bbc990
docs: plan repo-pre-5 cleanup extraction phase
```

The baseline documentation commit was:

```text
0666800fa529a8869757da85f2e69b8e1dd2c9f6
docs: record pre5 extraction baseline
```

The baseline recorded the following source identity:

```text
repo-pre-5/src/super.c blob:
c150d795df42ae4136fbd6e74c3b88903341b05a
```

The source scope was limited to extracting two existing cleanup regions from
`erofs_sb_free()` into private helpers. No feature, ABI, error handling,
locking, logging, ownership, or cleanup policy change was intended.

## Final Implementation

The final implementation is in [`src/super.c`](../src/super.c).

### Extra-device cleanup

`erofs_free_dev_context()` is a `static void` helper with exactly one
definition and one call. It contains only the existing extra-device cleanup:

```c
static void
erofs_free_dev_context(struct erofs_mount *em)
{
	unsigned int i;

	if (em->devs != NULL) {
		for (i = em->extra_devices; i > 0; --i)
			erofs_release_device_info(&em->devs[i - 1]);
		free(em->devs, M_EROFS);
	}
}
```

The reverse close order is unchanged. The primary device remains outside this
helper and is still released separately by `erofs_sb_free()`.

### Internal-inode cleanup

`erofs_drop_internal_inodes()` is a `static void` helper with exactly one
definition and one call. It contains only the existing metabox and packed
inode releases:

```c
static void
erofs_drop_internal_inodes(struct erofs_mount *em)
{
	if (em->metabox_en != NULL)
		free(em->metabox_en, M_EROFS);
	if (em->packed_inode != NULL)
		free(em->packed_inode, M_EROFS);
}
```

This remains a FreeBSD allocation cleanup path. It does not copy Linux
`iput()` or Linux inode-lifecycle semantics.

### Preserved cleanup order

The effective cleanup order remains:

```text
xattr prefixes
-> metabox
-> packed inode
-> extra devices in reverse order
-> primary device
-> mount state
```

The final caller is:

```c
static void
erofs_sb_free(struct erofs_mount *em)
{
	if (em == NULL)
		return;
	erofs_xattr_prefixes_cleanup(em);
	erofs_drop_internal_inodes(em);
	erofs_free_dev_context(em);
	erofs_release_device_info(&em->dif0);
	free(em, M_EROFS);
}
```

Static expansion of both helpers produces the baseline statement sequence.
No condition, loop direction, release function, pointer clearing, lock, errno,
log message, return value, or ownership rule was added or changed.

## Commit Timeline

| Commit | Purpose | Result |
|---|---|---|
| `6421919` | Establish the Pre5 execution plan | Baseline planning point. |
| `0666800` | Record the source baseline and validation status | Documentation only. |
| `52dca2e` | Initially extract `erofs_free_dev_context()` | Static behavior correct. |
| `e9b9fb2` | Initially extract `erofs_drop_internal_inodes()` | Static behavior correct. |
| `c406813` | Revert `e9b9fb2` | Non-destructively removed the second helper first. |
| `20733bd` | Revert `52dca2e` | Restored the exact baseline `super.c` blob. |
| `4535ccc` | Atomically introduce both cleanup helpers | Final source implementation. |

The initial two source commits were behaviorally correct. The static audit
found a commit-organization defect: after `e9b9fb2`, the earlier `52dca2e`
could not be independently reverted from the final HEAD without conflict
because both commits edited the same tightly coupled `erofs_sb_free()` region.

No history rewrite or destructive reset was used. The correction was:

1. Revert `e9b9fb2` with `c406813`.
2. Revert `52dca2e` with `20733bd`.
3. Confirm that `super.c` returned to baseline blob
   `c150d795df42ae4136fbd6e74c3b88903341b05a`.
4. Reintroduce both helpers in atomic commit `4535ccc`.

The final `super.c` blob is:

```text
03b92560bb5ef01f322b0d052f84bc3c577ef829
```

This is byte-for-byte identical to the correct source state at `e9b9fb2`.
The final commit `4535ccc` can be reverted without conflict and restores the
baseline blob.

The original plan preferred one source task per commit. That rule was adjusted
because the two extractions share one cleanup sequence and one caller region;
separate commits weakened independent rollback despite preserving behavior.
One atomic source commit provides a clearer and mechanically verifiable
rollback boundary without changing the planned source result.

## Static Review Evidence

The final independent static review result was PASS with no High or Medium
findings.

Verified properties:

- Only `repo-pre-5/src/super.c` differs from the source baseline.
- Both helpers are `static void` and each has one definition and one call.
- Extra devices are still released in reverse order before `em->devs` is
  freed.
- Metabox cleanup still precedes packed-inode cleanup.
- The primary device remains a separate release after the extra-device
  context.
- The mount state remains the final allocation released.
- Expanding both helpers recovers the original cleanup statement sequence.
- No header, exported interface, ABI, feature, condition, lock, errno, log, or
  ownership change was introduced.
- No deferred correctness, codec, descriptor, formatting, or feature work was
  mixed into Pre5.
- `repo-pre-1/`, `repo-pre-2/`, `repo-pre-3/`, `src-linux/`, planning files,
  reject records, and earlier reports remained protected from source changes.

The source result therefore satisfies the intended L2-S responsibility
extraction while preserving the necessary FreeBSD cleanup implementation.

## Build Evidence

The required build gate was executed in the existing FreeBSD 15 VM with PID
`26318`. No new VM was started for this build.

Command:

```sh
FREEBSD_SRC=/root/pre5-build-gate-20260812T125645Z/freebsd-src \
WITH_ZSTDIO=0 ./build.sh
```

Result:

| Evidence | Value |
|---|---|
| Exit code | `0` |
| Compiler warnings | `0` |
| Compiler errors | `0` |
| Build log | `repo-pre-5/build/pre5-zstdio0-20260812T125645Z/build.log` |
| Module | `repo-pre-5/build/pre5-zstdio0-20260812T125645Z/erofs.ko` |
| Module size | `78,248` bytes |
| Module SHA256 | `0a2928a711715a22dfe243a536f514395acd52af3cec5515bd4bb003e42a14ac` |

The build artifacts are under the ignored `repo-pre-5/build/` directory and
must not be committed. The module was not loaded, and the build result alone
does not establish runtime behavior.

## Not Run And Deferred

| Item | Status | Meaning |
|---|---|---|
| Load produced `erofs.ko` | NOT RUN | Module load and unload behavior were not checked. |
| QEMU functional testing | NOT RUN | No functional test VM run was performed for Pre5. |
| Feature or regression suite | NOT RUN | No feature-completeness claim is made. |
| Pre5 standalone smoke test | DEFERRED | Deferred by user direction and risk assessment. |
| Combined Pre5/Pre6 smoke test | REQUIRED LATER | Must be performed after Pre6 before claiming runtime coverage. |

The Pre5 changes only extract existing private cleanup statements, and the
static review plus build gate found no source or compiler issue requiring an
immediate standalone smoke run. To avoid duplicating a relatively expensive VM
cycle, the smoke test is deferred and will be combined with Pre6.

The combined Pre5/Pre6 smoke run must cover at least:

1. Plain and LZ4 basic build, module load, mount, read, readdir, unmount, and
   cleanup.
2. `TC099` multi-device success, missing-device failure, and device cleanup.
3. A packed-inode/metabox fixture mount and unmount path that exercises
   internal-inode cleanup.

None of these deferred checks is claimed as passed by this report.

## Residual Risk

- The compiled module has not been loaded, so loader, symbol-resolution, and
  unload behavior remain unverified for the final source commit.
- Failure and partial-initialization paths have only been reviewed statically.
- Multi-device cleanup has not been exercised at runtime after extracting
  `erofs_free_dev_context()`.
- Packed-inode and metabox cleanup has not been exercised at runtime after
  extracting `erofs_drop_internal_inodes()`.
- `WITH_ZSTDIO=1` was not built in this stage.
- No QEMU smoke, feature suite, stress test, or regression test has been run
  specifically against the final Pre5 source state.

These risks are accepted for the current stage and are carried into the
combined Pre5/Pre6 smoke gate. Until that gate runs, Pre5 should be described
as static-review PASS and `WITH_ZSTDIO=0` build PASS, not runtime PASS.
