From owner-svn-src-all@freebsd.org Thu Apr 6 09:07:03 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0D32BD305FC; Thu, 6 Apr 2017 09:07:03 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B5F56285; Thu, 6 Apr 2017 09:07:02 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v36971qw065446; Thu, 6 Apr 2017 09:07:01 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v369718F065445; Thu, 6 Apr 2017 09:07:01 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201704060907.v369718F065445@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Thu, 6 Apr 2017 09:07:01 +0000 (UTC) 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 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Apr 2017 09:07:03 -0000 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); }