diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/fs/fs_subr.c | 40 | ||||
-rw-r--r-- | usr/src/uts/common/fs/fs_subr.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/ufs/ufs_vnops.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/devpoll.c | 7 | ||||
-rw-r--r-- | usr/src/uts/common/sys/poll_impl.h | 3 |
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) /* |