11e3db1deSHans Petter Selasky /*- 21e3db1deSHans Petter Selasky * Copyright (c) 2017 Hans Petter Selasky 31e3db1deSHans Petter Selasky * All rights reserved. 41e3db1deSHans Petter Selasky * 51e3db1deSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 61e3db1deSHans Petter Selasky * modification, are permitted provided that the following conditions 71e3db1deSHans Petter Selasky * are met: 81e3db1deSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 91e3db1deSHans Petter Selasky * notice unmodified, this list of conditions, and the following 101e3db1deSHans Petter Selasky * disclaimer. 111e3db1deSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 121e3db1deSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 131e3db1deSHans Petter Selasky * documentation and/or other materials provided with the distribution. 141e3db1deSHans Petter Selasky * 151e3db1deSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161e3db1deSHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171e3db1deSHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181e3db1deSHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191e3db1deSHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201e3db1deSHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211e3db1deSHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221e3db1deSHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231e3db1deSHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241e3db1deSHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251e3db1deSHans Petter Selasky */ 261e3db1deSHans Petter Selasky 271e3db1deSHans Petter Selasky #include <sys/cdefs.h> 281e3db1deSHans Petter Selasky __FBSDID("$FreeBSD$"); 291e3db1deSHans Petter Selasky 301e3db1deSHans Petter Selasky #include <linux/compat.h> 318504aa98SMark Johnston #include <linux/completion.h> 321e3db1deSHans Petter Selasky #include <linux/mm.h> 331e3db1deSHans Petter Selasky #include <linux/kthread.h> 341e3db1deSHans Petter Selasky 351e3db1deSHans Petter Selasky #include <sys/kernel.h> 361e3db1deSHans Petter Selasky #include <sys/eventhandler.h> 371e3db1deSHans Petter Selasky #include <sys/malloc.h> 381e3db1deSHans Petter Selasky 391e3db1deSHans Petter Selasky static eventhandler_tag linuxkpi_thread_dtor_tag; 401e3db1deSHans Petter Selasky 411e3db1deSHans Petter Selasky static MALLOC_DEFINE(M_LINUX_CURRENT, "linuxcurrent", "LinuxKPI task structure"); 421e3db1deSHans Petter Selasky 431e3db1deSHans Petter Selasky int 441e3db1deSHans Petter Selasky linux_alloc_current(struct thread *td, int flags) 451e3db1deSHans Petter Selasky { 46e54b103eSHans Petter Selasky struct proc *proc; 47e54b103eSHans Petter Selasky struct thread *td_other; 481e3db1deSHans Petter Selasky struct task_struct *ts; 49e54b103eSHans Petter Selasky struct task_struct *ts_other; 5005d4f501SHans Petter Selasky struct mm_struct *mm; 51e54b103eSHans Petter Selasky struct mm_struct *mm_other; 521e3db1deSHans Petter Selasky 531e3db1deSHans Petter Selasky MPASS(td->td_lkpi_task == NULL); 541e3db1deSHans Petter Selasky 551e3db1deSHans Petter Selasky ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO); 561e3db1deSHans Petter Selasky if (ts == NULL) 571e3db1deSHans Petter Selasky return (ENOMEM); 581e3db1deSHans Petter Selasky 5905d4f501SHans Petter Selasky mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO); 6005d4f501SHans Petter Selasky if (mm == NULL) { 6105d4f501SHans Petter Selasky free(ts, M_LINUX_CURRENT); 6205d4f501SHans Petter Selasky return (ENOMEM); 6305d4f501SHans Petter Selasky } 6405d4f501SHans Petter Selasky 65e54b103eSHans Petter Selasky /* setup new task structure */ 661e3db1deSHans Petter Selasky atomic_set(&ts->kthread_flags, 0); 671e3db1deSHans Petter Selasky ts->task_thread = td; 681e3db1deSHans Petter Selasky ts->comm = td->td_name; 691e3db1deSHans Petter Selasky ts->pid = td->td_tid; 7007e0a3caSJohannes Lundberg ts->group_leader = ts; 71a0699ebfSHans Petter Selasky atomic_set(&ts->usage, 1); 72ef925749SHans Petter Selasky atomic_set(&ts->state, TASK_RUNNING); 738504aa98SMark Johnston init_completion(&ts->parked); 748504aa98SMark Johnston init_completion(&ts->exited); 7505d4f501SHans Petter Selasky 76e54b103eSHans Petter Selasky proc = td->td_proc; 77e54b103eSHans Petter Selasky 78e54b103eSHans Petter Selasky /* check if another thread already has a mm_struct */ 79e54b103eSHans Petter Selasky PROC_LOCK(proc); 80e54b103eSHans Petter Selasky FOREACH_THREAD_IN_PROC(proc, td_other) { 81e54b103eSHans Petter Selasky ts_other = td_other->td_lkpi_task; 82e54b103eSHans Petter Selasky if (ts_other == NULL) 83e54b103eSHans Petter Selasky continue; 84e54b103eSHans Petter Selasky 85e54b103eSHans Petter Selasky mm_other = ts_other->mm; 86e54b103eSHans Petter Selasky if (mm_other == NULL) 87e54b103eSHans Petter Selasky continue; 88e54b103eSHans Petter Selasky 89e54b103eSHans Petter Selasky /* try to share other mm_struct */ 90e54b103eSHans Petter Selasky if (atomic_inc_not_zero(&mm_other->mm_users)) { 91e54b103eSHans Petter Selasky /* set mm_struct pointer */ 92e54b103eSHans Petter Selasky ts->mm = mm_other; 93e54b103eSHans Petter Selasky break; 94e54b103eSHans Petter Selasky } 95e54b103eSHans Petter Selasky } 96e54b103eSHans Petter Selasky 97e54b103eSHans Petter Selasky /* use allocated mm_struct as a fallback */ 98e54b103eSHans Petter Selasky if (ts->mm == NULL) { 99e54b103eSHans Petter Selasky /* setup new mm_struct */ 10005d4f501SHans Petter Selasky init_rwsem(&mm->mmap_sem); 10105d4f501SHans Petter Selasky atomic_set(&mm->mm_count, 1); 10205d4f501SHans Petter Selasky atomic_set(&mm->mm_users, 1); 103e54b103eSHans Petter Selasky /* set mm_struct pointer */ 104e54b103eSHans Petter Selasky ts->mm = mm; 105e54b103eSHans Petter Selasky /* clear pointer to not free memory */ 106e54b103eSHans Petter Selasky mm = NULL; 107e54b103eSHans Petter Selasky } 10805d4f501SHans Petter Selasky 10905d4f501SHans Petter Selasky /* store pointer to task struct */ 1101e3db1deSHans Petter Selasky td->td_lkpi_task = ts; 111e54b103eSHans Petter Selasky PROC_UNLOCK(proc); 112e54b103eSHans Petter Selasky 113e54b103eSHans Petter Selasky /* free mm_struct pointer, if any */ 114e54b103eSHans Petter Selasky free(mm, M_LINUX_CURRENT); 115e54b103eSHans Petter Selasky 1161e3db1deSHans Petter Selasky return (0); 1171e3db1deSHans Petter Selasky } 1181e3db1deSHans Petter Selasky 11905d4f501SHans Petter Selasky struct mm_struct * 12005d4f501SHans Petter Selasky linux_get_task_mm(struct task_struct *task) 12105d4f501SHans Petter Selasky { 12205d4f501SHans Petter Selasky struct mm_struct *mm; 12305d4f501SHans Petter Selasky 12405d4f501SHans Petter Selasky mm = task->mm; 12568b9f2f0SHans Petter Selasky if (mm != NULL) { 12605d4f501SHans Petter Selasky atomic_inc(&mm->mm_users); 12705d4f501SHans Petter Selasky return (mm); 12805d4f501SHans Petter Selasky } 12905d4f501SHans Petter Selasky return (NULL); 13005d4f501SHans Petter Selasky } 13105d4f501SHans Petter Selasky 13205d4f501SHans Petter Selasky void 13305d4f501SHans Petter Selasky linux_mm_dtor(struct mm_struct *mm) 13405d4f501SHans Petter Selasky { 13505d4f501SHans Petter Selasky free(mm, M_LINUX_CURRENT); 13605d4f501SHans Petter Selasky } 13705d4f501SHans Petter Selasky 1381e3db1deSHans Petter Selasky void 1391e3db1deSHans Petter Selasky linux_free_current(struct task_struct *ts) 1401e3db1deSHans Petter Selasky { 14105d4f501SHans Petter Selasky mmput(ts->mm); 1421e3db1deSHans Petter Selasky free(ts, M_LINUX_CURRENT); 1431e3db1deSHans Petter Selasky } 1441e3db1deSHans Petter Selasky 1451e3db1deSHans Petter Selasky static void 1461e3db1deSHans Petter Selasky linuxkpi_thread_dtor(void *arg __unused, struct thread *td) 1471e3db1deSHans Petter Selasky { 1481e3db1deSHans Petter Selasky struct task_struct *ts; 1491e3db1deSHans Petter Selasky 1501e3db1deSHans Petter Selasky ts = td->td_lkpi_task; 1511e3db1deSHans Petter Selasky if (ts == NULL) 1521e3db1deSHans Petter Selasky return; 1531e3db1deSHans Petter Selasky 1541e3db1deSHans Petter Selasky td->td_lkpi_task = NULL; 155a0699ebfSHans Petter Selasky put_task_struct(ts); 156a0699ebfSHans Petter Selasky } 157a0699ebfSHans Petter Selasky 158a0699ebfSHans Petter Selasky struct task_struct * 159a0699ebfSHans Petter Selasky linux_pid_task(pid_t pid) 160a0699ebfSHans Petter Selasky { 161a0699ebfSHans Petter Selasky struct thread *td; 1628402f058SHans Petter Selasky struct proc *p; 163a0699ebfSHans Petter Selasky 1648402f058SHans Petter Selasky /* try to find corresponding thread */ 165a0699ebfSHans Petter Selasky td = tdfind(pid, -1); 166a0699ebfSHans Petter Selasky if (td != NULL) { 167a0699ebfSHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 168a0699ebfSHans Petter Selasky PROC_UNLOCK(td->td_proc); 169a0699ebfSHans Petter Selasky return (ts); 170a0699ebfSHans Petter Selasky } 1718402f058SHans Petter Selasky 1728402f058SHans Petter Selasky /* try to find corresponding procedure */ 1738402f058SHans Petter Selasky p = pfind(pid); 1748402f058SHans Petter Selasky if (p != NULL) { 1758402f058SHans Petter Selasky FOREACH_THREAD_IN_PROC(p, td) { 1768402f058SHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 1778402f058SHans Petter Selasky if (ts != NULL) { 1788402f058SHans Petter Selasky PROC_UNLOCK(p); 1798402f058SHans Petter Selasky return (ts); 1808402f058SHans Petter Selasky } 1818402f058SHans Petter Selasky } 1828402f058SHans Petter Selasky PROC_UNLOCK(p); 1838402f058SHans Petter Selasky } 184a0699ebfSHans Petter Selasky return (NULL); 185a0699ebfSHans Petter Selasky } 186a0699ebfSHans Petter Selasky 187a0699ebfSHans Petter Selasky struct task_struct * 188a0699ebfSHans Petter Selasky linux_get_pid_task(pid_t pid) 189a0699ebfSHans Petter Selasky { 190a0699ebfSHans Petter Selasky struct thread *td; 1918402f058SHans Petter Selasky struct proc *p; 192a0699ebfSHans Petter Selasky 1938402f058SHans Petter Selasky /* try to find corresponding thread */ 194a0699ebfSHans Petter Selasky td = tdfind(pid, -1); 195a0699ebfSHans Petter Selasky if (td != NULL) { 196a0699ebfSHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 197a0699ebfSHans Petter Selasky if (ts != NULL) 198a0699ebfSHans Petter Selasky get_task_struct(ts); 199a0699ebfSHans Petter Selasky PROC_UNLOCK(td->td_proc); 200a0699ebfSHans Petter Selasky return (ts); 201a0699ebfSHans Petter Selasky } 2028402f058SHans Petter Selasky 2038402f058SHans Petter Selasky /* try to find corresponding procedure */ 2048402f058SHans Petter Selasky p = pfind(pid); 2058402f058SHans Petter Selasky if (p != NULL) { 2068402f058SHans Petter Selasky FOREACH_THREAD_IN_PROC(p, td) { 2078402f058SHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 2088402f058SHans Petter Selasky if (ts != NULL) { 2098402f058SHans Petter Selasky get_task_struct(ts); 2108402f058SHans Petter Selasky PROC_UNLOCK(p); 2118402f058SHans Petter Selasky return (ts); 2128402f058SHans Petter Selasky } 2138402f058SHans Petter Selasky } 2148402f058SHans Petter Selasky PROC_UNLOCK(p); 2158402f058SHans Petter Selasky } 216a0699ebfSHans Petter Selasky return (NULL); 2171e3db1deSHans Petter Selasky } 2181e3db1deSHans Petter Selasky 219638fa5a3SHans Petter Selasky bool 220638fa5a3SHans Petter Selasky linux_task_exiting(struct task_struct *task) 221638fa5a3SHans Petter Selasky { 2229a4e535bSHans Petter Selasky struct thread *td; 223638fa5a3SHans Petter Selasky struct proc *p; 224638fa5a3SHans Petter Selasky bool ret; 225638fa5a3SHans Petter Selasky 226638fa5a3SHans Petter Selasky ret = false; 2279a4e535bSHans Petter Selasky 2289a4e535bSHans Petter Selasky /* try to find corresponding thread */ 2299a4e535bSHans Petter Selasky td = tdfind(task->pid, -1); 2309a4e535bSHans Petter Selasky if (td != NULL) { 2319a4e535bSHans Petter Selasky p = td->td_proc; 2329a4e535bSHans Petter Selasky } else { 2339a4e535bSHans Petter Selasky /* try to find corresponding procedure */ 234638fa5a3SHans Petter Selasky p = pfind(task->pid); 2359a4e535bSHans Petter Selasky } 2369a4e535bSHans Petter Selasky 237638fa5a3SHans Petter Selasky if (p != NULL) { 238638fa5a3SHans Petter Selasky if ((p->p_flag & P_WEXIT) != 0) 239638fa5a3SHans Petter Selasky ret = true; 240638fa5a3SHans Petter Selasky PROC_UNLOCK(p); 241638fa5a3SHans Petter Selasky } 242638fa5a3SHans Petter Selasky return (ret); 243638fa5a3SHans Petter Selasky } 244638fa5a3SHans Petter Selasky 2451e3db1deSHans Petter Selasky static void 2461e3db1deSHans Petter Selasky linux_current_init(void *arg __unused) 2471e3db1deSHans Petter Selasky { 248983ed4f9SMatt Macy lkpi_alloc_current = linux_alloc_current; 2491e3db1deSHans Petter Selasky linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 2501e3db1deSHans Petter Selasky linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 2511e3db1deSHans Petter Selasky } 2521e3db1deSHans Petter Selasky SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL); 2531e3db1deSHans Petter Selasky 2541e3db1deSHans Petter Selasky static void 2551e3db1deSHans Petter Selasky linux_current_uninit(void *arg __unused) 2561e3db1deSHans Petter Selasky { 257abf5c031SMark Johnston struct proc *p; 258abf5c031SMark Johnston struct task_struct *ts; 259abf5c031SMark Johnston struct thread *td; 260abf5c031SMark Johnston 261abf5c031SMark Johnston sx_slock(&allproc_lock); 262abf5c031SMark Johnston FOREACH_PROC_IN_SYSTEM(p) { 263abf5c031SMark Johnston PROC_LOCK(p); 264abf5c031SMark Johnston FOREACH_THREAD_IN_PROC(p, td) { 265abf5c031SMark Johnston if ((ts = td->td_lkpi_task) != NULL) { 266abf5c031SMark Johnston td->td_lkpi_task = NULL; 267abf5c031SMark Johnston put_task_struct(ts); 268abf5c031SMark Johnston } 269abf5c031SMark Johnston } 270abf5c031SMark Johnston PROC_UNLOCK(p); 271abf5c031SMark Johnston } 272abf5c031SMark Johnston sx_sunlock(&allproc_lock); 2731e3db1deSHans Petter Selasky EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); 274983ed4f9SMatt Macy lkpi_alloc_current = linux_alloc_current_noop; 2751e3db1deSHans Petter Selasky } 2761e3db1deSHans Petter Selasky SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL); 277