tech-kern archive

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

Re: Kernel panic in "subr_xcall.c"



On Mon, Oct 19, 2009 at 09:05:43AM +0100, Matthias Scheler wrote:
> Ok, I think I found the problem:
> 
> 1.) pool_cache_invalidate() calls xc_broadcast() with ci = NULL.
> 2.) xc_broadcast() calls xc_lowpri() with ci = NULL.
> 3.) xc_lowpri() iterates over all CPUs but doesn't fine any
>     running CPU and therefore doesn't schedule any cross calls.
> 4.) The KASSERT() at the end of loop in xc_lowpri() triggers
>     because "xc_tailp" and "xc_headp" are both zero.
> 
> The following patch avoids the problem:

Here is a slightly better patch:

Index: subr_xcall.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_xcall.c,v
retrieving revision 1.10
diff -u -r1.10 subr_xcall.c
--- subr_xcall.c        5 Mar 2009 13:18:51 -0000       1.10
+++ subr_xcall.c        19 Oct 2009 08:19:14 -0000
@@ -172,9 +172,11 @@
 xc_lowpri(u_int flags, xcfunc_t func, void *arg1, void *arg2,
          struct cpu_info *ci)
 {
-       CPU_INFO_ITERATOR cii;
+       bool call_direct;
        uint64_t where;
 
+       call_direct = false;
+
        mutex_enter(&xc_lock);
        while (xc_headp != xc_tailp)
                cv_wait(&xc_busy, &xc_lock);
@@ -182,10 +184,15 @@
        xc_arg2 = arg2;
        xc_func = func;
        if (ci == NULL) {
+               CPU_INFO_ITERATOR cii;
+
                xc_broadcast_ev.ev_count++;
                for (CPU_INFO_FOREACH(cii, ci)) {
-                       if ((ci->ci_schedstate.spc_flags & SPCF_RUNNING) == 0)
+                       if (!(ci->ci_schedstate.spc_flags & SPCF_RUNNING)) {
+                               if (curcpu() == ci)
+                                       call_direct = true;
                                continue;
+                       }
                        xc_headp += 1;
                        ci->ci_data.cpu_xcall_pending = true;
                        cv_signal(&ci->ci_data.cpu_xcall);
@@ -196,10 +203,13 @@
                ci->ci_data.cpu_xcall_pending = true;
                cv_signal(&ci->ci_data.cpu_xcall);
        }
-       KASSERT(xc_tailp < xc_headp);
+       KASSERT(xc_tailp < xc_headp || call_direct);
        where = xc_headp;
        mutex_exit(&xc_lock);
 
+       if (call_direct)
+               (*func)(arg1, arg2);
+
        return where;
 }
 
That is of course assuming that it is a bug in the cross call subsystem.

        Kind regards

-- 
Matthias Scheler                                  http://zhadum.org.uk/


Home | Main Index | Thread Index | Old Index