When an AF_UNIX socket is bound to a path, the resulting BoundEndpoint is
stored on the gofer inode, and other processes reach it by path: they walk
to the dentry, then pull the endpoint off its inode and connect. Crucially,
a bound socket stays connectable even when no file descriptor is holding
that path open.
The gofer refcounting invariant is: "An additional reference is held on all
synthetic dentries, and on all dentries for which endpoint is non-nil, until
they are unlinked or invalidated."
This purpose of this invariant is for a host-backed bound UDS to stay
resolvable by path even when no FD holds it. A gofer dentry at refs == 0 is
eligible for reclaim; reclaiming it tears down the inode and drops the
HostBoundEndpoint (and its host FD). So the filesystem pins every endpoint-
bearing dentry with one extra ref, held from bind until the name goes away.
This extra ref is dropped unconditionally, guarded only by `endpoint != nil`
in many places: unlinkAt, RenameAt, revalidation/invalidation, filesystem
teardown etc. (These drop paths assume that the invariant holds.)
To establish the invariant the extra ref is taken in the bind paths sure, but
we were missing a reference increment for a dentry that later comes to point
at the same endpoint-bearing inode. This can happen either due to a hard link
or another walk that lands on the same inode.
PiperOrigin-RevId: 966116353
This native test was flaking on Buildkite because it would timeout. The test
itself would pass but I think a cleanup stage would hang indefinitely. Such a
hang would only happen when one of the cleaners from uds.go:createPipeReader()
would fail with the following log:
`Failed to kick pipe reader: open /tmp/sockets930502909/pipe/out: no such
device or address`.
The connect_external_test does not even use pipes. It is unnecessary setup and
cleanup steps. Furthermore, test logs are very noisy from these such setup and
cleanup steps for tests that are not even run.
Although I am not sure why failing to kick the pipe reader would cause the test
to hang, I have split out the setup done in `CreateSocketTree()` into 3 parts:
1. Creating a UDS tree so that sandbox can connect to it.
2. Create connectors outside sandbox who connect to sockets created by sandbox.
3. Creating pipes outside the sandbox that sandbox can read/write to.
I also split the test targets into separate tests. These setup steps are only
done for their respective tests. Makes the logs more relevant, gets rid of
unnecessary steps and failures and deflakes the native connect test.
PiperOrigin-RevId: 511128400