Stefan Farfeleder wrote:
> (kgdb) l *kqueue_scan+0x242
> 0xc01a1212 is in kqueue_scan
> (/freebsd/current/src/sys/kern/kern_event.c:716).
> 713             TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
> 714             while (count) {
> 715                     kn = TAILQ_FIRST(&kq->kq_head);
> translates to:          mov    (%edi),%ebx
> 716                     TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
> translates to:          cmpl   $0x0,0x8(%ebx)
> 
> This line causes the page fault because %ebx is 0.


This can't happen, at least from an "empty list" perspective,
even if kqueue_scan() is reentered, since the "marker" is an
auto allocation on the stack, and a different stack means a
different marker gets inserted (marker isn't static, so having
more than one insert of the marker won't result in only a
single insertion).

I suspect that what is hapening is that the code is being
reentered, and one marker is being treated as an event, because
of whatever garbage happens to be on the stack in the allocated
marker.

The marker is removed, and then it is not found before you hit
the end of the list.

Please try the attached patch.

-- Terry
Index: sys/event.h
===================================================================
RCS file: /cvs/src/sys/sys/event.h,v
retrieving revision 1.21
diff -c -r1.21 event.h
*** sys/event.h 29 Jun 2002 19:14:52 -0000      1.21
--- sys/event.h 5 Oct 2002 15:12:24 -0000
***************
*** 160,165 ****
--- 160,166 ----
  #define KN_QUEUED     0x02                    /* event is on queue */
  #define KN_DISABLED   0x04                    /* event is disabled */
  #define KN_DETACHED   0x08                    /* knote is detached */
+ #define KN_MARKER     0x10                    /* knote is a scan marker */
  
  #define kn_id         kn_kevent.ident
  #define kn_filter     kn_kevent.filter
Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.45
diff -c -r1.45 kern_event.c
*** kern/kern_event.c   17 Aug 2002 02:36:16 -0000      1.45
--- kern/kern_event.c   5 Oct 2002 15:13:26 -0000
***************
*** 653,658 ****
--- 653,659 ----
  
        FILE_LOCK_ASSERT(fp, MA_NOTOWNED);
  
+       marker.kn_status = KN_MARKER;
        kq = (struct kqueue *)fp->f_data;
        count = maxevents;
        if (count == 0)
***************
*** 713,718 ****
--- 714,727 ----
        TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe); 
        while (count) {
                kn = TAILQ_FIRST(&kq->kq_head);
+               /*
+                * Skip over all markers which are not ours.  This looks
+                * unsafe, but we can't hit the end of the list without
+                * hitting our own marker.
+                */
+               while ((kn->kn_status & KN_MARKER) && (kn != &marker)) {
+                       kn = TAILQ_NEXT(kn, kn_tqe);
+               }
                TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); 
                if (kn == &marker) {
                        splx(s);

Reply via email to