The branch main has been updated by kib:

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

commit fad437ba612a7c19f5cf1633e2d0d1c44d4dd478
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-03-11 06:48:22 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2021-04-19 18:34:08 +0000

    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
---
 sys/compat/linuxkpi/common/src/linux_current.c | 85 +++++++++++++++-----------
 1 file 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 */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "[email protected]"

Reply via email to