Source-Changes-HG archive

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

[src/trunk]: src/sys/kern In pool_cache_put_slow(), pool_get() can block (it ...



details:   https://anonhg.NetBSD.org/src/rev/8b277173ff2b
branches:  trunk
changeset: 785394:8b277173ff2b
user:      pooka <pooka%NetBSD.org@localhost>
date:      Mon Mar 11 21:37:54 2013 +0000

description:
In pool_cache_put_slow(), pool_get() can block (it does mutex_enter()),
so we need to retry if curlwp took a context switch during the call.
Otherwise, CPU-local invariants can get screwed up:

    panic: kernel diagnostic assertion "cur->pcg_avail == cur->pcg_size" failed

This is (was) very easy to reproduce by just running:

  while : ; do RUMP_NCPU=32 ./a.out ; done

where a.out only calls rump_init().  But, any situation there's contention
and a pool doesn't have emptygroups would do.

diffstat:

 sys/kern/subr_pool.c |  19 +++++++++++++++----
 1 files changed, 15 insertions(+), 4 deletions(-)

diffs (68 lines):

diff -r bbf9f14ffcc7 -r 8b277173ff2b sys/kern/subr_pool.c
--- a/sys/kern/subr_pool.c      Mon Mar 11 20:19:28 2013 +0000
+++ b/sys/kern/subr_pool.c      Mon Mar 11 21:37:54 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: subr_pool.c,v 1.199 2013/02/09 00:31:21 christos Exp $ */
+/*     $NetBSD: subr_pool.c,v 1.200 2013/03/11 21:37:54 pooka Exp $    */
 
 /*-
  * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.199 2013/02/09 00:31:21 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.200 2013/03/11 21:37:54 pooka Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -2261,6 +2261,7 @@
 static bool __noinline
 pool_cache_put_slow(pool_cache_cpu_t *cc, int s, void *object)
 {
+       struct lwp *l = curlwp;
        pcg_t *pcg, *cur;
        uint64_t ncsw;
        pool_cache_t pc;
@@ -2271,6 +2272,7 @@
        pc = cc->cc_cache;
        pcg = NULL;
        cc->cc_misses++;
+       ncsw = l->l_ncsw;
 
        /*
         * If there are no empty groups in the cache then allocate one
@@ -2280,6 +2282,16 @@
                if (__predict_true(!pool_cache_disable)) {
                        pcg = pool_get(pc->pc_pcgpool, PR_NOWAIT);
                }
+               /*
+                * If pool_get() blocked, then our view of
+                * the per-CPU data is invalid: retry.
+                */
+               if (__predict_false(l->l_ncsw != ncsw)) {
+                       if (pcg != NULL) {
+                               pool_put(pc->pc_pcgpool, pcg);
+                       }
+                       return true;
+               }
                if (__predict_true(pcg != NULL)) {
                        pcg->pcg_avail = 0;
                        pcg->pcg_size = pc->pc_pcgsize;
@@ -2288,7 +2300,6 @@
 
        /* Lock the cache. */
        if (__predict_false(!mutex_tryenter(&pc->pc_lock))) {
-               ncsw = curlwp->l_ncsw;
                mutex_enter(&pc->pc_lock);
                pc->pc_contended++;
 
@@ -2296,7 +2307,7 @@
                 * If we context switched while locking, then our view of
                 * the per-CPU data is invalid: retry.
                 */
-               if (__predict_false(curlwp->l_ncsw != ncsw)) {
+               if (__predict_false(l->l_ncsw != ncsw)) {
                        mutex_exit(&pc->pc_lock);
                        if (pcg != NULL) {
                                pool_put(pc->pc_pcgpool, pcg);



Home | Main Index | Thread Index | Old Index