# DF-3181 — failed non-forced umount of tmpfs has already truncated every file (destructive side effect before vflush)

## What

`tmpfs_unmount` (sys/vfs/tmpfs/tmpfs_vfsops.c:284-334) walks every node and
calls `tmpfs_truncate(vp, 0)` on all VREG files **before** `vflush(mp, 0,
flags)`. If `vflush` then fails (vnode still referenced → EBUSY), unmount
returns the error and the filesystem remains mounted — with every file's
contents already destroyed:

```c
	/*
	 * Flush all vnodes on the unmount.
	 *
	 * If we fail to flush, we cannot unmount, but all the nodes have
	 * already been truncated. Erroring out is the best we can do.
	 */
	error = vflush(mp, 0, flags);
	if (error != 0) {
		TMPFS_UNLOCK(tmp);
		return (error);
	}
```

The correct order is to run vflush first (which can fail harmlessly) and
only discard data once vflush has succeeded (or for MNT_FORCE).

## Trigger surface (measured on the guest)

In practice the window is *narrower than it looks*: `dounmount`
(sys/kern/vfs_syscalls.c) bails out with EBUSY at its `mnt_refs` retry loop
before `VFS_UNMOUNT` is ever called whenever an open fd's `f_nchandle`
still references the mount — an open file (even unlinked) keeps a
namecache/mount reference and shields the filesystem from
`tmpfs_unmount` entirely (demonstrated: two attempts, no truncation,
see run.log / run2.log). The truncation-then-EBUSY path requires a vnode
that is v_usecount-busy with no f_nchandle — e.g. a vnode pinned by an
in-flight VOP on another CPU racing `dounmount`, or other transient kernel
holds. Hence: not reproduced from a stable userspace state; the code order
is still unconditionally wrong and destructive whenever vflush fails.

## Reproduce attempt

```
run.sh    # mounts tmpfs, writes 4MB file, holder opens+unlinks it and
          # fstat()s every second, then `umount` (non-forced)
```
Observed: `umount: Device busy`, mount stays, holder's fd *never* shrinks
(dounmount early EBUSY shield) — see run.log/run2.log.

## Fix

Move the destructive truncate loop after a successful `vflush` (or behind
`if (error == 0)`), leaving data intact whenever the unmount fails; for
MNT_FORCE the truncation before FORCECLOSE vflush is intentional and can
stay behind `if (flags & FORCECLOSE)`.
