diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2016-07-21 22:10:53 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@oxide.computer> | 2020-07-06 15:33:58 +0000 |
commit | 3c2d4f391c2bc4b3b4126c0757329835c80781ed (patch) | |
tree | 0f5a7390fef85b088e25fa642d787d702a708038 /usr/src | |
parent | cfcec26617a5b667ad909c32c24594a670c98b2d (diff) | |
download | illumos-joyent-3c2d4f391c2bc4b3b4126c0757329835c80781ed.tar.gz |
12907 epoll_ctl can avoid EINTR entirely
Reviewed by: Ryan Zezeski <rpz@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Robert Mustacchi <rm@fingolfin.org>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/devpoll.c | 27 |
1 files changed, 27 insertions, 0 deletions
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 @@ -736,6 +736,18 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp) 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 * perform the full check against our resource limits if and only if @@ -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); |