> I see.  I think dropping the ill_locks don't present a problem, but the
 > ipsq_lock is trickier since dropping it in ipsq_dq() opens up some races.
 > I'll put this issue on the TODO list.

I've now made the change, by moving the second ipsq_exit() to the end of
ipsq_dq(), after all locks are dropped.  If you could take another look at
ipsq_dq(), ipsq_enter(), and ipsq_exit() in ip_if.c, I'd really appreciate
it:
        http://cr.grommit.com/~meem/ipmp-cv-dev/
        *** NOTE: please be sure to reload the webrev pages ***

Along the way, I addressed a large oversight in the way threads sleeping
in ipsq_enter() are awoken.  The fix parallels the current Nevada logic:
when ipx_writer is cleared on an xop, all of the IPSQs associated with the
xop are walked, and the associated ill->ill_cv's are awoken:

        /* ... */
        ipx->ipx_writer = NULL;
        VERIFY(--ipx->ipx_reentry_cnt == 0);
        ipx->ipx_ipsq_queued = B_FALSE;
        emptied = B_TRUE;

        mutex_exit(&ipx->ipx_lock);
        mutex_exit(&ipsq->ipsq_lock);   

        if (emptied) {
                xopipsq = ipsq;
                do {
                        if ((phyi = xopipsq->ipsq_phyint) == NULL)
                                continue;

                        illv4 = phyi->phyint_illv4;
                        illv6 = phyi->phyint_illv6;

                        GRAB_ILL_LOCKS(illv4, illv6);
                        if (illv4 != NULL)
                                cv_broadcast(&illv4->ill_cv);
                        if (illv6 != NULL)
                                cv_broadcast(&illv6->ill_cv);
                        RELEASE_ILL_LOCKS(illv4, illv6);
                } while ((xopipsq = xopipsq->ipsq_next) != ipsq);
        }

(Recall that in the new code, the binding between IPSQ and ill/phyint
is fixed, and is only set to NULL when the phyint itself is freed,
at which point there will never be any threads to wake up.)

-- 
meem

Reply via email to