git: 165ba13fb806 - main - linuxkpi: guarantee allocations of task and mm for interrupt threads

Konstantin Belousov kib at FreeBSD.org
Mon Apr 19 18:38:18 UTC 2021


The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=165ba13fb806c8596f868981883631a5ee78d6c8

commit 165ba13fb806c8596f868981883631a5ee78d6c8
Author:     Konstantin Belousov <konstantinb at nvidia.com>
AuthorDate: 2021-03-11 06:34:42 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-04-19 18:34:08 +0000

    linuxkpi: guarantee allocations of task and mm for interrupt threads
    
    Create and use zones for task and mm.  Reserve items in zones based on the
    estimation of the max number of interrupts in the system.  Use M_USE_RESERVE
    to allow to take reserved items when allocation occurs from the interrupt
    thread context.
    
    Of course, this would only work first time we allocate the task for
    interrupt thread. If interrupt is deallocated and allocated anew,
    creating a new thread, it might be that zone is depleted. It still
    should be good enough for practical uses.
    
    Reviewed by:    hselasky
    Sponsored by:   Mellanox Technologies/NVidia Networking
    MFC after:      1 week
---
 sys/compat/linuxkpi/common/src/linux_current.c | 66 ++++++++++++++++++++++----
 1 file changed, 58 insertions(+), 8 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
index 081eab8edab1..ef51acc1952e 100644
--- a/sys/compat/linuxkpi/common/src/linux_current.c
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -31,14 +31,22 @@ __FBSDID("$FreeBSD$");
 #include <linux/completion.h>
 #include <linux/mm.h>
 #include <linux/kthread.h>
+#include <linux/moduleparam.h>
 
 #include <sys/kernel.h>
 #include <sys/eventhandler.h>
 #include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <vm/uma.h>
+
+#if defined(__i386__) || defined(__amd64__)
+extern u_int first_msi_irq, num_msi_irqs;
+#endif
 
 static eventhandler_tag linuxkpi_thread_dtor_tag;
 
-static MALLOC_DEFINE(M_LINUX_CURRENT, "linuxcurrent", "LinuxKPI task structure");
+static uma_zone_t linux_current_zone;
+static uma_zone_t linux_mm_zone;
 
 int
 linux_alloc_current(struct thread *td, int flags)
@@ -52,13 +60,23 @@ linux_alloc_current(struct thread *td, int flags)
 
 	MPASS(td->td_lkpi_task == NULL);
 
-	ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO);
-	if (ts == NULL)
+	if ((td->td_pflags & TDP_ITHREAD) != 0 || !THREAD_CAN_SLEEP()) {
+		flags &= ~M_WAITOK;
+		flags |= M_NOWAIT | M_USE_RESERVE;
+	}
+
+	ts = uma_zalloc(linux_current_zone, flags | M_ZERO);
+	if (ts == NULL) {
+		if ((flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK)
+			panic("linux_alloc_current: failed to allocate task");
 		return (ENOMEM);
+	}
 
-	mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO);
+	mm = uma_zalloc(linux_mm_zone, flags | M_ZERO);
 	if (mm == NULL) {
-		free(ts, M_LINUX_CURRENT);
+		if ((flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK)
+			panic("linux_alloc_current: failed to allocate mm");
+		uma_zfree(linux_current_zone, mm);
 		return (ENOMEM);
 	}
 
@@ -111,7 +129,7 @@ linux_alloc_current(struct thread *td, int flags)
 	PROC_UNLOCK(proc);
 
 	/* free mm_struct pointer, if any */
-	free(mm, M_LINUX_CURRENT);
+	uma_zfree(linux_mm_zone, mm);
 
 	return (0);
 }
@@ -132,14 +150,14 @@ linux_get_task_mm(struct task_struct *task)
 void
 linux_mm_dtor(struct mm_struct *mm)
 {
-	free(mm, M_LINUX_CURRENT);
+	uma_zfree(linux_mm_zone, mm);
 }
 
 void
 linux_free_current(struct task_struct *ts)
 {
 	mmput(ts->mm);
-	free(ts, M_LINUX_CURRENT);
+	uma_zfree(linux_current_zone, ts);
 }
 
 static void
@@ -229,12 +247,42 @@ linux_task_exiting(struct task_struct *task)
 	return (ret);
 }
 
+static int lkpi_task_resrv;
+SYSCTL_INT(_compat_linuxkpi, OID_AUTO, task_struct_reserve,
+    CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &lkpi_task_resrv, 0,
+    "Number of struct task and struct mm to reserve for non-sleepable "
+    "allocations");
+
 static void
 linux_current_init(void *arg __unused)
 {
 	lkpi_alloc_current = linux_alloc_current;
 	linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
 	    linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
+
+	TUNABLE_INT_FETCH("compat.linuxkpi.task_struct_reserve",
+	    &lkpi_task_resrv);
+	if (lkpi_task_resrv == 0) {
+#if defined(__i386__) || defined(__amd64__)
+		/*
+		 * Number of interrupt threads plus per-cpu callout
+		 * SWI threads.
+		 */
+		lkpi_task_resrv = first_msi_irq + num_msi_irqs + MAXCPU;
+#else
+		lkpi_task_resrv = 1024;		/* XXXKIB arbitrary */
+#endif
+	}
+	linux_current_zone = uma_zcreate("lkpicurr",
+	    sizeof(struct task_struct), NULL, NULL, NULL, NULL,
+	    UMA_ALIGN_PTR, 0);
+	uma_zone_reserve(linux_current_zone, lkpi_task_resrv);
+	uma_prealloc(linux_current_zone, lkpi_task_resrv);
+	linux_mm_zone = uma_zcreate("lkpimm",
+	    sizeof(struct task_struct), NULL, NULL, NULL, NULL,
+	    UMA_ALIGN_PTR, 0);
+	uma_zone_reserve(linux_mm_zone, lkpi_task_resrv);
+	uma_prealloc(linux_mm_zone, lkpi_task_resrv);
 }
 SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND,
     linux_current_init, NULL);
@@ -260,6 +308,8 @@ linux_current_uninit(void *arg __unused)
 	sx_sunlock(&allproc_lock);
 	EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag);
 	lkpi_alloc_current = linux_alloc_current_noop;
+	uma_zdestroy(linux_current_zone);
+	uma_zdestroy(linux_mm_zone);
 }
 SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND,
     linux_current_uninit, NULL);


More information about the dev-commits-src-all mailing list