Date: Sun, 03 May 2026 23:09:19 +0000 From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 476805133f57 - main - unix: Make sure we signal EOF on the write side when disconnecting Message-ID: <69f7d59f.24c32.3cabcabf@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=476805133f5736c2c8638e41d2b5d8dd2c597f3a commit 476805133f5736c2c8638e41d2b5d8dd2c597f3a Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2026-05-03 15:46:22 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2026-05-03 21:51:49 +0000 unix: Make sure we signal EOF on the write side when disconnecting Add a regression test. PR: 294014 Reported by: diizzy Reviewed by: glebius MFC after: 1 week Fixes: d15792780760 ("unix: new implementation of unix/stream & unix/seqpacket") Differential Revision: https://reviews.freebsd.org/D56764 --- sys/kern/uipc_usrreq.c | 2 ++ tests/sys/kern/unix_stream.c | 77 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index d56aac883d9c..8ff9822ee9eb 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -3159,6 +3159,8 @@ unp_soisdisconnected(struct socket *so) so->so_state |= SS_ISDISCONNECTED; so->so_state &= ~SS_ISCONNECTED; so->so_rcv.uxst_peer = NULL; + selwakeuppri(&so->so_wrsel, PSOCK); + KNOTE_LOCKED(&so->so_snd.sb_sel->si_note, 0); socantrcvmore_locked(so); } diff --git a/tests/sys/kern/unix_stream.c b/tests/sys/kern/unix_stream.c index 442b766ac885..df8dd1a15f85 100644 --- a/tests/sys/kern/unix_stream.c +++ b/tests/sys/kern/unix_stream.c @@ -109,6 +109,7 @@ typedef void check_func_t(struct check_ctx *); struct check_ctx { check_func_t *method; int sv[2]; + int kq; bool timeout; union { enum { SELECT_RD, SELECT_WR } select_what; @@ -156,24 +157,47 @@ check_poll(struct check_ctx *ctx) } static void -check_kevent(struct check_ctx *ctx) +add_kevent(struct check_ctx *ctx) { struct kevent kev; - int nfds, kq; + int kq, nfds; + + if (ctx->kq <= 0) { + kq = kqueue(); + ATF_REQUIRE(kq > 0); + ctx->kq = kq; + } - ATF_REQUIRE(kq = kqueue()); EV_SET(&kev, ctx->sv[0], ctx->kev_filter, EV_ADD, 0, 0, NULL); - nfds = kevent(kq, &kev, 1, NULL, 0, NULL); + nfds = kevent(ctx->kq, &kev, 1, NULL, 0, NULL); ATF_REQUIRE_MSG(nfds == 0, "kevent() returns %d errno %d", nfds, errno); - nfds = kevent(kq, NULL, 0, &kev, 1, ctx->timeout ? +} + +static void +check_kevent(struct check_ctx *ctx) +{ + struct kevent kev; + int nfds; + + nfds = kevent(ctx->kq, NULL, 0, &kev, 1, ctx->timeout ? &(struct timespec){.tv_nsec = 1000000} : NULL); ATF_REQUIRE_MSG(nfds == ctx->nfds, "kevent() returns %d errno %d", nfds, errno); - ATF_REQUIRE(kev.ident == (uintptr_t)ctx->sv[0] && - kev.filter == ctx->kev_filter && - (kev.flags & ctx->kev_flags) == ctx->kev_flags); - close(kq); + if (nfds > 0) { + ATF_REQUIRE_EQ(kev.ident, (uintptr_t)ctx->sv[0]); + ATF_REQUIRE_EQ(kev.filter, ctx->kev_filter); + ATF_REQUIRE_EQ(kev.flags & ctx->kev_flags, ctx->kev_flags); + } + close(ctx->kq); + ctx->kq = -1; +} + +static void +add_and_check_kevent(struct check_ctx *ctx) +{ + add_kevent(ctx); + check_kevent(ctx); } static void @@ -287,7 +311,7 @@ ATF_TC_WITHOUT_HEAD(full_writability_kevent); ATF_TC_BODY(full_writability_kevent, tc) { struct check_ctx ctx = { - .method = check_kevent, + .method = add_and_check_kevent, .kev_filter = EVFILT_WRITE, }; @@ -312,7 +336,7 @@ ATF_TC_BODY(connected_writability, tc) ctx.poll_events = POLLOUT | POLLWRNORM; check_poll(&ctx); ctx.kev_filter = EVFILT_WRITE; - check_kevent(&ctx); + add_and_check_kevent(&ctx); close(ctx.sv[0]); close(ctx.sv[1]); @@ -333,13 +357,13 @@ ATF_TC_BODY(unconnected_writability, tc) ctx.poll_events = POLLOUT | POLLWRNORM; check_poll(&ctx); ctx.kev_filter = EVFILT_WRITE; - check_kevent(&ctx); + add_and_check_kevent(&ctx); close(ctx.sv[0]); } -ATF_TC_WITHOUT_HEAD(peerclosed_writability); -ATF_TC_BODY(peerclosed_writability, tc) +ATF_TC_WITHOUT_HEAD(peerclosed_writability_level); +ATF_TC_BODY(peerclosed_writability_level, tc) { struct check_ctx ctx = { .timeout = false, @@ -355,6 +379,24 @@ ATF_TC_BODY(peerclosed_writability, tc) check_poll(&ctx); ctx.kev_filter = EVFILT_WRITE; ctx.kev_flags = EV_EOF; + add_and_check_kevent(&ctx); + + close(ctx.sv[0]); +} + +ATF_TC_WITHOUT_HEAD(peerclosed_writability_edge); +ATF_TC_BODY(peerclosed_writability_edge, tc) +{ + struct check_ctx ctx = { + .timeout = false, + .nfds = 1, + }; + + do_socketpair(ctx.sv); + ctx.kev_filter = EVFILT_WRITE; + ctx.kev_flags = EV_EOF; + add_kevent(&ctx); + close(ctx.sv[1]); check_kevent(&ctx); close(ctx.sv[0]); @@ -384,7 +426,7 @@ ATF_TC_BODY(peershutdown_writability, tc) * and then this test will also expect EV_EOF in returned flags. */ ctx.kev_filter = EVFILT_WRITE; - check_kevent(&ctx); + add_and_check_kevent(&ctx); close(ctx.sv[0]); close(ctx.sv[1]); @@ -463,7 +505,7 @@ ATF_TC_WITHOUT_HEAD(peershutdown_wakeup_kevent); ATF_TC_BODY(peershutdown_wakeup_kevent, tc) { peershutdown_wakeup(&(struct check_ctx){ - .method = check_kevent, + .method = add_and_check_kevent, .kev_filter = EVFILT_READ, .kev_flags = EV_EOF, }); @@ -525,7 +567,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, full_writability_select); ATF_TP_ADD_TC(tp, full_writability_poll); ATF_TP_ADD_TC(tp, full_writability_kevent); - ATF_TP_ADD_TC(tp, peerclosed_writability); + ATF_TP_ADD_TC(tp, peerclosed_writability_level); + ATF_TP_ADD_TC(tp, peerclosed_writability_edge); ATF_TP_ADD_TC(tp, peershutdown_writability); ATF_TP_ADD_TC(tp, peershutdown_readability); ATF_TP_ADD_TC(tp, peershutdown_wakeup_select);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f7d59f.24c32.3cabcabf>
