Date: Thu, 6 Apr 2017 09:07:01 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r316561 - head/sys/compat/linuxkpi/common/src Message-ID: <201704060907.v369718F065445@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Thu Apr 6 09:07:01 2017 New Revision: 316561 URL: https://svnweb.freebsd.org/changeset/base/316561 Log: Before registering a new mm_struct in the LinuxKPI check if other tasks in the belonging procedure already have a valid mm_struct and reference that instead. The mm_struct in the LinuxKPI should be shared among all tasks belonging to the same procedure. This has to do with with the mmap_sem semaphore which should serialize all VM operations inside a given procedure. Linux based drivers depend on this behaviour. MFC after: 1 week Sponsored by: Mellanox Technologies Modified: head/sys/compat/linuxkpi/common/src/linux_current.c Modified: head/sys/compat/linuxkpi/common/src/linux_current.c ============================================================================== --- head/sys/compat/linuxkpi/common/src/linux_current.c Thu Apr 6 06:31:48 2017 (r316560) +++ head/sys/compat/linuxkpi/common/src/linux_current.c Thu Apr 6 09:07:01 2017 (r316561) @@ -42,8 +42,12 @@ static MALLOC_DEFINE(M_LINUX_CURRENT, "l 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; MPASS(td->td_lkpi_task == NULL); @@ -57,22 +61,55 @@ linux_alloc_current(struct thread *td, i return (ENOMEM); } + /* setup new task structure */ atomic_set(&ts->kthread_flags, 0); ts->task_thread = td; ts->comm = td->td_name; ts->pid = td->td_tid; - ts->mm = mm; atomic_set(&ts->usage, 1); ts->state = TASK_RUNNING; - /* setup mm_struct */ - init_rwsem(&mm->mmap_sem); - atomic_set(&mm->mm_count, 1); - atomic_set(&mm->mm_users, 1); - mm->vmspace = vmspace_acquire_ref(td->td_proc); + 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 = ts_other->mm; + if (mm_other == NULL) + continue; + + /* try to share other mm_struct */ + if (atomic_inc_not_zero(&mm_other->mm_users)) { + /* set mm_struct pointer */ + 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); + mm->vmspace = vmspace_acquire_ref(proc); + /* set mm_struct pointer */ + ts->mm = mm; + /* clear pointer to not free memory */ + mm = NULL; + } /* store pointer to task struct */ td->td_lkpi_task = ts; + PROC_UNLOCK(proc); + + /* free mm_struct pointer, if any */ + free(mm, M_LINUX_CURRENT); + return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201704060907.v369718F065445>