Now that we have a_fflag in struct vop_poll_args we can handle
things like POLLOUT on a read-only fd more sensibly. Previously,
any poll events could be used regardless of the actual file flags
of the descriptor.
Rather than call soo_poll() I've created a real fifo_poll() that
checks the socket status. With this change, POLLOUT on a read-only
fd will be ignored.
This is similar to what Linux does, though Linux will return POLLHUP
when the writer closes even when there are no valid events specified.
I have updated regress tests too...
- todd
Index: sys/miscfs/fifofs/fifo_vnops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fifofs/fifo_vnops.c,v
retrieving revision 1.45
diff -u -p -u -r1.45 fifo_vnops.c
--- sys/miscfs/fifofs/fifo_vnops.c 12 Feb 2015 14:31:02 -0000 1.45
+++ sys/miscfs/fifofs/fifo_vnops.c 4 May 2015 20:41:22 -0000
@@ -38,6 +38,7 @@
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/lock.h>
+#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
@@ -289,23 +290,46 @@ int
fifo_poll(void *v)
{
struct vop_poll_args *ap = v;
- struct file filetmp;
- const int events = ap->a_events;
+ struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
+ struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
+ int events = 0;
int revents = 0;
+ int s;
- if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
- filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
- if (filetmp.f_data)
- revents |= soo_poll(&filetmp, events, ap->a_p);
+ if (ap->a_fflag & FREAD)
+ events |= ap->a_events & (POLLIN | POLLPRI | POLLRDNORM |
POLLRDBAND);
+ if (ap->a_fflag & FWRITE)
+ events |= ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ if (events == 0)
+ return (0);
+
+ s = splsoftnet();
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (soreadable(rso))
+ revents |= events & (POLLIN | POLLRDNORM);
+ }
+ /* NOTE: POLLHUP and POLLOUT/POLLWRNORM are mutually exclusive */
+ if (rso->so_state & SS_ISDISCONNECTED) {
+ revents |= POLLHUP;
+ } else if (events & (POLLOUT | POLLWRNORM)) {
+ if (sowriteable(wso))
+ revents |= events & (POLLOUT | POLLWRNORM);
}
- /* POLLHUP and POLLOUT/POLLWRNORM/POLLWRBAND are mutually exclusive */
- if (!(revents & POLLHUP)) {
- if (events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
- filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
- if (filetmp.f_data)
- revents |= soo_poll(&filetmp, events, ap->a_p);
+ if (events & (POLLPRI | POLLRDBAND)) {
+ if (rso->so_oobmark || (rso->so_state & SS_RCVATMARK))
+ revents |= events & (POLLPRI | POLLRDBAND);
+ }
+ if (revents == 0) {
+ if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
+ selrecord(ap->a_p, &rso->so_rcv.sb_sel);
+ rso->so_rcv.sb_flagsintr |= SB_SEL;
+ }
+ if (events & (POLLOUT | POLLWRNORM)) {
+ selrecord(ap->a_p, &wso->so_snd.sb_sel);
+ wso->so_snd.sb_flagsintr |= SB_SEL;
}
}
+ splx(s);
return (revents);
}