Source-Changes-HG archive

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

[src/trunk]: src/sys/uvm Draining pools from the pagedaemon thread can deadlo...



details:   https://anonhg.NetBSD.org/src/rev/8b6fff56da54
branches:  trunk
changeset: 450659:8b6fff56da54
user:      chs <chs%NetBSD.org@localhost>
date:      Sun Apr 21 15:32:18 2019 +0000

description:
Draining pools from the pagedaemon thread can deadlock, because draining
a pool can involve taking a lock which can be held by a thread which is
blocked waiting for memory.  Avoid this by moving the pool-draining work
to a separate worker thread.

diffstat:

 sys/uvm/uvm_pdaemon.c |  86 ++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 71 insertions(+), 15 deletions(-)

diffs (150 lines):

diff -r f71dba0130a4 -r 8b6fff56da54 sys/uvm/uvm_pdaemon.c
--- a/sys/uvm/uvm_pdaemon.c     Sun Apr 21 15:27:59 2019 +0000
+++ b/sys/uvm/uvm_pdaemon.c     Sun Apr 21 15:32:18 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uvm_pdaemon.c,v 1.109 2017/10/28 00:37:13 pgoyette Exp $       */
+/*     $NetBSD: uvm_pdaemon.c,v 1.110 2019/04/21 15:32:18 chs Exp $    */
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_pdaemon.c,v 1.109 2017/10/28 00:37:13 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_pdaemon.c,v 1.110 2019/04/21 15:32:18 chs Exp $");
 
 #include "opt_uvmhist.h"
 #include "opt_readahead.h"
@@ -79,6 +79,7 @@
 #include <sys/buf.h>
 #include <sys/module.h>
 #include <sys/atomic.h>
+#include <sys/kthread.h>
 
 #include <uvm/uvm.h>
 #include <uvm/uvm_pdpolicy.h>
@@ -105,9 +106,16 @@
 static void    uvmpd_scan(void);
 static void    uvmpd_scan_queue(void);
 static void    uvmpd_tune(void);
+static void    uvmpd_pool_drain_thread(void *);
+static void    uvmpd_pool_drain_wakeup(void);
 
 static unsigned int uvm_pagedaemon_waiters;
 
+/* State for the pool drainer thread */
+static kmutex_t uvmpd_pool_drain_lock;
+static kcondvar_t uvmpd_pool_drain_cv;
+static bool uvmpd_pool_drain_run = false;
+
 /*
  * XXX hack to avoid hangs when large processes fork.
  */
@@ -229,14 +237,21 @@
 void
 uvm_pageout(void *arg)
 {
-       int bufcnt, npages = 0;
+       int npages = 0;
        int extrapages = 0;
-       struct pool *pp;
        
        UVMHIST_FUNC("uvm_pageout"); UVMHIST_CALLED(pdhist);
 
        UVMHIST_LOG(pdhist,"<starting uvm pagedaemon>", 0, 0, 0, 0);
 
+       mutex_init(&uvmpd_pool_drain_lock, MUTEX_DEFAULT, IPL_VM);
+       cv_init(&uvmpd_pool_drain_cv, "pooldrain");
+
+       /* Create the pool drainer kernel thread. */
+       if (kthread_create(PRI_VM, KTHREAD_MPSAFE, NULL,
+           uvmpd_pool_drain_thread, NULL, NULL, "pooldrain"))
+               panic("fork pooldrain");
+
        /*
         * ensure correct priority and set paging parameters...
         */
@@ -288,9 +303,6 @@
                 * system only when entire pool page is empty.
                 */
                mutex_spin_enter(&uvm_fpageqlock);
-               bufcnt = uvmexp.freetarg - uvmexp.free;
-               if (bufcnt < 0)
-                       bufcnt = 0;
 
                UVMHIST_LOG(pdhist,"  free/ftarg=%jd/%jd",
                    uvmexp.free, uvmexp.freetarg, 0,0);
@@ -331,16 +343,10 @@
                        continue;
 
                /*
-                * kill unused metadata buffers.
+                * kick the pool drainer thread.
                 */
-               mutex_enter(&bufcache_lock);
-               buf_drain(bufcnt << PAGE_SHIFT);
-               mutex_exit(&bufcache_lock);
 
-               /*
-                * drain the pools.
-                */
-               pool_drain(&pp);
+               uvmpd_pool_drain_wakeup();
        }
        /*NOTREACHED*/
 }
@@ -1022,3 +1028,53 @@
        uvmpdpol_estimatepageable(active, inactive);
 }
 
+
+/*
+ * Use a separate thread for draining pools.
+ * This work can't done from the main pagedaemon thread because
+ * some pool allocators need to take vm_map locks.
+ */
+
+static void
+uvmpd_pool_drain_thread(void *arg)
+{
+       int bufcnt;
+
+       for (;;) {
+               mutex_enter(&uvmpd_pool_drain_lock);
+               if (!uvmpd_pool_drain_run) {
+                       cv_wait(&uvmpd_pool_drain_cv, &uvmpd_pool_drain_lock);
+               }
+               uvmpd_pool_drain_run = false;
+               mutex_exit(&uvmpd_pool_drain_lock);
+
+               /*
+                * kill unused metadata buffers.
+                */
+               mutex_spin_enter(&uvm_fpageqlock);
+               bufcnt = uvmexp.freetarg - uvmexp.free;
+               mutex_spin_exit(&uvm_fpageqlock);
+               if (bufcnt < 0)
+                       bufcnt = 0;
+
+               mutex_enter(&bufcache_lock);
+               buf_drain(bufcnt << PAGE_SHIFT);
+               mutex_exit(&bufcache_lock);
+
+               /*
+                * drain a pool.
+                */
+               pool_drain(NULL);
+       }
+       /*NOTREACHED*/
+}
+
+static void
+uvmpd_pool_drain_wakeup(void)
+{
+
+       mutex_enter(&uvmpd_pool_drain_lock);
+       uvmpd_pool_drain_run = true;
+       cv_signal(&uvmpd_pool_drain_cv);
+       mutex_exit(&uvmpd_pool_drain_lock);
+}



Home | Main Index | Thread Index | Old Index