summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2016-07-21 22:10:53 +0000
committerPatrick Mooney <pmooney@oxide.computer>2020-07-06 15:33:58 +0000
commit3c2d4f391c2bc4b3b4126c0757329835c80781ed (patch)
tree0f5a7390fef85b088e25fa642d787d702a708038 /usr/src
parentcfcec26617a5b667ad909c32c24594a670c98b2d (diff)
downloadillumos-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.c27
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);