From 3c2d4f391c2bc4b3b4126c0757329835c80781ed Mon Sep 17 00:00:00 2001 From: Patrick Mooney Date: Thu, 21 Jul 2016 22:10:53 +0000 Subject: 12907 epoll_ctl can avoid EINTR entirely Reviewed by: Ryan Zezeski Reviewed by: Jerry Jelinek Approved by: Robert Mustacchi --- usr/src/uts/common/io/devpoll.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'usr/src') diff --git a/usr/src/uts/common/io/devpoll.c b/usr/src/uts/common/io/devpoll.c index 6f9bf93226..31a2788435 100644 --- a/usr/src/uts/common/io/devpoll.c +++ b/usr/src/uts/common/io/devpoll.c @@ -735,6 +735,18 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp) uiosize = uiop->uio_resid; pollfdnum = uiosize / size; + /* + * For epoll-enabled handles, restrict the allowed write size to 2. + * This corresponds to an epoll_ctl(3C) performing an EPOLL_CTL_MOD + * operation which is expanded into two operations (DEL and ADD). + * + * All other operations performed through epoll_ctl(3C) will consist of + * a single entry. + */ + if (is_epoll && pollfdnum > 2) { + return (EINVAL); + } + /* * We want to make sure that pollfdnum isn't large enough to DoS us, * but we also don't want to grab p_lock unnecessarily -- so we @@ -794,6 +806,21 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp) while ((dpep->dpe_flag & DP_WRITER_PRESENT) != 0) { ASSERT(dpep->dpe_refcnt != 0); + /* + * The epoll API does not allow EINTR as a result when making + * modifications to the set of polled fds. Given that write + * activity is relatively quick and the size of accepted writes + * is limited above to two entries, a signal-ignorant wait is + * used here to avoid the EINTR. + */ + if (is_epoll) { + cv_wait(&dpep->dpe_cv, &dpep->dpe_lock); + continue; + } + + /* + * Non-epoll writers to /dev/poll handles can tolerate EINTR. + */ if (!cv_wait_sig_swap(&dpep->dpe_cv, &dpep->dpe_lock)) { dpep->dpe_writerwait--; mutex_exit(&dpep->dpe_lock); -- cgit v1.2.3