fix(runtime): avoid Copy to RAM worker panic

This commit is contained in:
Mikhail Chusavitin
2026-09-03 15:34:30 +03:00
parent eae5570730
commit b14417b729
3 changed files with 21 additions and 2 deletions
+9 -2
View File
@@ -401,8 +401,7 @@ func copyFileLarge(ctx context.Context, src, dst string, logFunc func(string)) e
copied += int64(n) copied += int64(n)
if shouldLogCopyProgress(copied, total, lastLogged) { if shouldLogCopyProgress(copied, total, lastLogged) {
lastLogged = copied lastLogged = copied
pct := int(float64(copied) / float64(total) * 100) maybeLogCopyProgress(logFunc, copied, total)
logFunc(fmt.Sprintf(" %s / %s (%d%%)", humanBytes(copied), humanBytes(total), pct))
} }
} }
if err == io.EOF { if err == io.EOF {
@@ -415,6 +414,14 @@ func copyFileLarge(ctx context.Context, src, dst string, logFunc func(string)) e
return out.Sync() return out.Sync()
} }
func maybeLogCopyProgress(logFunc func(string), copied, total int64) {
if logFunc == nil || total <= 0 {
return
}
pct := int(float64(copied) / float64(total) * 100)
logFunc(fmt.Sprintf(" %s / %s (%d%%)", humanBytes(copied), humanBytes(total), pct))
}
func shouldLogCopyProgress(copied, total, lastLogged int64) bool { func shouldLogCopyProgress(copied, total, lastLogged int64) bool {
if total <= 0 || copied <= 0 { if total <= 0 || copied <= 0 {
return false return false
@@ -272,3 +272,7 @@ func TestDetachInstallMedium(t *testing.T) {
} }
}) })
} }
func TestMaybeLogCopyProgressAllowsNilLogger(t *testing.T) {
maybeLogCopyProgress(nil, copyProgressLogStep, copyProgressLogStep)
}
@@ -24,6 +24,12 @@ The Linux ABI defines `LOOP_CHANGE_FD` as `0x4C06` and
`ioctlLoopChangeFD`, so every fallback reassociation called the wrong ioctl `ioctlLoopChangeFD`, so every fallback reassociation called the wrong ioctl
and received `EINVAL`. and received `EINVAL`.
The follow-up live run exposed another independent failure: copying the
remaining medium tree passes a nil progress callback to `copyFileLarge`, but
the copier called that callback unconditionally after each progress interval.
The worker therefore panicked immediately after logging "Copying remaining
medium files...", and the parent task only reported `exit status 1`.
## Decision ## Decision
- Use the correct `LOOP_CHANGE_FD` request number, `0x4C06`, and protect it - Use the correct `LOOP_CHANGE_FD` request number, `0x4C06`, and protect it
@@ -40,6 +46,8 @@ and received `EINVAL`.
- Eject the original device without unmounting the new RAM bind mount. - Eject the original device without unmounting the new RAM bind mount.
- Preserve a complete RAM copy after any failure that occurs after loop - Preserve a complete RAM copy after any failure that occurs after loop
reassociation begins, so retry never deletes a file backing a live loop. reassociation begins, so retry never deletes a file backing a live loop.
- Progress reporting is optional; bulk copies without a logger must never
panic.
## Consequences ## Consequences