aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2025-09-02 20:34:12 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2025-09-02 20:34:12 +0000
commit60d5a4216b3479a2d62eb65f2cb03b799546dcbb (patch)
tree88cbb115094702b003bef5279bddcaa044f1ea8b
parent3296fda0c309c873ae37a0a4e25ded3ae04b421c (diff)
unix/stream: fix EVFILT_WRITE after we did shutdown(2)
When fixing bug 286692, the change eafe5967ac558, that fixed a case when peer side does close(), also had regressed a case when our side does shutdown(SHUT_WR). These actually are two independent code paths, and the eafe5967ac558 shouldn't have touched the second block. The removal of 'kn->kn_flags |= EV_EOF' was incorrect and the statement on original behavior in the commit message was also incorrect. Do not add back so_error setting, since I failed to find a test case that would return anything but 0 in kevent.fflags when run on stable/14. This was found with help of https://github.com/tokio-rs/mio. Add a test case into our test suite for that. Fixes: eafe5967ac558de142d91660e18e9238289890e3 Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D52327
-rw-r--r--sys/kern/uipc_usrreq.c4
-rw-r--r--tests/sys/kern/unix_stream.c24
2 files changed, 25 insertions, 3 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 19870e989437..6138e543fae7 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1807,9 +1807,7 @@ uipc_filt_sowrite(struct knote *kn, long hint)
kn->kn_data = uipc_stream_sbspace(&so2->so_rcv);
if (so2->so_rcv.sb_state & SBS_CANTRCVMORE) {
- /*
- * XXXGL: maybe kn->kn_flags |= EV_EOF ?
- */
+ 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 bb811f78f620..49d621dc5b0a 100644
--- a/tests/sys/kern/unix_stream.c
+++ b/tests/sys/kern/unix_stream.c
@@ -467,6 +467,29 @@ ATF_TC_BODY(peershutdown_wakeup_kevent, tc)
});
}
+ATF_TC_WITHOUT_HEAD(ourshutdown_kevent);
+ATF_TC_BODY(ourshutdown_kevent, tc)
+{
+ struct kevent kev;
+ int sv[2], kq;
+
+ do_socketpair(sv);
+ ATF_REQUIRE(kq = kqueue());
+
+ EV_SET(&kev, sv[1], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ ATF_REQUIRE(kevent(kq, &kev, 1, NULL, 0, NULL) == 0);
+
+ ATF_REQUIRE(shutdown(sv[1], SHUT_WR) == 0);
+
+ ATF_REQUIRE(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
+ ATF_REQUIRE(kev.ident == (uintptr_t)sv[1] &&
+ kev.filter == EVFILT_WRITE &&
+ kev.flags == EV_EOF);
+
+ close(sv[0]);
+ close(sv[1]);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getpeereid);
@@ -482,6 +505,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, peershutdown_wakeup_select);
ATF_TP_ADD_TC(tp, peershutdown_wakeup_poll);
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
+ ATF_TP_ADD_TC(tp, ourshutdown_kevent);
return atf_no_error();
}