aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <konstantinb@nvidia.com>2021-03-11 06:48:22 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-04-19 18:34:08 +0000
commitfad437ba612a7c19f5cf1633e2d0d1c44d4dd478 (patch)
tree4c61a7d67099de3baf195ac38b648f964a197b95
parent165ba13fb806c8596f868981883631a5ee78d6c8 (diff)
downloadsrc-fad437ba612a7c19f5cf1633e2d0d1c44d4dd478.tar.gz
src-fad437ba612a7c19f5cf1633e2d0d1c44d4dd478.zip
linuxkpi: reduce number of stray mm_struct allocations
Only allocate struct_mm after we checked that other threads do not carry useful mm_struct. If they don't, drop process lock, allocate, and recheck. Note that for M_NOWAIT allocations we could avoid dropping process lock, but I do not think that this increased complexity is useful. Reviewed by: hselasky Sponsored by: Mellanox Technologies/NVidia Networking MFC after: 1 week
-rw-r--r--sys/compat/linuxkpi/common/src/linux_current.c85
1 files changed, 50 insertions, 35 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
index ef51acc1952e..9bae7ee92e49 100644
--- a/sys/compat/linuxkpi/common/src/linux_current.c
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -48,15 +48,35 @@ static eventhandler_tag linuxkpi_thread_dtor_tag;
static uma_zone_t linux_current_zone;
static uma_zone_t linux_mm_zone;
+/* check if another thread already has a mm_struct */
+static struct mm_struct *
+find_other_mm(struct proc *p)
+{
+ struct thread *td;
+ struct task_struct *ts;
+ struct mm_struct *mm;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ FOREACH_THREAD_IN_PROC(p, td) {
+ ts = td->td_lkpi_task;
+ if (ts == NULL)
+ continue;
+ mm = ts->mm;
+ if (mm == NULL)
+ continue;
+ /* try to share other mm_struct */
+ if (atomic_inc_not_zero(&mm->mm_users))
+ return (mm);
+ }
+ return (NULL);
+}
+
int
linux_alloc_current(struct thread *td, int flags)
{
struct proc *proc;
- struct thread *td_other;
struct task_struct *ts;
- struct task_struct *ts_other;
- struct mm_struct *mm;
- struct mm_struct *mm_other;
+ struct mm_struct *mm, *mm_other;
MPASS(td->td_lkpi_task == NULL);
@@ -71,14 +91,7 @@ linux_alloc_current(struct thread *td, int flags)
panic("linux_alloc_current: failed to allocate task");
return (ENOMEM);
}
-
- mm = uma_zalloc(linux_mm_zone, flags | M_ZERO);
- if (mm == NULL) {
- if ((flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK)
- panic("linux_alloc_current: failed to allocate mm");
- uma_zfree(linux_current_zone, mm);
- return (ENOMEM);
- }
+ mm = NULL;
/* setup new task structure */
atomic_set(&ts->kthread_flags, 0);
@@ -93,35 +106,37 @@ linux_alloc_current(struct thread *td, int flags)
proc = td->td_proc;
- /* check if another thread already has a mm_struct */
PROC_LOCK(proc);
- FOREACH_THREAD_IN_PROC(proc, td_other) {
- ts_other = td_other->td_lkpi_task;
- if (ts_other == NULL)
- continue;
+ mm_other = find_other_mm(proc);
- mm_other = ts_other->mm;
- if (mm_other == NULL)
- continue;
+ /* use allocated mm_struct as a fallback */
+ if (mm_other == NULL) {
+ PROC_UNLOCK(proc);
+ mm = uma_zalloc(linux_mm_zone, flags | M_ZERO);
+ if (mm == NULL) {
+ if ((flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK)
+ panic(
+ "linux_alloc_current: failed to allocate mm");
+ uma_zfree(linux_current_zone, mm);
+ return (ENOMEM);
+ }
- /* try to share other mm_struct */
- if (atomic_inc_not_zero(&mm_other->mm_users)) {
+ PROC_LOCK(proc);
+ mm_other = find_other_mm(proc);
+ if (mm_other == NULL) {
+ /* setup new mm_struct */
+ init_rwsem(&mm->mmap_sem);
+ atomic_set(&mm->mm_count, 1);
+ atomic_set(&mm->mm_users, 1);
/* set mm_struct pointer */
+ ts->mm = mm;
+ /* clear pointer to not free memory */
+ mm = NULL;
+ } else {
ts->mm = mm_other;
- break;
}
- }
-
- /* use allocated mm_struct as a fallback */
- if (ts->mm == NULL) {
- /* setup new mm_struct */
- init_rwsem(&mm->mmap_sem);
- atomic_set(&mm->mm_count, 1);
- atomic_set(&mm->mm_users, 1);
- /* set mm_struct pointer */
- ts->mm = mm;
- /* clear pointer to not free memory */
- mm = NULL;
+ } else {
+ ts->mm = mm_other;
}
/* store pointer to task struct */