Skip to content

9p/xen: reconnect to the backend on resume - #36

Merged
azenla merged 4 commits into
edera/mainlinefrom
azenla/feat/9pfs-suspend-resume
Oct 18, 2026
Merged

azenla merged 4 commits into
edera/mainlinefrom
azenla/feat/9pfs-suspend-resume

Conversation

@azenla

@azenla azenla commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

9p/xen: reconnect to the backend on resume

A zone that is suspended and resumed, forked or restored comes back with its 9pfs rings gone. Today every access to the mount hangs.

  • The frontend now tears down its rings when the guest suspends, and sets them up again when the backend reappears. Requests made while it is disconnected wait for it. Requests the backend held when the rings went away fail with -EIO, because whether they took effect is not known.
  • The ring wait queue is woken with wake_up(), so a waiter that sleeps killable is not missed.
  • If the backend advertises feature-session-transfer (an Edera extension, 9P ids 200 to 203), the frontend saves the backend's fid table at suspend and keeps it in guest memory. After a fork or restore it hands the table to the new backend, so open files keep working. The frontend does not read the saved data.

Tested on Xen with a PVH zone and protect-storage from edera-dev/protect (azenla/feat/9pfs-suspend-resume-storage). A workload held a file open on a 9pfs mount and wrote to it with sync every second.

  • Ten suspend and resume cycles under heavy writes: no errors, writes continued.
  • Three forks of a busy parent: the parent and all three children kept writing through their own backends.

The frontend also publishes feature-session-transfer in its own xenstore node, so the toolstack can tell before it exports a zone whether the guest can hand its session back.

A request that does not fit in its ring sleeps in
io_wait_event_killable() until the backend frees space, but the event
handler wakes the ring with wake_up_interruptible(), which only wakes
TASK_INTERRUPTIBLE sleepers. A TASK_KILLABLE waiter therefore sleeps
until it is killed, which hangs a guest that has enough large requests
in flight to fill a ring.

Wake the ring with wake_up() so killable waiters see the freed space.

Fixes: 9523fea ("net/9p: Switch to wait_event_killable()")
Signed-off-by: Alex Zenla <alex@edera.dev>
The frontend's resume handler only warned that suspend and resume are
unsupported. After a restore its rings, grant references and event
channels are gone, yet the mounted client kept writing requests into
them, so every request on the mount hung. The next InitWait from the
backend then allocated a second frontend instance for the same device,
which no client used.

On resume, collect any replies the backend left in the rings, free the
rings, fail the requests that are still unanswered with -EIO, and
publish Initialising so that a backend which still serves the old rings
starts over. When the backend reaches InitWait, allocate and publish new
rings for the existing frontend, keeping its clients. Requests that
arrive while the frontend is not connected wait until it is, and a
rw_semaphore keeps them off the rings while a resume replaces them.

Signed-off-by: Alex Zenla <alex@edera.dev>
A forked, restored or imported domain resumes against a new backend
whose fid table is empty, while the guest's 9P clients still hold the
fids of the session they were suspended with. With the transport
reconnected every request on those fids still fails, so even an idle
mount comes back unusable.

When the backend advertises feature-session-transfer, wait at suspend
for the requests in flight to be answered, then ask the backend for its
fid table with Tsession_save and keep the pages in guest memory, where
they survive into whatever domain the guest resumes in. Once a restored
frontend's new backend connects, replay the pages with Tsession_restore
before any request can use the rings. The pages are opaque to the
frontend; the backend validates every entry as it would a walk or open.

Signed-off-by: Alex Zenla <alex@edera.dev>
@azenla
azenla marked this pull request as ready for review October 18, 2026 08:56
@azenla
azenla requested a review from a team October 18, 2026 08:57
marly-edera
marly-edera previously approved these changes Oct 18, 2026
The toolstack has to know whether a guest can carry its 9P session into a
new backend before it exports the domain, because a guest that cannot
comes back with every open file on its mounts unusable. Until now only the
backend advertised the feature, and the frontend's support was invisible
from dom0.

Publish feature-session-transfer = 1 in the frontend's own xenstore
directory, next to version and num-rings.

Signed-off-by: Alex Zenla <alex@edera.dev>
@github-actions

Copy link
Copy Markdown

Backport to edera/6.18-lts: proposed in #37

  • the checker found differences from the mainline commits (see below)
  • Claude's report asks for a decision

Run log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants