Re: [PATCH net v2 2/2] selftest: af_unix: Test scm_fds on dgram disconnect.
From: Siddharth Chintamaneni
Date: Sat Nov 14 2026 - 11:23:15 EST
On Fri, 13 Nov 2026 at 23:53, Kuniyuki Iwashima <kuniyu@xxxxxxxxxx> wrote:
>
> On Wed, 11 Nov 2026 22:51:48 +0000, Siddharth Chintamaneni wrote:
> > Add dgram_disconnect_fdinfo in scm_rights.c verifying that scm_fds in
> > /proc/self/fdinfo/<fd> returns to 0 when a connected SOCK_DGRAM socket
> > with queued SCM_RIGHTS datagrams disconnects via connect(AF_UNSPEC) or
> > observes a dead peer in send().
> >
> > Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@xxxxxxxxx>
> > ---
> > .../selftests/net/af_unix/scm_rights.c | 79 +++++++++++++++++++
> > 1 file changed, 79 insertions(+)
> >
> > diff --git a/tools/testing/selftests/net/af_unix/scm_rights.c b/tools/testing/selftests/net/af_unix/scm_rights.c
> > index c165f250220a..ced83d3173b7 100644
> > --- a/tools/testing/selftests/net/af_unix/scm_rights.c
> > +++ b/tools/testing/selftests/net/af_unix/scm_rights.c
> > @@ -395,4 +395,83 @@ TEST_F(scm_rights, mixed_lowpoint)
> > close_sockets(6);
> > }
> >
> > +static int count_scm_fds(struct __test_metadata *_metadata, int fd)
> > +{
> > + char path[64], *line = NULL;
> > + int scm_fds = -1, ret;
> > + size_t unused = 0;
> > + FILE *f;
> > +
> > + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
> > +
> > + f = fopen(path, "r");
> > + ASSERT_NE(NULL, f);
> > +
> > + while (getline(&line, &unused, f) != -1) {
> > + if (strncmp(line, "scm_fds:", 8))
> > + continue;
> > +
> > + ret = sscanf(line + 8, "%d", &scm_fds);
> > + ASSERT_EQ(1, ret);
> > +
> > + break;
> > + }
> > +
> > + free(line);
> > +
> > + ret = fclose(f);
> > + ASSERT_EQ(0, ret);
> > +
> > + return scm_fds;
> > +}
> > +
> > +TEST(dgram_disconnect_fdinfo)
> > +{
> > + const FIXTURE_VARIANT(scm_rights) variant = {
> > + .name = "UNIX ",
> > + .type = SOCK_DGRAM,
> > + };
> > + FIXTURE_DATA(scm_rights) self = {};
> > + struct sockaddr addr = {
> > + .sa_family = AF_UNSPEC,
> > + };
> > + int ret;
> > +
> > + ret = unshare(CLONE_NEWNET);
> > + ASSERT_EQ(0, ret);
> > + ASSERT_EQ(0, count_sockets(_metadata, &variant));
>
> nit: count_sockets() is not needed.
>
>
> > +
> > + create_socketpairs(_metadata, &self, &variant, 2);
> > +
> > + /* 1. Disconnect via connect(AF_UNSPEC) */
> > + __send_fd(_metadata, &self, &variant, 0, 0);
> > + ASSERT_EQ(2, count_scm_fds(_metadata, self.fd[0]));
> > +
> > + ret = connect(self.fd[0], &addr, sizeof(addr.sa_family));
> > + ASSERT_EQ(0, ret);
> > + ASSERT_EQ(0, count_scm_fds(_metadata, self.fd[0]));
> > +
> > + /* 2. Dead-peer disconnect via send() */
> > + __send_fd(_metadata, &self, &variant, 1, 1);
> > + ASSERT_EQ(2, count_scm_fds(_metadata, self.fd[2]));
> > +
> > + ret = close(self.fd[3]);
> > + ASSERT_EQ(0, ret);
> > +
> > + ret = send(self.fd[2], "x", 1, 0);
> > + ASSERT_EQ(-1, ret);
> > + ASSERT_EQ(ECONNREFUSED, errno);
> > + ASSERT_EQ(0, count_scm_fds(_metadata, self.fd[2]));
> > +
> > + ret = close(self.fd[0]);
> > + ASSERT_EQ(0, ret);
> > + ret = close(self.fd[1]);
> > + ASSERT_EQ(0, ret);
> > + ret = close(self.fd[2]);
> > + ASSERT_EQ(0, ret);
> > +
> > + sleep(1);
> > + ASSERT_EQ(0, count_sockets(_metadata, &variant));
>
> Same, these two lines are unnecessary.
>
> sleep() and count_sockets() in FIXTURE_TEARDOWN(scm_rights)
> were to wait GC to purge cyclic references, but this test does
> not create that.
>
Thanks for the review! I'll drop both count_sockets() calls and re-spin in it.
>
> > +}
> > +
> > TEST_HARNESS_MAIN
> > --
> > 2.43.0
> >