Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linuxkpi/common/src/linux_current.c
Show All 39 Lines | |||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
extern u_int first_msi_irq, num_msi_irqs; | extern u_int first_msi_irq, num_msi_irqs; | ||||
#endif | #endif | ||||
static eventhandler_tag linuxkpi_thread_dtor_tag; | static eventhandler_tag linuxkpi_thread_dtor_tag; | ||||
static atomic_t linux_current_allocs; | |||||
static uma_zone_t linux_current_zone; | static uma_zone_t linux_current_zone; | ||||
static uma_zone_t linux_mm_zone; | static uma_zone_t linux_mm_zone; | ||||
/* check if another thread already has a mm_struct */ | /* check if another thread already has a mm_struct */ | ||||
static struct mm_struct * | static struct mm_struct * | ||||
find_other_mm(struct proc *p) | find_other_mm(struct proc *p) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | linux_alloc_current(struct thread *td, int flags) | ||||
/* store pointer to task struct */ | /* store pointer to task struct */ | ||||
td->td_lkpi_task = ts; | td->td_lkpi_task = ts; | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
/* free mm_struct pointer, if any */ | /* free mm_struct pointer, if any */ | ||||
uma_zfree(linux_mm_zone, mm); | uma_zfree(linux_mm_zone, mm); | ||||
/* keep track of number of allocations */ | |||||
if (atomic_add_return(1, &linux_current_allocs) == INT_MAX) | |||||
panic("linux_alloc_current: Refcount too high!"); | |||||
return (0); | return (0); | ||||
} | } | ||||
struct mm_struct * | struct mm_struct * | ||||
linux_get_task_mm(struct task_struct *task) | linux_get_task_mm(struct task_struct *task) | ||||
{ | { | ||||
struct mm_struct *mm; | struct mm_struct *mm; | ||||
Show All 11 Lines | linux_mm_dtor(struct mm_struct *mm) | ||||
uma_zfree(linux_mm_zone, mm); | uma_zfree(linux_mm_zone, mm); | ||||
} | } | ||||
void | void | ||||
linux_free_current(struct task_struct *ts) | linux_free_current(struct task_struct *ts) | ||||
{ | { | ||||
mmput(ts->mm); | mmput(ts->mm); | ||||
uma_zfree(linux_current_zone, ts); | uma_zfree(linux_current_zone, ts); | ||||
/* keep track of number of allocations */ | |||||
if (atomic_sub_return(1, &linux_current_allocs) < 0) | |||||
panic("linux_free_current: Negative refcount!"); | |||||
} | } | ||||
static void | static void | ||||
linuxkpi_thread_dtor(void *arg __unused, struct thread *td) | linuxkpi_thread_dtor(void *arg __unused, struct thread *td) | ||||
{ | { | ||||
struct task_struct *ts; | struct task_struct *ts; | ||||
ts = td->td_lkpi_task; | ts = td->td_lkpi_task; | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | #endif | ||||
linux_mm_zone = uma_zcreate("lkpimm", | linux_mm_zone = uma_zcreate("lkpimm", | ||||
sizeof(struct task_struct), NULL, NULL, NULL, NULL, | sizeof(struct task_struct), NULL, NULL, NULL, NULL, | ||||
UMA_ALIGN_PTR, 0); | UMA_ALIGN_PTR, 0); | ||||
uma_zone_reserve(linux_mm_zone, lkpi_task_resrv); | uma_zone_reserve(linux_mm_zone, lkpi_task_resrv); | ||||
uma_prealloc(linux_mm_zone, lkpi_task_resrv); | uma_prealloc(linux_mm_zone, lkpi_task_resrv); | ||||
atomic_thread_fence_seq_cst(); | atomic_thread_fence_seq_cst(); | ||||
lkpi_alloc_current = linux_alloc_current; | |||||
linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, | linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, | ||||
linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); | linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); | ||||
lkpi_alloc_current = linux_alloc_current; | |||||
} | } | ||||
SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, | SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, | ||||
linux_current_init, NULL); | linux_current_init, NULL); | ||||
static void | static void | ||||
linux_current_uninit(void *arg __unused) | linux_current_uninit(void *arg __unused) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
Show All 12 Lines | FOREACH_THREAD_IN_PROC(p, td) { | ||||
td->td_lkpi_task = NULL; | td->td_lkpi_task = NULL; | ||||
put_task_struct(ts); | put_task_struct(ts); | ||||
} | } | ||||
} | } | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
/* | thread_reap_barrier(); | ||||
* There is a window where threads are removed from the | |||||
* process list and where the thread destructor is invoked. | |||||
* Catch that window by waiting for all task_struct | |||||
* allocations to be returned before freeing the UMA zone. | |||||
*/ | |||||
while (atomic_read(&linux_current_allocs) != 0) | |||||
pause("W", 1); | |||||
EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); | EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); | ||||
uma_zdestroy(linux_current_zone); | uma_zdestroy(linux_current_zone); | ||||
uma_zdestroy(linux_mm_zone); | uma_zdestroy(linux_mm_zone); | ||||
} | } | ||||
SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, | SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, | ||||
linux_current_uninit, NULL); | linux_current_uninit, NULL); |