SIGN IN SIGN UP

vfs: rebuild the epoll ready list on restore instead of saving it

EpollInstance.ready, the per-interest link into it, and the epollInterest.ready
flag that mirrors membership are all saved, but readyMu -- which protects all
three -- is state:"nosave". state.Save walks the graph without taking it, and
not every notifier is quiesced for the save: udp's Pause is a no-op, tcp's
stops only the dispatcher, and netstack timers are not enumerated by
pauseTimeLocked. A Notify landing inside the encode window is enough for the
encoder to read epi.ready at one instant and the list links at another, saving
an image in which epi.ready is false while epi is still linked into ep.ready.

On restore, epollInterest.afterLoad calls NotifyEvent, whose `if !epi.ready`
branch is taken for that interest even though its entry is already linked.
PushBack begins with SetNext(nil), so every interest queued behind it is
silently unlinked while keeping ready == true, and the `if !epi.ready` guard
then skips them forever. The victim is not the torn interest, which ends up
self-consistent, but whichever interests were queued behind it.

Measured on release-20260803.0 with an instrumented runsc: the inconsistency
appears in the restored image on failing restores only (3/3 failures, 0/9704
healthy samples), and the ready list observably collapses from 3 entries to 1
across that afterLoad while every healthy interest adds exactly one. Retrying
the restore from the same image rescues nothing (0/7), since the tear is in the
image and state.Load is deterministic.

Stop saving the list, the link and the flag. afterLoad already calls
NotifyEvent for every interest, so an empty list is rebuilt consistently and
ReadEvents re-checks real readiness immediately after; the list is a cache of a
conclusion that is recomputed on restore anyway. This mirrors the fix for the
same class of bug in tcp's epQueue (#13554), resolved by rebuilding on restore
rather than persisting a serialized intrusive list whose mutators are not fully
quiesced at save time.

This removes the consequence, not the race: state.Save still walks the graph
without readyMu, and other serialized structures protected by nosave locks
remain exposed to the same pattern.
N
NekoPunch committed
cc62901f69f38627ca3edcf6b33c69503ab35e64
Parent: 8c6bfc8