Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-3]: src/sys/arch/xen/xen Pull up revision 1.3 (requested by yamt ...



details:   https://anonhg.NetBSD.org/src/rev/340df120fe02
branches:  netbsd-3
changeset: 575366:340df120fe02
user:      tron <tron%NetBSD.org@localhost>
date:      Wed Apr 13 21:38:45 2005 +0000

description:
Pull up revision 1.3 (requested by yamt in ticket #146):
fix a bug which corrupts runqueue.
when dealing with events, which are handed to xenevt pseudo device,
don't call wakeup(9)/selnotify(9) at too high IPL.  PR/29792.

diffstat:

 sys/arch/xen/xen/xenevt.c |  184 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 145 insertions(+), 39 deletions(-)

diffs (256 lines):

diff -r 862e682dd68c -r 340df120fe02 sys/arch/xen/xen/xenevt.c
--- a/sys/arch/xen/xen/xenevt.c Wed Apr 13 21:38:38 2005 +0000
+++ b/sys/arch/xen/xen/xenevt.c Wed Apr 13 21:38:45 2005 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: xenevt.c,v 1.2 2005/03/09 22:39:21 bouyer Exp $      */
+/*      $NetBSD: xenevt.c,v 1.2.2.1 2005/04/13 21:38:45 tron Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -87,6 +87,9 @@
 #define XENEVT_RING_SIZE 2048
 #define XENEVT_RING_MASK 2047
 struct xenevt_d {
+       struct simplelock lock;
+       STAILQ_ENTRY(xenevt_d) pendingq;
+       boolean_t pending;
        u_int16_t ring[2048]; 
        u_int ring_read; /* pointer of the reader */
        u_int ring_write; /* pointer of the writer */
@@ -98,6 +101,13 @@
 /* event -> user device mapping */
 static struct xenevt_d *devevent[NR_EVENT_CHANNELS];
 
+/* pending events */
+struct simplelock devevent_pending_lock = SIMPLELOCK_INITIALIZER;
+STAILQ_HEAD(, xenevt_d) devevent_pending =
+    STAILQ_HEAD_INITIALIZER(devevent_pending);
+
+static void xenevt_donotify(struct xenevt_d *);
+static void xenevt_record(struct xenevt_d *, int);
 
 /* called at boot time */
 void
@@ -110,26 +120,94 @@
 void
 xenevt_event(int port)
 {
+       struct xenevt_d *d;
+       struct cpu_info *ci;
+
        hypervisor_mask_event(port);
        hypervisor_clear_event(port);
-       if (devevent[port] != NULL) {
-               /*
-                * This algorithm overflows for one less slot than available.
-                * Not really an issue, and the correct algorithm would be more
-                * complex
-                */
-                
-               if (devevent[port]->ring_read ==
-                   ((devevent[port]->ring_write + 1) & XENEVT_RING_MASK)) {
-                       devevent[port]->flags |= XENEVT_F_OVERFLOW;
-                       printf("xenevt_event: ring overflow port %d\n", port);
+       d = devevent[port];
+       if (d != NULL) {
+               xenevt_record(d, port);
+
+               if (d->pending) {
+                       return;
+               }
+
+               ci = curcpu();
+
+               if (ci->ci_ilevel < IPL_SOFTXENEVT) {
+                       /* fast and common path */
+                       ci->ci_isources[SIR_XENEVT]->is_evcnt.ev_count++;
+                       xenevt_donotify(d);
                } else {
-                       devevent[port]->ring[devevent[port]->ring_write] = port;
-                       devevent[port]->ring_write =
-                           (devevent[port]->ring_write + 1) & XENEVT_RING_MASK;
+                       simple_lock(&devevent_pending_lock);
+                       STAILQ_INSERT_TAIL(&devevent_pending, d, pendingq);
+                       simple_unlock(&devevent_pending_lock);
+                       d->pending = TRUE;
+                       softintr(SIR_XENEVT);
+               }
+       }
+}
+
+void
+xenevt_notify()
+{
+
+       cli();
+       simple_lock(&devevent_pending_lock);
+       while (/* CONSTCOND */ 1) {
+               struct xenevt_d *d;
+
+               d = STAILQ_FIRST(&devevent_pending);
+               if (d == NULL) {
+                       break;
                }
-               selnotify(&devevent[port]->sel, 1);
-               wakeup(&devevent[port]->ring_read);
+               STAILQ_REMOVE_HEAD(&devevent_pending, pendingq);
+               simple_unlock(&devevent_pending_lock);
+               sti();
+
+               d->pending = FALSE;
+               xenevt_donotify(d);
+
+               cli();
+               simple_lock(&devevent_pending_lock);
+       }
+       simple_unlock(&devevent_pending_lock);
+       sti();
+}
+
+static void
+xenevt_donotify(struct xenevt_d *d)
+{
+       int s;
+
+       s = splsoftxenevt();
+       simple_lock(&d->lock);
+        
+       selnotify(&d->sel, 1);
+       wakeup(&d->ring_read);
+
+       simple_unlock(&d->lock);
+       splx(s);
+}
+
+static void
+xenevt_record(struct xenevt_d *d, int port)
+{
+
+       /*
+        * This algorithm overflows for one less slot than available.
+        * Not really an issue, and the correct algorithm would be more
+        * complex
+        */
+
+       if (d->ring_read ==
+           ((d->ring_write + 1) & XENEVT_RING_MASK)) {
+               d->flags |= XENEVT_F_OVERFLOW;
+               printf("xenevt_event: ring overflow port %d\n", port);
+       } else {
+               d->ring[d->ring_write] = port;
+               d->ring_write = (d->ring_write + 1) & XENEVT_RING_MASK;
        }
 }
 
@@ -146,6 +224,7 @@
                return error;
 
        d = malloc(sizeof(*d), M_DEVBUF, M_WAITOK | M_ZERO);
+       simple_lock_init(&d->lock);
 
        return fdclone(p, fp, fd, flags, &xenevt_fileops, d);
 }
@@ -175,45 +254,71 @@
        struct xenevt_d *d = fp->f_data;
        int error;
        size_t len, uio_len;
+       int ring_read;
+       int ring_write;
+       int s;
 
-       while (d->ring_read == d->ring_write) {
-               if (d->flags & XENEVT_F_OVERFLOW)
-                       return EFBIG;
+       error = 0;
+       s = splsoftxenevt();
+       simple_lock(&d->lock);
+       while (error == 0) {
+               ring_read = d->ring_read;
+               ring_write = d->ring_write;
+               if (ring_read != ring_write) {
+                       break;
+               }
+               if (d->flags & XENEVT_F_OVERFLOW) {
+                       break;
+               }
+
                /* nothing to read */
-               if (fp->f_flag & FNONBLOCK)
-                       return (EAGAIN);
-               error = tsleep(&d->ring_read, PRIBIO | PCATCH, "xenevt", 0);
-               if (error == EINTR || error == ERESTART) {
-                       return(error);
+               if (fp->f_flag & FNONBLOCK) {
+                       error = EAGAIN;
+               } else {
+                       error = ltsleep(&d->ring_read, PRIBIO | PCATCH,
+                           "xenevt", 0, &d->lock);
                }
-               if (d->ring_read != d->ring_write)
-                       break;
+       }
+       if (error == 0 && (d->flags & XENEVT_F_OVERFLOW)) {
+               error = EFBIG;
        }
-       if (d->flags & XENEVT_F_OVERFLOW)
-               return EFBIG;
+       simple_unlock(&d->lock);
+       splx(s);
+
+       if (error) {
+               return error;
+       }
 
        uio_len = uio->uio_resid >> 1; 
-       if (d->ring_read <= d->ring_write)
-               len = d->ring_write - d->ring_read;
+       if (ring_read <= ring_write)
+               len = ring_write - ring_read;
        else
-               len = XENEVT_RING_SIZE - d->ring_read;
+               len = XENEVT_RING_SIZE - ring_read;
        if (len > uio_len)
                len = uio_len;
-       error = uiomove(&d->ring[d->ring_read], len << 1, uio);
+       error = uiomove(&d->ring[ring_read], len << 1, uio);
        if (error)
                return error;
-       d->ring_read = (d->ring_read + len) & XENEVT_RING_MASK;
+       ring_read = (ring_read + len) & XENEVT_RING_MASK;
        uio_len = uio->uio_resid >> 1; 
        if (uio_len == 0)
-               return 0; /* we're done */
+               goto done;
        /* ring wrapped, read the second part */
-       len = d->ring_write - d->ring_read;
+       len = ring_write - ring_read;
        if (len > uio_len)
                len = uio_len;
-       error = uiomove(&d->ring[d->ring_read], len << 1, uio);
+       error = uiomove(&d->ring[ring_read], len << 1, uio);
        if (error)
                return error;
-       d->ring_read = (d->ring_read + len) & XENEVT_RING_MASK;
+       ring_read = (ring_read + len) & XENEVT_RING_MASK;
+
+done:
+       s = splsoftxenevt();
+       simple_lock(&d->lock);
+       d->ring_read = ring_read;
+       simple_unlock(&d->lock);
+       splx(s);
+
        return 0;
 }
 
@@ -235,8 +340,9 @@
                return error;
        for (i = 0; i < nentries; i++) {
                if (chans[i] < NR_EVENT_CHANNELS &&
-                   devevent[chans[i]] == d)
+                   devevent[chans[i]] == d) {
                        hypervisor_unmask_event(chans[i]);
+               }
        }
        return 0;
 }



Home | Main Index | Thread Index | Old Index