svn commit: r316561 - head/sys/compat/linuxkpi/common/src
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Apr 6 09:07:03 UTC 2017
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);
}
More information about the svn-src-head
mailing list