From 80d5689f5d4588adc071138e25e9d0d5252d9b55 Mon Sep 17 00:00:00 2001 From: Patrick Mooney Date: Fri, 22 Sep 2017 23:43:19 +0000 Subject: [PATCH] 8634 epoll fails to wake on certain edge-triggered conditions 8635 epoll should not emit POLLNVAL 8636 recursive epoll should emit EPOLLRDNORM Reviewed by: Jerry Jelinek Reviewed by: Robert Mustacchi Reviewed by: Toomas Soome Reviewed by: Igor Kozhukhov Approved by: Dan McDonald --- usr/src/man/man9e/chpoll.9e | 22 ++- usr/src/uts/common/crypto/api/kcf_random.c | 4 +- usr/src/uts/common/fs/fs_subr.c | 23 ++- usr/src/uts/common/fs/ufs/ufs_vnops.c | 164 ++++++++------------- usr/src/uts/common/inet/sockmods/socksdp.c | 25 ++-- .../common/io/1394/targets/av1394/av1394_async.c | 16 +- usr/src/uts/common/io/1394/targets/dcam1394/dcam.c | 59 +++----- usr/src/uts/common/io/bpf/bpf.c | 26 ++-- usr/src/uts/common/io/bpf/net/bpfdesc.h | 1 - usr/src/uts/common/io/devpoll.c | 153 +++++++++++++++---- usr/src/uts/common/io/eventfd.c | 6 +- .../common/io/ib/clients/of/sol_ucma/sol_ucma.c | 10 +- .../common/io/ib/clients/of/sol_umad/sol_umad.c | 38 ++--- .../io/ib/clients/of/sol_uverbs/sol_uverbs_event.c | 17 ++- usr/src/uts/common/io/mem.c | 9 +- usr/src/uts/common/io/random.c | 4 +- usr/src/uts/common/io/rsm/rsm.c | 24 ++- usr/src/uts/common/io/signalfd.c | 6 +- usr/src/uts/common/io/srn.c | 10 +- usr/src/uts/common/os/streamio.c | 29 ++-- .../uts/common/sys/1394/targets/dcam1394/dcam.h | 4 +- usr/src/uts/common/xen/io/evtchn_dev.c | 11 +- usr/src/uts/common/xen/io/xpvtap.c | 12 +- usr/src/uts/intel/io/ipmi/ipmi_main.c | 8 +- 24 files changed, 374 insertions(+), 307 deletions(-) diff --git a/usr/src/man/man9e/chpoll.9e b/usr/src/man/man9e/chpoll.9e index 7b4b3edf0b..1e8aac5e81 100644 --- a/usr/src/man/man9e/chpoll.9e +++ b/usr/src/man/man9e/chpoll.9e @@ -1,10 +1,11 @@ '\" te .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved. .\" Copyright 1989 AT&T +.\" Copyright 2017 Joyent, Inc .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH CHPOLL 9E "May 7, 2008" +.TH CHPOLL 9E "Jan 18, 2017" .SH NAME chpoll \- poll entry point for a non-STREAMS character driver .SH SYNOPSIS @@ -182,13 +183,26 @@ if (specified_events_are_satisfied_now) { *reventsp = satisfied_events & events; } else { *reventsp = 0; - if (!anyyet) - *phpp = &my_local_pollhead_structure; } +if ((*reventsp == 0 && !anyyet) || (events & POLLET)) + *phpp = &my_local_pollhead_structure; return (0); .fi .in -2 +Note: Prior to the integration of \fBepoll\fR(5), which included +edge-triggering via the \fBPOLLET\fR flag, standard chpoll mechanisms would +only provide a pollhead in \fBphpp\fR if there were no matching events. +Edge-triggered polling requires that \fBpollwakeup()\fR always be called for a +resource, so if \fBPOLLET\fR is set in the \fBevents\fR of interest, the chpoll +method must yield a pollhead and prepare to issue \fBpollwakeup()\fR calls on +it. + +Drivers which are not wired up to make \fBpollwakeup()\fR calls on a pollhead +when their status changes should emit one from their \fBchpoll\fR routine. +This will exclude the resource from caching by pollers, since it cannot alert +them to new events without \fBpollwakeup()\fR notification. + .RE .RS +4 .TP @@ -252,7 +266,7 @@ associated with the \fBpollhead\fR is about to be deallocated by the number. .SH SEE ALSO .LP -\fBpoll\fR(2), \fBnochpoll\fR(9F), \fBpollwakeup\fR(9F) +\fBpoll\fR(2), \fBepoll\fR(5), \fBnochpoll\fR(9F), \fBpollwakeup\fR(9F) .sp .LP \fIWriting Device Drivers\fR diff --git a/usr/src/uts/common/crypto/api/kcf_random.c b/usr/src/uts/common/crypto/api/kcf_random.c index bc72fa984a..5f84a4952e 100644 --- a/usr/src/uts/common/crypto/api/kcf_random.c +++ b/usr/src/uts/common/crypto/api/kcf_random.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2015, Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ /* @@ -922,7 +922,7 @@ kcf_rnd_chpoll(short events, int anyyet, short *reventsp, *reventsp |= (events & (POLLIN | POLLRDNORM)); } - if (*reventsp == 0 && !anyyet) + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) *phpp = &rnd_pollhead; } diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c index 28a3866015..3249a574f7 100644 --- a/usr/src/uts/common/fs/fs_subr.c +++ b/usr/src/uts/common/fs/fs_subr.c @@ -25,7 +25,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright 2015 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ /* @@ -416,6 +416,17 @@ int 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. + */ + if (events & POLLET) { + return (EPERM); + } + *reventsp = 0; if (events & POLLIN) *reventsp |= POLLIN; @@ -427,7 +438,15 @@ fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp, *reventsp |= POLLOUT; if (events & POLLWRBAND) *reventsp |= POLLWRBAND; - *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL; + /* + * 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/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c index 898be4d7b2..801e6f26fc 100644 --- a/usr/src/uts/common/fs/ufs/ufs_vnops.c +++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1984, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015, Joyent, Inc. + * Copyright 2017 Joyent, Inc. * Copyright (c) 2016 by Delphix. All rights reserved. */ @@ -275,7 +275,7 @@ ufs_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ct) /*ARGSUSED*/ static int ufs_close(struct vnode *vp, int flag, int count, offset_t offset, - struct cred *cr, caller_context_t *ct) + struct cred *cr, caller_context_t *ct) { cleanlocks(vp, ttoproc(curthread)->p_pid, 0); cleanshares(vp, ttoproc(curthread)->p_pid); @@ -302,7 +302,7 @@ ufs_close(struct vnode *vp, int flag, int count, offset_t offset, /*ARGSUSED*/ static int ufs_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr, - struct caller_context *ct) + struct caller_context *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp; @@ -432,7 +432,7 @@ ufs_check_rewrite(struct inode *ip, struct uio *uiop, int ioflag) /*ARGSUSED*/ static int ufs_write(struct vnode *vp, struct uio *uiop, int ioflag, cred_t *cr, - caller_context_t *ct) + caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp; @@ -1993,7 +1993,7 @@ ufs_ioctl( /* ARGSUSED */ static int ufs_getattr(struct vnode *vp, struct vattr *vap, int flags, - struct cred *cr, caller_context_t *ct) + struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp; @@ -2101,12 +2101,8 @@ ufs_priv_access(void *vip, int mode, struct cred *cr) /*ARGSUSED4*/ static int -ufs_setattr( - struct vnode *vp, - struct vattr *vap, - int flags, - struct cred *cr, - caller_context_t *ct) +ufs_setattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr, + caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp = ip->i_ufsvfs; @@ -2438,7 +2434,7 @@ out: /*ARGSUSED*/ static int ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr, - caller_context_t *ct) + caller_context_t *ct) { struct inode *ip = VTOI(vp); @@ -2462,7 +2458,7 @@ ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr, /* ARGSUSED */ static int ufs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cr, - caller_context_t *ct) + caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp; @@ -2617,8 +2613,7 @@ nolockout: /* ARGSUSED */ static int -ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr, - caller_context_t *ct) +ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp = ip->i_ufsvfs; @@ -2723,8 +2718,8 @@ int ufs_lookup_idle_count = 2; /* Number of inodes to idle each time */ /* ARGSUSED */ static int ufs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, - struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr, - caller_context_t *ct, int *direntflags, pathname_t *realpnp) + struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr, + caller_context_t *ct, int *direntflags, pathname_t *realpnp) { struct inode *ip; struct inode *sip; @@ -2908,8 +2903,8 @@ out: /*ARGSUSED*/ static int ufs_create(struct vnode *dvp, char *name, struct vattr *vap, enum vcexcl excl, - int mode, struct vnode **vpp, struct cred *cr, int flag, - caller_context_t *ct, vsecattr_t *vsecp) + int mode, struct vnode **vpp, struct cred *cr, int flag, + caller_context_t *ct, vsecattr_t *vsecp) { struct inode *ip; struct inode *xip; @@ -3193,8 +3188,8 @@ out: extern int ufs_idle_max; /*ARGSUSED*/ static int -ufs_remove(struct vnode *vp, char *nm, struct cred *cr, - caller_context_t *ct, int flags) +ufs_remove(struct vnode *vp, char *nm, struct cred *cr, caller_context_t *ct, + int flags) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp = ip->i_ufsvfs; @@ -3260,7 +3255,7 @@ out: /*ARGSUSED*/ static int ufs_link(struct vnode *tdvp, struct vnode *svp, char *tnm, struct cred *cr, - caller_context_t *ct, int flags) + caller_context_t *ct, int flags) { struct inode *sip; struct inode *tdp = VTOI(tdvp); @@ -3355,14 +3350,8 @@ clock_t ufs_rename_backoff_delay = 1; /*ARGSUSED*/ static int -ufs_rename( - struct vnode *sdvp, /* old (source) parent vnode */ - char *snm, /* old (source) entry name */ - struct vnode *tdvp, /* new (target) parent vnode */ - char *tnm, /* new (target) entry name */ - struct cred *cr, - caller_context_t *ct, - int flags) +ufs_rename(struct vnode *sdvp, char *snm, struct vnode *tdvp, char *tnm, + struct cred *cr, caller_context_t *ct, int flags) { struct inode *sip = NULL; /* source inode */ struct inode *ip = NULL; /* check inode */ @@ -3761,8 +3750,8 @@ unlock: /*ARGSUSED*/ static int ufs_mkdir(struct vnode *dvp, char *dirname, struct vattr *vap, - struct vnode **vpp, struct cred *cr, caller_context_t *ct, int flags, - vsecattr_t *vsecp) + struct vnode **vpp, struct cred *cr, caller_context_t *ct, int flags, + vsecattr_t *vsecp) { struct inode *ip; struct inode *xip; @@ -3839,7 +3828,7 @@ out: /*ARGSUSED*/ static int ufs_rmdir(struct vnode *vp, char *nm, struct vnode *cdir, struct cred *cr, - caller_context_t *ct, int flags) + caller_context_t *ct, int flags) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp = ip->i_ufsvfs; @@ -3901,13 +3890,8 @@ out: /* ARGSUSED */ static int -ufs_readdir( - struct vnode *vp, - struct uio *uiop, - struct cred *cr, - int *eofp, - caller_context_t *ct, - int flags) +ufs_readdir(struct vnode *vp, struct uio *uiop, struct cred *cr, int *eofp, + caller_context_t *ct, int flags) { struct iovec *iovp; struct inode *ip; @@ -4110,14 +4094,8 @@ out: /*ARGSUSED*/ static int -ufs_symlink( - struct vnode *dvp, /* ptr to parent dir vnode */ - char *linkname, /* name of symbolic link */ - struct vattr *vap, /* attributes */ - char *target, /* target path */ - struct cred *cr, /* user credentials */ - caller_context_t *ct, - int flags) +ufs_symlink(struct vnode *dvp, char *linkname, struct vattr *vap, char *target, + struct cred *cr, caller_context_t *ct, int flags) { struct inode *ip, *dip = VTOI(dvp); struct ufsvfs *ufsvfsp = dip->i_ufsvfs; @@ -4300,8 +4278,8 @@ out: */ int ufs_rdwri(enum uio_rw rw, int ioflag, struct inode *ip, caddr_t base, - ssize_t len, offset_t offset, enum uio_seg seg, int *aresid, - struct cred *cr) + ssize_t len, offset_t offset, enum uio_seg seg, int *aresid, + struct cred *cr) { struct uio auio; struct iovec aiov; @@ -4433,8 +4411,7 @@ ufs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp) /* ARGSUSED */ static int -ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp, - caller_context_t *ct) +ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) { return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); } @@ -4442,8 +4419,8 @@ ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp, /* ARGSUSED */ static int ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag, - offset_t offset, struct flk_callback *flk_cbp, struct cred *cr, - caller_context_t *ct) + offset_t offset, struct flk_callback *flk_cbp, struct cred *cr, + caller_context_t *ct) { struct inode *ip = VTOI(vp); @@ -4465,7 +4442,7 @@ ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag, /* ARGSUSED */ static int ufs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag, - offset_t offset, cred_t *cr, caller_context_t *ct) + offset_t offset, cred_t *cr, caller_context_t *ct) { struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; struct ulockfs *ulp; @@ -4527,8 +4504,8 @@ ufs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag, /*ARGSUSED*/ static int ufs_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp, - page_t *plarr[], size_t plsz, struct seg *seg, caddr_t addr, - enum seg_rw rw, struct cred *cr, caller_context_t *ct) + page_t *plarr[], size_t plsz, struct seg *seg, caddr_t addr, + enum seg_rw rw, struct cred *cr, caller_context_t *ct) { u_offset_t uoff = (u_offset_t)off; /* type conversion */ u_offset_t pgoff; @@ -4891,7 +4868,7 @@ out: /* ARGSUSED */ static int ufs_getpage_miss(struct vnode *vp, u_offset_t off, size_t len, struct seg *seg, - caddr_t addr, page_t *pl[], size_t plsz, enum seg_rw rw, int seq) + caddr_t addr, page_t *pl[], size_t plsz, enum seg_rw rw, int seq) { struct inode *ip = VTOI(vp); page_t *pp; @@ -5109,7 +5086,7 @@ int ufs_delay = 1; /*ARGSUSED*/ static int ufs_putpage(struct vnode *vp, offset_t off, size_t len, int flags, - struct cred *cr, caller_context_t *ct) + struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); int err = 0; @@ -5191,12 +5168,8 @@ errout: */ /*ARGSUSED*/ static int -ufs_putpages( - struct vnode *vp, - offset_t off, - size_t len, - int flags, - struct cred *cr) +ufs_putpages(struct vnode *vp, offset_t off, size_t len, int flags, + struct cred *cr) { u_offset_t io_off; u_offset_t eoff; @@ -5366,13 +5339,8 @@ ufs_iodone(buf_t *bp) */ /*ARGSUSED*/ int -ufs_putapage( - struct vnode *vp, - page_t *pp, - u_offset_t *offp, - size_t *lenp, /* return values */ - int flags, - struct cred *cr) +ufs_putapage(struct vnode *vp, page_t *pp, u_offset_t *offp, size_t *lenp, + int flags, struct cred *cr) { u_offset_t io_off; u_offset_t off; @@ -5603,16 +5571,9 @@ uint64_t ufs_map_lockfs_retry_cnt; /* ARGSUSED */ static int -ufs_map(struct vnode *vp, - offset_t off, - struct as *as, - caddr_t *addrp, - size_t len, - uchar_t prot, - uchar_t maxprot, - uint_t flags, - struct cred *cr, - caller_context_t *ct) +ufs_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp, + size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr, + caller_context_t *ct) { struct segvn_crargs vn_a; struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; @@ -5728,16 +5689,9 @@ out: /* ARGSUSED */ static int -ufs_addmap(struct vnode *vp, - offset_t off, - struct as *as, - caddr_t addr, - size_t len, - uchar_t prot, - uchar_t maxprot, - uint_t flags, - struct cred *cr, - caller_context_t *ct) +ufs_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr, + size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, + struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); @@ -5754,8 +5708,8 @@ ufs_addmap(struct vnode *vp, /*ARGSUSED*/ static int ufs_delmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr, - size_t len, uint_t prot, uint_t maxprot, uint_t flags, - struct cred *cr, caller_context_t *ct) + size_t len, uint_t prot, uint_t maxprot, uint_t flags, struct cred *cr, + caller_context_t *ct) { struct inode *ip = VTOI(vp); @@ -5777,10 +5731,18 @@ struct pollhead ufs_pollhd; /* ARGSUSED */ int ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp, - caller_context_t *ct) + caller_context_t *ct) { struct ufsvfs *ufsvfsp; + /* + * Regular files reject edge-triggered pollers. + * See the comment in fs_poll() for a more detailed explanation. + */ + if (ev & POLLET) { + return (EPERM); + } + *revp = 0; ufsvfsp = VTOI(vp)->i_ufsvfs; @@ -5815,7 +5777,9 @@ ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp, if ((ev & POLLPRI) && (*revp & (POLLERR|POLLHUP))) *revp |= POLLPRI; out: - *phpp = !any && !*revp ? &ufs_pollhd : (struct pollhead *)NULL; + if (*revp == 0 && ! any) { + *phpp = &ufs_pollhd; + } return (0); } @@ -5823,7 +5787,7 @@ out: /* ARGSUSED */ static int ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr, - caller_context_t *ct) + caller_context_t *ct) { struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; struct ulockfs *ulp = NULL; @@ -5937,7 +5901,7 @@ int ufs_pageio_writes, ufs_pageio_reads; /*ARGSUSED*/ static int ufs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len, - int flags, struct cred *cr, caller_context_t *ct) + int flags, struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ufsvfs *ufsvfsp; @@ -6418,7 +6382,7 @@ save_dblks(struct inode *ip, struct ufsvfs *ufsvfsp, daddr32_t *storeblk, /* ARGSUSED */ static int ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, - struct cred *cr, caller_context_t *ct) + struct cred *cr, caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ulockfs *ulp; @@ -6450,7 +6414,7 @@ ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, /* ARGSUSED */ static int ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr, - caller_context_t *ct) + caller_context_t *ct) { struct inode *ip = VTOI(vp); struct ulockfs *ulp = NULL; diff --git a/usr/src/uts/common/inet/sockmods/socksdp.c b/usr/src/uts/common/inet/sockmods/socksdp.c index 8841bce55c..6b6ddd646a 100644 --- a/usr/src/uts/common/inet/sockmods/socksdp.c +++ b/usr/src/uts/common/inet/sockmods/socksdp.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2017 Joyent, Inc. */ #include @@ -1092,26 +1093,22 @@ sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp, * Check for errors */ if (so->so_error != 0 && - ((POLLIN|POLLRDNORM|POLLOUT) & origevents) != 0) { + ((POLLIN|POLLRDNORM|POLLOUT) & origevents) != 0) { *reventsp = (POLLIN|POLLRDNORM|POLLOUT) & origevents; - return (0); + goto done; } *reventsp = 0; + if (so->so_type != SOCK_STREAM) { + goto done; + } /* - * Don't mark socket as writable until TX queued data is - * below watermark. + * Don't mark socket writable until TX queued data is below watermark. */ - if (so->so_type == SOCK_STREAM) { - if (sdp_polldata( - (struct sdp_conn_struct_t *)so->so_proto_handle, - SDP_XMIT)) { - *reventsp |= POLLOUT & events; - } - } else { - *reventsp = 0; - goto done; + if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle, + SDP_XMIT)) { + *reventsp |= POLLOUT & events; } if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle, @@ -1124,7 +1121,7 @@ sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp, } done: - if (!*reventsp && !anyyet) { + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { *phpp = &so->so_poll_list; } diff --git a/usr/src/uts/common/io/1394/targets/av1394/av1394_async.c b/usr/src/uts/common/io/1394/targets/av1394/av1394_async.c index 4a2556177e..05356bc926 100644 --- a/usr/src/uts/common/io/1394/targets/av1394/av1394_async.c +++ b/usr/src/uts/common/io/1394/targets/av1394/av1394_async.c @@ -25,7 +25,7 @@ */ /* - * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. */ /* @@ -323,7 +323,7 @@ av1394_async_write(av1394_inst_t *avp, struct uio *uiop) /*ARGSUSED*/ int av1394_async_ioctl(av1394_inst_t *avp, int cmd, intptr_t arg, int mode, - int *rvalp) + int *rvalp) { int ret = EINVAL; @@ -350,23 +350,25 @@ av1394_async_ioctl(av1394_inst_t *avp, int cmd, intptr_t arg, int mode, return (ret); } -/*ARGSUSED*/ int av1394_async_poll(av1394_inst_t *avp, short events, int anyyet, short *reventsp, - struct pollhead **phpp) + struct pollhead **phpp) { av1394_async_t *ap = &avp->av_a; av1394_queue_t *rq = &ap->a_rq; AV1394_TNF_ENTER(av1394_async_poll); - if (events & POLLIN) { - if (av1394_peekq(rq)) + if (events & (POLLIN | POLLET)) { + if ((events & POLLIN) && av1394_peekq(rq)) { *reventsp |= POLLIN; + } if ((!*reventsp && !anyyet) || (events & POLLET)) { mutex_enter(&ap->a_mutex); - ap->a_pollevents |= POLLIN; + if (events & POLLIN) { + ap->a_pollevents |= POLLIN; + } *phpp = &ap->a_pollhead; mutex_exit(&ap->a_mutex); } diff --git a/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c b/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c index 2db4bf174b..e1acea0878 100644 --- a/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c +++ b/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c @@ -21,6 +21,7 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ @@ -1040,68 +1041,54 @@ done: } -/* - * dcam_chpoll - */ /* ARGSUSED */ int dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp) { dcam_state_t *softc_p; - int instance, ring_buff_has_data, read_ptr_id; - size_t read_ptr_pos, write_ptr_pos; - short revent; + int instance; + short revent = 0; - instance = DEV_TO_INSTANCE(dev); + /* + * Without the logic to perform wakeups (see comment below), reject + * attempts at edge-triggered polling. + */ + if (events & POLLET) { + return (EPERM); + } + instance = DEV_TO_INSTANCE(dev); softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance); if (softc_p == NULL) { return (ENXIO); } - read_ptr_id = 0; - revent = 0; + if (softc_p->ring_buff_p != NULL) { + size_t read_ptr_pos, write_ptr_pos; - if (softc_p->ring_buff_p == NULL) { - ring_buff_has_data = 0; - } else { mutex_enter(&softc_p->dcam_frame_is_done_mutex); - read_ptr_pos = - ring_buff_read_ptr_pos_get(softc_p->ring_buff_p, - read_ptr_id); - + ring_buff_read_ptr_pos_get(softc_p->ring_buff_p, 0); write_ptr_pos = ring_buff_write_ptr_pos_get(softc_p->ring_buff_p); - - if (read_ptr_pos != write_ptr_pos) { - ring_buff_has_data = 1; - } else { - ring_buff_has_data = 0; - } - mutex_exit(&softc_p->dcam_frame_is_done_mutex); - } - /* - * now check for events - */ - if ((events & POLLRDNORM) && ring_buff_has_data) { - revent |= POLLRDNORM; + if ((events & POLLRDNORM) && read_ptr_pos != write_ptr_pos) { + revent |= POLLRDNORM; + } } if ((events & POLLPRI) && softc_p->param_status) { revent |= POLLPRI; } - /* if no events have occurred */ - if (revent == 0) { - if (!anyyet) { - *phpp = &softc_p->dcam_pollhead; - } - } - + /* + * No portion of this driver was ever wired up to perform a + * pollwakeup() on an associated pollhead. The lack of an emitted + * pollhead informs poll/devpoll that the event status of this resource + * is not cacheable. + */ *reventsp = revent; return (0); diff --git a/usr/src/uts/common/io/bpf/bpf.c b/usr/src/uts/common/io/bpf/bpf.c index 92dcb545da..59c71f8d4b 100644 --- a/usr/src/uts/common/io/bpf/bpf.c +++ b/usr/src/uts/common/io/bpf/bpf.c @@ -40,6 +40,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ /* @@ -1396,20 +1397,21 @@ bpf_ifname(struct bpf_d *d, char *buffer, int bufsize) return (0); } -/* - * Support for poll() system call - * - * Return true iff the specific operation will not block indefinitely - with - * the assumption that it is safe to positively acknowledge a request for the - * ability to write to the BPF device. - * Otherwise, return false but make a note that a selnotify() must be done. - */ +/* ARGSUSED */ int bpfchpoll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp) { struct bpf_d *d = bpf_dev_get(getminor(dev)); + /* + * Until this driver is modified to issue proper pollwakeup() calls on + * its pollhead, edge-triggered polling is not allowed. + */ + if (events & POLLET) { + return (EPERM); + } + if (events & (POLLIN | POLLRDNORM)) { /* * An imitation of the FIONREAD ioctl code. @@ -1420,9 +1422,13 @@ bpfchpoll(dev_t dev, short events, int anyyet, short *reventsp, d->bd_slen != 0)) { *reventsp |= events & (POLLIN | POLLRDNORM); } else { + /* + * Until the bpf driver has been updated to include + * adequate pollwakeup() logic, no pollhead will be + * emitted here, preventing the resource from being + * cached by poll()/devpoll/epoll. + */ *reventsp = 0; - if (!anyyet) - *phpp = &d->bd_poll; /* Start the read timeout if necessary */ if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { bpf_clear_timeout(d); diff --git a/usr/src/uts/common/io/bpf/net/bpfdesc.h b/usr/src/uts/common/io/bpf/net/bpfdesc.h index bfa861e3f8..e4ff331b74 100644 --- a/usr/src/uts/common/io/bpf/net/bpfdesc.h +++ b/usr/src/uts/common/io/bpf/net/bpfdesc.h @@ -149,7 +149,6 @@ struct bpf_d { int bd_nonblock; /* non-zero for non-blocking read */ pid_t bd_pgid; /* process or group id for signal */ int bd_timedout; - struct pollhead bd_poll; timeout_id_t bd_callout; /* for BPF timeouts with select */ pid_t bd_pid; /* corresponding PID */ void *bd_sih; /* soft interrupt handle */ diff --git a/usr/src/uts/common/io/devpoll.c b/usr/src/uts/common/io/devpoll.c index 4fce431e00..4ef14a99de 100644 --- a/usr/src/uts/common/io/devpoll.c +++ b/usr/src/uts/common/io/devpoll.c @@ -25,7 +25,7 @@ /* * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright 2016 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ #include @@ -366,21 +366,36 @@ repoll: if (fp != pdp->pd_fp) { /* - * user is polling on a cached fd which was - * closed and then reused. Unfortunately - * there is no good way to inform user. - * If the file struct is also reused, we - * may not be able to detect the fd reuse - * at all. As long as this does not - * cause system failure and/or memory leak, - * we will play along. Man page states if - * user does not clean up closed fds, polling + * The user is polling on a cached fd which was + * closed and then reused. Unfortunately there + * is no good way to communicate this fact to + * the consumer. + * + * If the file struct is also reused, we may + * not be able to detect the fd reuse at all. + * As long as this does not cause system + * failure and/or memory leaks, we will play + * along. The man page states that if the user + * does not clean up closed fds, polling * results will be indeterministic. * - * XXX - perhaps log the detection of fd - * reuse? + * XXX: perhaps log the detection of fd reuse? */ pdp->pd_fp = fp; + + /* + * When this situation has been detected, it's + * likely that any existing pollhead is + * ill-suited to perform proper wake-ups. + * + * Clean up the old entry under the expectation + * that a valid one will be provided as part of + * the later VOP_POLL. + */ + if (pdp->pd_php != NULL) { + pollhead_delete(pdp->pd_php, pdp); + pdp->pd_php = NULL; + } } /* * XXX - pollrelock() logic needs to know which @@ -396,6 +411,27 @@ repoll: curthread->t_pollcache = pcp; error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, &revent, &php, NULL); + + /* + * Recheck edge-triggered descriptors which lack a + * pollhead. While this check is performed when an fd + * is added to the pollcache in dpwrite(), subsequent + * descriptor manipulation could cause a different + * resource to be present now. + */ + if ((pdp->pd_events & POLLET) && error == 0 && + pdp->pd_php == NULL && php == NULL && revent != 0) { + short levent = 0; + + /* + * The same POLLET-only VOP_POLL is used in an + * attempt to coax a pollhead from older + * driver logic. + */ + error = VOP_POLL(fp->f_vnode, POLLET, + 0, &levent, &php, NULL); + } + curthread->t_pollcache = NULL; releasef(fd); if (error != 0) { @@ -431,6 +467,16 @@ repoll: ep->data.u64 = pdp->pd_epolldata; /* + * Since POLLNVAL is a legal event for + * VOP_POLL handlers to emit, it must + * be translated epoll-legal. + */ + if (revent & POLLNVAL) { + revent &= ~POLLNVAL; + revent |= POLLERR; + } + + /* * If any of the event bits are set for * which poll and epoll representations * differ, swizzle in the native epoll @@ -488,19 +534,12 @@ repoll: } } - /* - * If POLLET is set, clear the bit in the - * bitmap -- which effectively latches the - * edge on a pollwakeup() from the driver. - */ - if (pdp->pd_events & POLLET) - BT_CLEAR(pcp->pc_bitmap, fd); - - /* - * If POLLONESHOT is set, perform the implicit - * POLLREMOVE. - */ + /* Handle special polling modes. */ if (pdp->pd_events & POLLONESHOT) { + /* + * If POLLONESHOT is set, perform the + * implicit POLLREMOVE. + */ pdp->pd_fp = NULL; pdp->pd_events = 0; @@ -511,6 +550,28 @@ repoll: } BT_CLEAR(pcp->pc_bitmap, fd); + } else if (pdp->pd_events & POLLET) { + /* + * Wire up the pollhead which should + * have been provided. Edge-triggered + * polling cannot function properly + * with drivers which do not emit one. + */ + if (php != NULL && + pdp->pd_php == NULL) { + pollhead_insert(php, pdp); + pdp->pd_php = php; + } + + /* + * If the driver has emitted a pollhead, + * clear the bit in the bitmap which + * effectively latches the edge on a + * pollwakeup() from the driver. + */ + if (pdp->pd_php != NULL) { + BT_CLEAR(pcp->pc_bitmap, fd); + } } fdcnt++; @@ -917,6 +978,32 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp) curthread->t_pollcache = pcp; error = VOP_POLL(fp->f_vnode, pfdp->events, 0, &pfdp->revents, &php, NULL); + + /* + * Edge-triggered polling requires a pollhead in order + * to initiate wake-ups properly. Drivers which are + * savvy to POLLET presence, which should include + * everything in-gate, will always emit one, regardless + * of revent status. Older drivers which only emit a + * pollhead if 'revents == 0' are given a second chance + * here via a second VOP_POLL, with only POLLET set in + * the events of interest. These circumstances should + * induce any cacheable drivers to emit a pollhead for + * wake-ups. + * + * Drivers which never emit a pollhead will simply + * disobey the exectation of edge-triggered behavior. + * This includes recursive epoll which, even on Linux, + * yields its events in a level-triggered fashion only. + */ + if ((pdp->pd_events & POLLET) && error == 0 && + php == NULL) { + short levent = 0; + + error = VOP_POLL(fp->f_vnode, POLLET, 0, + &levent, &php, NULL); + } + curthread->t_pollcache = NULL; /* * We always set the bit when this fd is cached; @@ -1458,9 +1545,21 @@ dppoll(dev_t dev, short events, int anyyet, short *reventsp, int fdcnt = 0; pollstate_t *ps = curthread->t_pollstate; - rc = dp_pcache_poll(dpep, NULL, pcp, nfds, &fdcnt); - if (rc == 0) { - *reventsp = (fdcnt > 0) ? POLLIN : 0; + /* + * Recursive polling will only emit certain events. Skip a + * scan of the pollcache if those events are not of interest. + */ + if (events & (POLLIN|POLLRDNORM)) { + rc = dp_pcache_poll(dpep, NULL, pcp, nfds, &fdcnt); + } else { + rc = 0; + fdcnt = 0; + } + + if (rc == 0 && fdcnt > 0) { + *reventsp = POLLIN|POLLRDNORM; + } else { + *reventsp = 0; } pcachelink_assoc(pcp, ps->ps_pc_stack[0]); pollstate_exit(pcp); diff --git a/usr/src/uts/common/io/eventfd.c b/usr/src/uts/common/io/eventfd.c index ac2f75885c..9b0840aa8b 100644 --- a/usr/src/uts/common/io/eventfd.c +++ b/usr/src/uts/common/io/eventfd.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2016 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ /* @@ -228,8 +228,10 @@ eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp, if (state->efd_value < EVENTFD_VALMAX) revents |= POLLWRNORM | POLLOUT; - if (!(*reventsp = revents & events) && !anyyet) + *reventsp = revents & events; + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { *phpp = &state->efd_pollhd; + } mutex_exit(&state->efd_lock); diff --git a/usr/src/uts/common/io/ib/clients/of/sol_ucma/sol_ucma.c b/usr/src/uts/common/io/ib/clients/of/sol_ucma/sol_ucma.c index a0d0e3d304..8f03a81cf5 100644 --- a/usr/src/uts/common/io/ib/clients/of/sol_ucma/sol_ucma.c +++ b/usr/src/uts/common/io/ib/clients/of/sol_ucma/sol_ucma.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2017 Joyent, Inc. */ /* @@ -766,8 +767,8 @@ sol_ucma_write(dev_t dev, struct uio *uio, cred_t *credp) } static int -sol_ucma_poll(dev_t dev, short events, int anyyet, - short *reventsp, struct pollhead **phpp) +sol_ucma_poll(dev_t dev, short events, int anyyet, short *reventsp, + struct pollhead **phpp) { minor_t minor = getminor(dev); sol_ucma_file_t *filep; @@ -785,8 +786,9 @@ sol_ucma_poll(dev_t dev, short events, int anyyet, *reventsp = POLLIN | POLLRDNORM; } else { *reventsp = 0; - if (!anyyet) - *phpp = filep->file_pollhead; + } + if ((*reventsp == 0 && !anyyet) || (events && POLLET)) { + *phpp = filep->file_pollhead; } sol_ofs_uobj_put(&filep->file_uobj); diff --git a/usr/src/uts/common/io/ib/clients/of/sol_umad/sol_umad.c b/usr/src/uts/common/io/ib/clients/of/sol_umad/sol_umad.c index 997f4e0ce0..ce440115e5 100644 --- a/usr/src/uts/common/io/ib/clients/of/sol_umad/sol_umad.c +++ b/usr/src/uts/common/io/ib/clients/of/sol_umad/sol_umad.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2017 Joyent, Inc. */ @@ -2545,40 +2546,31 @@ done: * is true if a message has been queued for the user context receive list. */ static int -umad_poll( - dev_t dev, - short events, - int anyyet, - short *reventsp, - struct pollhead **phpp) +umad_poll(dev_t dev, short events, int anyyet, short *reventsp, + struct pollhead **phpp) { - int rc = 0; - int minor; - umad_uctx_t *uctx; - umad_port_info_t *port; - umad_info_t *info; - short revent = 0; + int minor; + umad_uctx_t *uctx; + umad_info_t *info; + short revent = 0; info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE); if (info == NULL) { - rc = ENXIO; - goto err1; + return (ENXIO); } /* lookup the node and port #s */ minor = getminor(dev); if (ISSM_MINOR(minor)) { - rc = ENXIO; - goto err1; + return (ENXIO); } mutex_enter(&info->info_mutex); uctx = info->info_uctx[GET_UCTX(minor)]; mutex_exit(&info->info_mutex); ASSERT(uctx != NULL); - port = uctx->uctx_port; - ASSERT(port != NULL); + ASSERT(uctx->uctx_port != NULL); /* * Always signal ready for POLLOUT / POLLWRNORM. @@ -2595,15 +2587,11 @@ umad_poll( mutex_exit(&uctx->uctx_recv_lock); } - if (revent == 0) { - if (! anyyet) - *phpp = &uctx->uctx_pollhead; + if ((revent == 0 && !anyyet) || (events & POLLET)) { + *phpp = &uctx->uctx_pollhead; } - *reventsp = revent; -err1: - - return (rc); + return (0); } /* diff --git a/usr/src/uts/common/io/ib/clients/of/sol_uverbs/sol_uverbs_event.c b/usr/src/uts/common/io/ib/clients/of/sol_uverbs/sol_uverbs_event.c index 929b895d81..ea7b551cee 100644 --- a/usr/src/uts/common/io/ib/clients/of/sol_uverbs/sol_uverbs_event.c +++ b/usr/src/uts/common/io/ib/clients/of/sol_uverbs/sol_uverbs_event.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2017 Joyent, Inc. */ /* @@ -280,9 +281,9 @@ sol_uverbs_event_file_poll(uverbs_ufile_uobj_t *ufile, short events, } /* - * If we didn't get an event + * If we didn't get an event or are edge-triggered */ - if (revent == 0 && !anyyet) { + if ((revent == 0 && !anyyet) || (events & POLLET)) { SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "event_file_poll " "Event entry NOT available"); @@ -569,7 +570,7 @@ uverbs_async_qp_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, /* ARGSUSED */ void uverbs_async_cq_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, - enum ib_event_type code, ibt_async_event_t *event) + enum ib_event_type code, ibt_async_event_t *event) { uverbs_ucq_uobj_t *ucq; @@ -611,7 +612,7 @@ uverbs_async_cq_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, /* ARGSUSED */ void uverbs_async_srq_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, - enum ib_event_type code, ibt_async_event_t *event) + enum ib_event_type code, ibt_async_event_t *event) { uverbs_usrq_uobj_t *usrq; @@ -653,7 +654,7 @@ uverbs_async_srq_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, /* ARGSUSED */ void uverbs_async_unaff_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, - enum ib_event_type code, ibt_async_event_t *event) + enum ib_event_type code, ibt_async_event_t *event) { sol_ofs_uobj_table_t *uo_tbl = &uverbs_uctxt_uo_tbl; sol_ofs_uobj_blk_t *blk; @@ -712,7 +713,7 @@ uverbs_async_unaff_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, */ void uverbs_async_event_handler(void *clnt_private, ibt_hca_hdl_t hca_hdl, - ibt_async_code_t code, ibt_async_event_t *event) + ibt_async_code_t code, ibt_async_event_t *event) { enum ib_event_type ofa_type; sol_uverbs_ib_event_handler_t *handler; @@ -884,7 +885,7 @@ uverbs_async_event_common(uverbs_uctxt_uobj_t *uctxt, uint64_t element, */ void uverbs_release_ucq_channel(uverbs_uctxt_uobj_t *uctxt, - uverbs_ufile_uobj_t *ufile, uverbs_ucq_uobj_t *ucq) + uverbs_ufile_uobj_t *ufile, uverbs_ucq_uobj_t *ucq) { uverbs_event_t *evt; llist_head_t *entry; @@ -1043,7 +1044,7 @@ uverbs_release_uqp_uevents(uverbs_ufile_uobj_t *ufile, uverbs_uqp_uobj_t *uqp) */ void uverbs_release_usrq_uevents(uverbs_ufile_uobj_t *ufile, - uverbs_usrq_uobj_t *usrq) + uverbs_usrq_uobj_t *usrq) { uverbs_event_t *evt; llist_head_t *entry; diff --git a/usr/src/uts/common/io/mem.c b/usr/src/uts/common/io/mem.c index 2faf0794d8..950fab1272 100644 --- a/usr/src/uts/common/io/mem.c +++ b/usr/src/uts/common/io/mem.c @@ -25,7 +25,7 @@ */ /* - * Copyright (c) 2015, Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. * Copyright 2017 James S Blachly, MD */ @@ -259,10 +259,11 @@ mmchpoll(dev_t dev, short events, int anyyet, short *reventsp, POLLWRNORM | POLLRDBAND | POLLWRBAND); /* * A non NULL pollhead pointer should be returned in case - * user polls for 0 events. + * user polls for 0 events or is doing an edge-triggerd poll. */ - *phpp = !anyyet && !*reventsp ? - &mm_pollhd : (struct pollhead *)NULL; + if ((!*reventsp && !anyyet) || (events & POLLET)) { + *phpp = &mm_pollhd; + } return (0); default: /* no other devices currently support polling */ diff --git a/usr/src/uts/common/io/random.c b/usr/src/uts/common/io/random.c index c4984e956f..d79b86362c 100644 --- a/usr/src/uts/common/io/random.c +++ b/usr/src/uts/common/io/random.c @@ -20,6 +20,8 @@ * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2017 Joyent, Inc. */ @@ -329,7 +331,7 @@ rnd_chpoll(dev_t dev, short events, int anyyet, short *reventsp, * A non NULL pollhead pointer should be returned in case * user polls for 0 events. */ - if (*reventsp == 0 && !anyyet) + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) *phpp = &urnd_pollhd; break; diff --git a/usr/src/uts/common/io/rsm/rsm.c b/usr/src/uts/common/io/rsm/rsm.c index d00367ca95..4ec7d34b92 100644 --- a/usr/src/uts/common/io/rsm/rsm.c +++ b/usr/src/uts/common/io/rsm/rsm.c @@ -23,6 +23,7 @@ * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright 2017 Joyent, Inc. */ @@ -2419,9 +2420,7 @@ rsm_bind(rsmseg_t *seg, rsm_ioctlmsg_t *msg, intptr_t dataptr, int mode) static void rsm_remap_local_importers(rsm_node_id_t src_nodeid, - rsm_memseg_id_t ex_segid, - ddi_umem_cookie_t cookie) - + rsm_memseg_id_t ex_segid, ddi_umem_cookie_t cookie) { rsmresource_t *p = NULL; rsmhash_table_t *rhash = &rsm_import_segs; @@ -3644,10 +3643,8 @@ rsm_intr_segconnect(rsm_node_id_t src, rsmipc_request_t *req) * */ static void -rsm_force_unload(rsm_node_id_t src_nodeid, - rsm_memseg_id_t ex_segid, +rsm_force_unload(rsm_node_id_t src_nodeid, rsm_memseg_id_t ex_segid, boolean_t disconnect_flag) - { rsmresource_t *p = NULL; rsmhash_table_t *rhash = &rsm_import_segs; @@ -6762,7 +6759,6 @@ rsm_disconnect(rsmseg_t *seg) return (DDI_SUCCESS); } -/*ARGSUSED*/ static int rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp) @@ -6784,8 +6780,6 @@ rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp, return (ENXIO); } - *reventsp = 0; - /* * An exported segment must be in state RSM_STATE_EXPORT; an * imported segment must be in state RSM_STATE_ACTIVE. @@ -6794,7 +6788,11 @@ rsm_chpoll(dev_t dev, short events, int anyyet, short *reventsp, if (seg->s_pollevent) { *reventsp = POLLRDNORM; - } else if (!anyyet) { + } else { + *reventsp = 0; + } + + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { /* cannot take segment lock here */ *phpp = &seg->s_poll; seg->s_pollflag |= RSM_SEGMENT_POLL; @@ -8288,7 +8286,7 @@ rsmmap_access(devmap_cookie_t dhp, void *pvt, offset_t offset, size_t len, static int rsmmap_dup(devmap_cookie_t dhp, void *oldpvt, devmap_cookie_t new_dhp, - void **newpvt) + void **newpvt) { rsmseg_t *seg = (rsmseg_t *)oldpvt; rsmcookie_t *p, *old; @@ -8339,8 +8337,8 @@ rsmmap_dup(devmap_cookie_t dhp, void *oldpvt, devmap_cookie_t new_dhp, static void rsmmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, size_t len, - devmap_cookie_t new_dhp1, void **pvtp1, - devmap_cookie_t new_dhp2, void **pvtp2) + devmap_cookie_t new_dhp1, void **pvtp1, + devmap_cookie_t new_dhp2, void **pvtp2) { /* * Remove pvtp structure from segment list. diff --git a/usr/src/uts/common/io/signalfd.c b/usr/src/uts/common/io/signalfd.c index 883c81d2ce..6416d6d45a 100644 --- a/usr/src/uts/common/io/signalfd.c +++ b/usr/src/uts/common/io/signalfd.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2016 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ /* @@ -560,7 +560,6 @@ signalfd_sig_pending(proc_t *p, kthread_t *t, k_sigset_t set) set.__sigbits[2]) & FILLSET2)); } -_NOTE(ARGSUSED(4)) static int signalfd_poll(dev_t dev, short events, int anyyet, short *reventsp, struct pollhead **phpp) @@ -581,7 +580,8 @@ signalfd_poll(dev_t dev, short events, int anyyet, short *reventsp, mutex_exit(&state->sfd_lock); - if (!(*reventsp = revents & events) && !anyyet) { + *reventsp = revents & events; + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { sigfd_proc_state_t *pstate; sigfd_poll_waiter_t *pw; diff --git a/usr/src/uts/common/io/srn.c b/usr/src/uts/common/io/srn.c index b931206f69..9aaeeb9007 100644 --- a/usr/src/uts/common/io/srn.c +++ b/usr/src/uts/common/io/srn.c @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ @@ -253,7 +254,7 @@ srn_perms(int perm, cred_t *cr) static int srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, - struct pollhead **phpp) + struct pollhead **phpp) { extern struct pollhead srn_pollhead[]; int clone; @@ -263,9 +264,10 @@ srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, *reventsp |= (POLLIN | POLLRDNORM); } else { *reventsp = 0; - if (!anyyet) { - *phpp = &srn_pollhead[clone]; - } + } + + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { + *phpp = &srn_pollhead[clone]; } return (0); } diff --git a/usr/src/uts/common/os/streamio.c b/usr/src/uts/common/os/streamio.c index 62f94729cf..62569eefed 100644 --- a/usr/src/uts/common/os/streamio.c +++ b/usr/src/uts/common/os/streamio.c @@ -24,7 +24,7 @@ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. */ #include @@ -8174,12 +8174,8 @@ out: * an M_PROTO/M_PCPROTO part). */ int -strpoll( - struct stdata *stp, - short events_arg, - int anyyet, - short *reventsp, - struct pollhead **phpp) +strpoll(struct stdata *stp, short events_arg, int anyyet, short *reventsp, + struct pollhead **phpp) { int events = (ushort_t)events_arg; int retevents = 0; @@ -8316,8 +8312,7 @@ chkrd: retevents |= (events & (POLLIN | POLLRDBAND)); break; } - if (! (retevents & normevents) && - (stp->sd_wakeq & RSLEEP)) { + if (!(retevents & normevents) && (stp->sd_wakeq & RSLEEP)) { /* * Sync stream barrier read queue has data. */ @@ -8328,19 +8323,11 @@ chkrd: retevents |= normevents; } - *reventsp = (short)retevents; - if (retevents && !(events & POLLET)) { - if (headlocked) - mutex_exit(&stp->sd_lock); - return (0); - } - /* - * If poll() has not found any events yet, set up event cell - * to wake up the poll if a requested event occurs on this - * stream. Check for collisions with outstanding poll requests. + * Pass back a pollhead if no events are pending or if edge-triggering + * has been configured on this resource. */ - if (!anyyet) { + if ((retevents == 0 && !anyyet) || (events & POLLET)) { *phpp = &stp->sd_pollist; if (headlocked == 0) { if (polllock(&stp->sd_pollist, &stp->sd_lock) != 0) { @@ -8351,6 +8338,8 @@ chkrd: } stp->sd_rput_opt |= SR_POLLIN; } + + *reventsp = (short)retevents; if (headlocked) mutex_exit(&stp->sd_lock); return (0); diff --git a/usr/src/uts/common/sys/1394/targets/dcam1394/dcam.h b/usr/src/uts/common/sys/1394/targets/dcam1394/dcam.h index d5a5bb7758..6bfdc3c1ff 100644 --- a/usr/src/uts/common/sys/1394/targets/dcam1394/dcam.h +++ b/usr/src/uts/common/sys/1394/targets/dcam1394/dcam.h @@ -22,13 +22,12 @@ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ #ifndef _SYS_1394_TARGETS_DCAM1394_DCAM_H #define _SYS_1394_TARGETS_DCAM1394_DCAM_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -120,7 +119,6 @@ typedef struct dcam_state_s { int cur_frame_rate; int cur_ring_buff_capacity; int param_status; - struct pollhead dcam_pollhead; int camera_online; int pm_open_count; int pm_cable_power; diff --git a/usr/src/uts/common/xen/io/evtchn_dev.c b/usr/src/uts/common/xen/io/evtchn_dev.c index 4955875080..f8b652a341 100644 --- a/usr/src/uts/common/xen/io/evtchn_dev.c +++ b/usr/src/uts/common/xen/io/evtchn_dev.c @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ @@ -450,7 +451,6 @@ evtchndrv_poll(dev_t dev, short ev, int anyyet, short *revp, pollhead_t **phpp) short mask = 0; ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor)); - *phpp = (struct pollhead *)NULL; if (ev & POLLOUT) mask |= POLLOUT; @@ -458,13 +458,14 @@ evtchndrv_poll(dev_t dev, short ev, int anyyet, short *revp, pollhead_t **phpp) mask |= POLLERR; if (ev & (POLLIN | POLLRDNORM)) { mutex_enter(&ep->evtchn_lock); - if (ep->ring_cons != ep->ring_prod) + if (ep->ring_cons != ep->ring_prod) { mask |= (POLLIN | POLLRDNORM) & ev; - else - if (mask == 0 && !anyyet) - *phpp = &ep->evtchn_pollhead; + } mutex_exit(&ep->evtchn_lock); } + if ((mask == 0 && !anyyet) || (ev & POLLET)) { + *phpp = &ep->evtchn_pollhead; + } *revp = mask; return (0); } diff --git a/usr/src/uts/common/xen/io/xpvtap.c b/usr/src/uts/common/xen/io/xpvtap.c index 57290aa9d5..37144ad2f0 100644 --- a/usr/src/uts/common/xen/io/xpvtap.c +++ b/usr/src/uts/common/xen/io/xpvtap.c @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ @@ -656,7 +657,6 @@ xpvtap_chpoll(dev_t dev, short events, int anyyet, short *reventsp, } if (((events & (POLLIN | POLLRDNORM)) == 0) && !anyyet) { - *reventsp = 0; return (EINVAL); } @@ -664,6 +664,7 @@ xpvtap_chpoll(dev_t dev, short events, int anyyet, short *reventsp, * if we pushed requests on the user ring since the last poll, wakeup * the user app */ + *reventsp = 0; usring = &state->bt_user_ring; if (usring->ur_prod_polled != usring->ur_ring.req_prod_pvt) { @@ -677,13 +678,10 @@ xpvtap_chpoll(dev_t dev, short events, int anyyet, short *reventsp, usring->ur_prod_polled = usring->ur_ring.sring->req_prod; *reventsp = POLLIN | POLLRDNORM; + } - /* no new requests */ - } else { - *reventsp = 0; - if (!anyyet) { - *phpp = &state->bt_pollhead; - } + if ((*reventsp == 0 && !anyyet) || (events & POLLET)) { + *phpp = &state->bt_pollhead; } return (0); diff --git a/usr/src/uts/intel/io/ipmi/ipmi_main.c b/usr/src/uts/intel/io/ipmi/ipmi_main.c index 2425c250d1..1879564149 100644 --- a/usr/src/uts/intel/io/ipmi/ipmi_main.c +++ b/usr/src/uts/intel/io/ipmi/ipmi_main.c @@ -20,7 +20,7 @@ */ /* - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ @@ -460,10 +460,8 @@ ipmi_poll(dev_t dv, short events, int anyyet, short *reventsp, revent |= POLLERR; } - if (revent == 0) { - /* nothing has occurred */ - if (!anyyet) - *phpp = dev->ipmi_pollhead; + if ((revent == 0 && !anyyet) || (events & POLLET)) { + *phpp = dev->ipmi_pollhead; } *reventsp = revent; -- 2.11.4.GIT