tech-kern archive

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

Re: getiobuf(x, false) can sleep ?



On Fri, Apr 02, 2010 at 12:49:56PM +0000, Andrew Doran wrote:
> On Fri, Apr 02, 2010 at 06:30:30PM +0900, enami tsugutomo wrote:
> > > When called this way getiobuf() will do pool_cache_get(bufio_cache,
> > > PR_NOWAIT).  Does anyone see if this can sleep somewhere despite the
> > > PR_NOWAIT ?
> > 
> > The mutex_enter() in the pool_cache_get_slow()?
> 
> This cache won't sleep if PR_NOWAIT, it's interrupt safe.
> 
> You could verify the context switch theory using something like:
> 
>       uint64_t pctr;
> 
>       kpreempt_disable();
>       pctr = lwp_pctr();
>       /* do stuff */
>       KASSERT(pctr == lwp_pctr());    /* check for context switch */
>       kpreempt_enable();

I've been running with the attached patch for a day now (the workaround
for bp changing under us was already there for a couple days), and the
"dkstart: preemption occured" printf fired twice. I didn't do the
kpreempt_disable()/kpreempt_enable() because the code is running
with the kernel_lock and at splbio(), so kernel preemption should already
be disabled (if it's not it's a problem). 
The "tbp != bp" has not fired today, but I guess it's because the
load is sighly smaller than a working day.

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: dk.c
===================================================================
RCS file: /cvsroot/src/sys/dev/dkwedge/dk.c,v
retrieving revision 1.42.6.2
diff -u -r1.42.6.2 dk.c
--- dk.c        30 Jan 2010 19:00:46 -0000      1.42.6.2
+++ dk.c        4 Apr 2010 21:58:30 -0000
@@ -1021,6 +1021,8 @@
 
        /* Place it in the queue and start I/O on the unit. */
        s = splbio();
+       KASSERT(curcpu()->ci_biglock_count > 0);
+       KASSERT(curlwp->l_blcnt > 0);
        sc->sc_iopend++;
        BUFQ_PUT(sc->sc_bufq, bp);
        dkstart(sc);
@@ -1042,10 +1044,14 @@
 dkstart(struct dkwedge_softc *sc)
 {
        struct vnode *vp;
-       struct buf *bp, *nbp;
+       struct buf *bp, *nbp, *tbp;
+       uint64_t pctr;
 
        /* Do as much work as has been enqueued. */
        while ((bp = BUFQ_PEEK(sc->sc_bufq)) != NULL) {
+               KASSERT(curcpu()->ci_biglock_count > 0);
+               KASSERT(curcpu()->ci_ilevel >= IPL_BIO);
+               KASSERT(curlwp->l_blcnt > 0);
                if (sc->sc_state != DKW_STATE_RUNNING) {
                        (void) BUFQ_GET(sc->sc_bufq);
                        if (sc->sc_iopend-- == 1 &&
@@ -1056,24 +1062,39 @@
                        bp->b_error = ENXIO;
                        bp->b_resid = bp->b_bcount;
                        biodone(bp);
+                       continue;
                }
 
-               /* Instrumentation. */
-               disk_busy(&sc->sc_dk);
-
+               pctr = curlwp->l_ncsw;
                nbp = getiobuf(sc->sc_parent->dk_rawvp, false);
+               if (pctr != curlwp->l_ncsw) {
+                       printf("dkstart: preemption occured\n");
+               }
                if (nbp == NULL) {
                        /*
                         * No resources to run this request; leave the
                         * buffer queued up, and schedule a timer to
                         * restart the queue in 1/2 a second.
                         */
-                       disk_unbusy(&sc->sc_dk, 0, bp->b_flags & B_READ);
                        callout_schedule(&sc->sc_restart_ch, hz / 2);
                        return;
                }
 
-               (void) BUFQ_GET(sc->sc_bufq);
+               KASSERT(curcpu()->ci_biglock_count > 0);
+               KASSERT(curcpu()->ci_ilevel >= IPL_BIO);
+               KASSERT(curlwp->l_blcnt > 0);
+               tbp = BUFQ_GET(sc->sc_bufq);
+               if (tbp != bp) {
+                       printf("dkstart tbp %p != bp %p\n", tbp, bp);
+                       bp = tbp;
+                       if (bp == NULL) {
+                               putiobuf(nbp);
+                               return;
+                       }
+               }
+                               
+               /* Instrumentation. */
+               disk_busy(&sc->sc_dk);
 
                nbp->b_data = bp->b_data;
                nbp->b_flags = bp->b_flags;


Home | Main Index | Thread Index | Old Index