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
This commit is contained in:
parent
4ce1f6162e
commit
165ba13fb8
@ -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)
|
||||
return (ENOMEM);
|
||||
if ((td->td_pflags & TDP_ITHREAD) != 0 || !THREAD_CAN_SLEEP()) {
|
||||
flags &= ~M_WAITOK;
|
||||
flags |= M_NOWAIT | M_USE_RESERVE;
|
||||
}
|
||||
|
||||
mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO);
|
||||
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 = 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);
|
||||
|
Loading…
Reference in New Issue
Block a user