Skip site navigation (1)Skip section navigation (2)
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>