SocketThread connects to the socket API once, at startup
(socketthread.cpp, connect() around line 118). There is no path anywhere in
the class that dials again. Once that connection is gone, the mount stays up but
can no longer hydrate anything, for as long as it exists.
In the intended architecture the client owns the mount lifecycle, so a clean
client restart tears the mount down and brings it back. The problem is the case
where it does not: if the client crashes, or is killed, or exits without
unmounting, what is left behind is a mount that looks completely healthy —
findmnt shows it, ls and stat work, hydrated files still read — and that
fails every open of a dehydrated placeholder from then on.
Observed
Killing the client under a live mount and starting a new one on the same socket
path. The new client accepts no connection, because nothing dials it:
write: Bad file descriptor
Failed to send msg 25: V2/HYDRATE_FILE
open Failed job 25 ./test.pdf -> EIO, immediately, and for every open after
The failure itself is well-behaved: EIO straight away, no hang, no partial
file, no corruption. It is the permanence that is the problem, and the fact that
nothing about the mount indicates it has become useless.
On main specifically
socketSendMsg() calls close(_socket) on a failed write but does not set
_socket to -1, so subsequent sends write to a closed descriptor — which the
kernel may by then have reused for something else. #54 changes that to -1 and
publishes the send failure as an explicit failed state, which is what produced
the clean EIO above. Neither version reconnects.
Why I am not sending a patch
There are at least three defensible answers and the choice is yours:
- Redial with backoff. The mount survives a client restart. Costs a
reconnect loop and a decision about what to do with hydrations in flight.
- Exit and unmount when the connection drops. The mount disappears with the
client that owns it, which matches the lifecycle model in INTEGRATION.md.
Blunt, but it never leaves a mount that silently cannot work.
- Keep failing, but say so. Report it through a state the client or the
user can see, rather than only in the log of a daemon nobody is reading.
I would rather report this accurately than pick one for you.
Environment
Linux 7.1.8 (CachyOS), libfuse 3.18.2, main at 525d8c6 and the #54 branch at
0096111 — both behave the same way in this respect.
SocketThreadconnects to the socket API once, at startup(
socketthread.cpp,connect()around line 118). There is no path anywhere inthe class that dials again. Once that connection is gone, the mount stays up but
can no longer hydrate anything, for as long as it exists.
In the intended architecture the client owns the mount lifecycle, so a clean
client restart tears the mount down and brings it back. The problem is the case
where it does not: if the client crashes, or is killed, or exits without
unmounting, what is left behind is a mount that looks completely healthy —
findmntshows it,lsandstatwork, hydrated files still read — and thatfails every open of a dehydrated placeholder from then on.
Observed
Killing the client under a live mount and starting a new one on the same socket
path. The new client accepts no connection, because nothing dials it:
The failure itself is well-behaved:
EIOstraight away, no hang, no partialfile, no corruption. It is the permanence that is the problem, and the fact that
nothing about the mount indicates it has become useless.
On
mainspecificallysocketSendMsg()callsclose(_socket)on a failed write but does not set_socketto-1, so subsequent sends write to a closed descriptor — which thekernel may by then have reused for something else. #54 changes that to
-1andpublishes the send failure as an explicit failed state, which is what produced
the clean
EIOabove. Neither version reconnects.Why I am not sending a patch
There are at least three defensible answers and the choice is yours:
reconnect loop and a decision about what to do with hydrations in flight.
client that owns it, which matches the lifecycle model in
INTEGRATION.md.Blunt, but it never leaves a mount that silently cannot work.
user can see, rather than only in the log of a daemon nobody is reading.
I would rather report this accurately than pick one for you.
Environment
Linux 7.1.8 (CachyOS), libfuse 3.18.2,
mainat 525d8c6 and the #54 branch at0096111 — both behave the same way in this respect.