summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/fs_subr.c40
-rw-r--r--usr/src/uts/common/fs/fs_subr.h4
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vnops.c4
-rw-r--r--usr/src/uts/common/io/devpoll.c7
-rw-r--r--usr/src/uts/common/sys/poll_impl.h3
5 files changed, 36 insertions, 22 deletions
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index 3249a574f7..e3d07b595d 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -60,6 +60,9 @@
#include <acl/acl_common.h>
#include <sys/pathname.h>
+/* required for fs_reject_epoll */
+#include <sys/poll_impl.h>
+
static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
/*
@@ -406,10 +409,20 @@ fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
}
/*
- * Return the answer requested to poll() for non-device files.
- * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
+ * Unlike poll(2), epoll should reject attempts to add normal files or
+ * directories to a given handle. Most non-pseudo filesystems rely on
+ * fs_poll() as their implementation of polling behavior. Exceptions to that
+ * rule (ufs) can use fs_reject_epoll(), so they don't require access to the
+ * inner details of poll. Potential race conditions related to the poll module
+ * being loaded are avoided by implementing the check here in genunix.
*/
-struct pollhead fs_pollhd;
+boolean_t
+fs_reject_epoll()
+{
+ /* Check if the currently-active pollcache is epoll-enabled. */
+ return (curthread->t_pollcache != NULL &&
+ (curthread->t_pollcache->pc_flag & PC_EPOLL) != 0);
+}
/* ARGSUSED */
int
@@ -417,13 +430,12 @@ fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
struct pollhead **phpp, caller_context_t *ct)
{
/*
- * Reject all attempts for edge-triggered polling. These should only
- * occur when regular files are added to a /dev/poll handle which is in
- * epoll mode. The Linux epoll does not allow epoll-ing on regular
- * files at all, so rejecting EPOLLET requests is congruent with those
- * expectations.
+ * Regular filesystems should reject epollers. On the off chance that
+ * a non-epoll consumer expresses the desire for edge-triggered
+ * polling, we reject them too. Yes, the expected error for this
+ * really is EPERM.
*/
- if (events & POLLET) {
+ if (fs_reject_epoll() || (events & POLLET) != 0) {
return (EPERM);
}
@@ -438,15 +450,7 @@ fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
*reventsp |= POLLOUT;
if (events & POLLWRBAND)
*reventsp |= POLLWRBAND;
- /*
- * Emitting a pollhead without the intention of issuing pollwakeup()
- * calls against it is a recipe for trouble. It's only acceptable in
- * this case since the above logic matches practically all useful
- * events.
- */
- if (*reventsp == 0 && !anyyet) {
- *phpp = &fs_pollhd;
- }
+
return (0);
}
diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index 27c9e3d830..877dc36f9c 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -24,6 +24,7 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
*/
#ifndef _SYS_FS_SUBR_H
@@ -95,6 +96,9 @@ extern int fs_need_estale_retry(int);
extern void fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int));
extern int fs_vscan(vnode_t *, cred_t *, int);
+/* Helper function to detect when epoll checks VOP_POLL handlers */
+extern boolean_t fs_reject_epoll();
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/fs/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c
index 888e4e69bb..2be623f755 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c
@@ -5631,10 +5631,10 @@ ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp,
struct ufsvfs *ufsvfsp;
/*
- * Regular files reject edge-triggered pollers.
+ * Regular files reject epollers (and edge-triggered pollers).
* See the comment in fs_poll() for a more detailed explanation.
*/
- if (ev & POLLET) {
+ if (fs_reject_epoll() || (ev & POLLET) != 0) {
return (EPERM);
}
diff --git a/usr/src/uts/common/io/devpoll.c b/usr/src/uts/common/io/devpoll.c
index 31a2788435..7a8ab7e773 100644
--- a/usr/src/uts/common/io/devpoll.c
+++ b/usr/src/uts/common/io/devpoll.c
@@ -1170,8 +1170,13 @@ dpioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
* to turn it off for a particular open.
*/
dpep->dpe_flag |= DP_ISEPOLLCOMPAT;
- mutex_exit(&dpep->dpe_lock);
+ /* Record the epoll-enabled nature in the pollcache too */
+ mutex_enter(&pcp->pc_lock);
+ pcp->pc_flag |= PC_EPOLL;
+ mutex_exit(&pcp->pc_lock);
+
+ mutex_exit(&dpep->dpe_lock);
return (0);
}
diff --git a/usr/src/uts/common/sys/poll_impl.h b/usr/src/uts/common/sys/poll_impl.h
index 67b47f9a1e..58a9d37dbe 100644
--- a/usr/src/uts/common/sys/poll_impl.h
+++ b/usr/src/uts/common/sys/poll_impl.h
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2017 Joyent, Inc.
*/
#ifndef _SYS_POLL_IMPL_H
@@ -256,6 +256,7 @@ struct pollcache {
/* pc_flag */
#define PC_POLLWAKE 0x02 /* pollwakeup() occurred */
+#define PC_EPOLL 0x04 /* pollcache is epoll-enabled */
#if defined(_KERNEL)
/*