git: eafe5967ac55 - main - unix: fix EVFILT_WRITE when peer close(2)s and shutdown(2)s
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 21 May 2025 02:55:39 UTC
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=eafe5967ac558de142d91660e18e9238289890e3 commit eafe5967ac558de142d91660e18e9238289890e3 Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2025-05-21 00:30:57 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2025-05-21 02:54:51 +0000 unix: fix EVFILT_WRITE when peer close(2)s and shutdown(2)s For the close(2) case restore reporting the event with EV_EOF set. This fixes bug 286692. For the shutdown(2) case restore original behavior, but leave comment that we may want to change that. The d15792780760 was not intended to bring in functional API changes. Provide tests for both cases. PR: 286692 Fixes: d15792780760ef94647af9b377b5f0a80e1826bc --- sys/kern/uipc_usrreq.c | 16 ++++++++++++--- tests/sys/kern/unix_stream.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 0836652b6a24..164030eec7ab 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1767,16 +1767,26 @@ uipc_filt_sowrite(struct knote *kn, long hint) struct socket *so = kn->kn_fp->f_data, *so2; struct unpcb *unp = sotounpcb(so), *unp2 = unp->unp_conn; - if (SOLISTENING(so) || unp2 == NULL) + if (SOLISTENING(so)) return (0); + if (unp2 == NULL) { + if (so->so_state & SS_ISDISCONNECTED) { + kn->kn_flags |= EV_EOF; + kn->kn_fflags = so->so_error; + return (1); + } else + return (0); + } + so2 = unp2->unp_socket; SOCK_RECVBUF_LOCK_ASSERT(so2); kn->kn_data = uipc_stream_sbspace(&so2->so_rcv); if (so2->so_rcv.sb_state & SBS_CANTRCVMORE) { - kn->kn_flags |= EV_EOF; - kn->kn_fflags = so->so_error; + /* + * XXXGL: maybe kn->kn_flags |= EV_EOF ? + */ return (1); } else if (kn->kn_sfflags & NOTE_LOWAT) return (kn->kn_data >= kn->kn_sdata); diff --git a/tests/sys/kern/unix_stream.c b/tests/sys/kern/unix_stream.c index 7aedf462dcce..9f750967ebf8 100644 --- a/tests/sys/kern/unix_stream.c +++ b/tests/sys/kern/unix_stream.c @@ -279,6 +279,52 @@ ATF_TC_BODY(unconnected_writability, tc) close(s); } +ATF_TC_WITHOUT_HEAD(peerclosed_writability); +ATF_TC_BODY(peerclosed_writability, tc) +{ + struct kevent kev; + int sv[2], kq; + + do_socketpair(sv); + close(sv[1]); + + check_writable_select(sv[0], 1, false); + check_writable_poll(sv[0], 1, false); + + ATF_REQUIRE(kq = kqueue()); + EV_SET(&kev, sv[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL); + ATF_REQUIRE(kevent(kq, &kev, 1, &kev, 1, NULL) == 1); + ATF_REQUIRE(kev.ident == (uintptr_t)sv[0] && + kev.filter == EVFILT_WRITE && + kev.flags == EV_EOF); + + close(sv[0]); +} + +ATF_TC_WITHOUT_HEAD(peershutdown_writability); +ATF_TC_BODY(peershutdown_writability, tc) +{ + int sv[2]; + + do_socketpair(sv); + shutdown(sv[1], SHUT_RD); + + check_writable_select(sv[0], 1, false); + check_writable_poll(sv[0], 1, false); + /* + * XXXGL: historically unix(4) sockets were not reporting peer's + * shutdown(SHUT_RD) as our EV_EOF. The kevent(2) manual page says + * "filter will set EV_EOF when the reader disconnects", which is hard + * to interpret unambigously. For now leave the historic behavior, + * but we may want to change that in uipc_usrreq.c:uipc_filt_sowrite(), + * and then this test will look like the peerclosed_writability test. + */ + check_writable_kevent(sv[0], 1, false); + + close(sv[0]); + close(sv[1]); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, getpeereid); @@ -288,6 +334,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, peershutdown_writability); return atf_no_error(); }