kernel - Fix read event on file for select/poll API
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 22 Aug 2010 22:30:08 +0000 (15:30 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 22 Aug 2010 22:30:08 +0000 (15:30 -0700)
* select/poll have always returned an immediate read event on regular
  files, but kqueue is expected to only return a EVFILT_READ event
  when not sitting at the file EOF.

* The kernel adds a NOTE_OLDAPI flag which filter functions can use to
  discern between select/poll and kqueue related knotes.

* Adjust filesystem filter function to always return an immediate
  event for reads via select/poll.

* Fixes guile, which for some reason beyond our ken select()'s for a
  read event on a file.

Reported-by: Johannes Hofmann <johannes.hofmann@gmx.de>
sys/kern/sys_generic.c
sys/sys/event.h
sys/vfs/gnu/ext2fs/ext2_vnops.c
sys/vfs/hammer/hammer_vnops.c
sys/vfs/ufs/ufs_vnops.c

index 9a36c33..0bab31d 100644 (file)
@@ -915,7 +915,7 @@ select_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
                         */
                        fdp = skap->read_set;
                        filter = EVFILT_READ;
-                       fflags = 0;
+                       fflags = NOTE_OLDAPI;
                        if (fdp)
                                break;
                        ++skap->active_set;
@@ -927,7 +927,7 @@ select_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
                         */
                        fdp = skap->write_set;
                        filter = EVFILT_WRITE;
-                       fflags = 0;
+                       fflags = NOTE_OLDAPI;
                        if (fdp)
                                break;
                        ++skap->active_set;
@@ -939,7 +939,7 @@ select_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
                         */
                        fdp = skap->except_set;
                        filter = EVFILT_EXCEPT;
-                       fflags = NOTE_OOB;
+                       fflags = NOTE_OLDAPI | NOTE_OOB;
                        if (fdp)
                                break;
                        ++skap->active_set;
@@ -1253,17 +1253,17 @@ poll_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
                kev = &kevp[*events];
                if (pfd->events & (POLLIN | POLLRDNORM)) {
                        EV_SET(kev++, pfd->fd, EVFILT_READ, EV_ADD|EV_ENABLE,
-                              0, 0, (void *)(uintptr_t)
+                              NOTE_OLDAPI, 0, (void *)(uintptr_t)
                                (pkap->lwp->lwp_kqueue_serial + pkap->pfds));
                }
                if (pfd->events & (POLLOUT | POLLWRNORM)) {
                        EV_SET(kev++, pfd->fd, EVFILT_WRITE, EV_ADD|EV_ENABLE,
-                              0, 0, (void *)(uintptr_t)
+                              NOTE_OLDAPI, 0, (void *)(uintptr_t)
                                (pkap->lwp->lwp_kqueue_serial + pkap->pfds));
                }
                if (pfd->events & (POLLPRI | POLLRDBAND)) {
                        EV_SET(kev++, pfd->fd, EVFILT_EXCEPT, EV_ADD|EV_ENABLE,
-                              NOTE_OOB, 0,
+                              NOTE_OLDAPI | NOTE_OOB, 0,
                               (void *)(uintptr_t)
                                (pkap->lwp->lwp_kqueue_serial + pkap->pfds));
                }
index b568178..ae40ab0 100644 (file)
@@ -157,8 +157,12 @@ MALLOC_DECLARE(M_KQUEUE);
 /*
  * Flag indicating hint is a signal.  Used by EVFILT_SIGNAL, and also
  * shared by EVFILT_PROC  (all knotes attached to p->p_klist)
+ *
+ * NOTE_OLDAPI is used to signal that standard filters are being called
+ * from the select/poll wrapper.
  */
 #define NOTE_SIGNAL    0x08000000
+#define NOTE_OLDAPI    0x04000000      /* select/poll note */
 
 #define FILTEROP_ISFD  0x0001          /* if ident == filedescriptor */
 #define FILTEROP_MPSAFE        0x0002
index 8283e8c..bf0ec6e 100644 (file)
@@ -1982,6 +1982,7 @@ filt_ext2read(struct knote *kn, long hint)
 {
        struct vnode *vp = (struct vnode *)kn->kn_hook;
        struct inode *ip = VTOI(vp);
+       off_t off;
 
        /*
         * filesystem is gone, so set the EOF flag and schedule 
@@ -1991,8 +1992,10 @@ filt_ext2read(struct knote *kn, long hint)
                kn->kn_flags |= (EV_EOF | EV_ONESHOT);
                return (1);
        }
-
-        kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+        off = ip->i_size - kn->kn_fp->f_offset;
+       kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
+       if (kn->kn_sfflags & NOTE_OLDAPI)
+               return(1);
         return (kn->kn_data != 0);
 }
 
index d02b004..05c4084 100644 (file)
@@ -3384,10 +3384,7 @@ hammer_vop_kqfilter(struct vop_kqfilter_args *ap)
 
        kn->kn_hook = (caddr_t)vp;
 
-       /* XXX: kq token actually protects the list */
-       lwkt_gettoken(&vp->v_token);
        knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
-       lwkt_reltoken(&vp->v_token);
 
        return(0);
 }
@@ -3397,9 +3394,7 @@ filt_hammerdetach(struct knote *kn)
 {
        struct vnode *vp = (void *)kn->kn_hook;
 
-       lwkt_gettoken(&vp->v_token);
        knote_remove(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
-       lwkt_reltoken(&vp->v_token);
 }
 
 static int
@@ -3407,12 +3402,16 @@ filt_hammerread(struct knote *kn, long hint)
 {
        struct vnode *vp = (void *)kn->kn_hook;
        hammer_inode_t ip = VTOI(vp);
+       off_t off;
 
        if (hint == NOTE_REVOKE) {
                kn->kn_flags |= (EV_EOF | EV_ONESHOT);
                return(1);
        }
-       kn->kn_data = ip->ino_data.size - kn->kn_fp->f_offset;
+       off = ip->ino_data.size - kn->kn_fp->f_offset;
+       kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
+       if (kn->kn_sfflags & NOTE_OLDAPI)
+               return(1);
        return (kn->kn_data != 0);
 }
 
index 0640f4a..65fdd6d 100644 (file)
@@ -2174,6 +2174,7 @@ filt_ufsread(struct knote *kn, long hint)
 {
        struct vnode *vp = (struct vnode *)kn->kn_hook;
        struct inode *ip = VTOI(vp);
+       off_t off;
 
        /*
         * filesystem is gone, so set the EOF flag and schedule 
@@ -2184,7 +2185,10 @@ filt_ufsread(struct knote *kn, long hint)
                return (1);
        }
 
-        kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+       off = ip->i_size - kn->kn_fp->f_offset;
+       kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
+       if (kn->kn_sfflags & NOTE_OLDAPI)
+               return(1);
         return (kn->kn_data != 0);
 }