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; 70a0699ebfSHans Petter Selasky atomic_set(&ts->usage, 1); 711e3db1deSHans Petter Selasky ts->state = TASK_RUNNING; 728504aa98SMark Johnston init_completion(&ts->parked); 738504aa98SMark Johnston init_completion(&ts->exited); 7405d4f501SHans Petter Selasky 75e54b103eSHans Petter Selasky proc = td->td_proc; 76e54b103eSHans Petter Selasky 77e54b103eSHans Petter Selasky /* check if another thread already has a mm_struct */ 78e54b103eSHans Petter Selasky PROC_LOCK(proc); 79e54b103eSHans Petter Selasky FOREACH_THREAD_IN_PROC(proc, td_other) { 80e54b103eSHans Petter Selasky ts_other = td_other->td_lkpi_task; 81e54b103eSHans Petter Selasky if (ts_other == NULL) 82e54b103eSHans Petter Selasky continue; 83e54b103eSHans Petter Selasky 84e54b103eSHans Petter Selasky mm_other = ts_other->mm; 85e54b103eSHans Petter Selasky if (mm_other == NULL) 86e54b103eSHans Petter Selasky continue; 87e54b103eSHans Petter Selasky 88e54b103eSHans Petter Selasky /* try to share other mm_struct */ 89e54b103eSHans Petter Selasky if (atomic_inc_not_zero(&mm_other->mm_users)) { 90e54b103eSHans Petter Selasky /* set mm_struct pointer */ 91e54b103eSHans Petter Selasky ts->mm = mm_other; 92e54b103eSHans Petter Selasky break; 93e54b103eSHans Petter Selasky } 94e54b103eSHans Petter Selasky } 95e54b103eSHans Petter Selasky 96e54b103eSHans Petter Selasky /* use allocated mm_struct as a fallback */ 97e54b103eSHans Petter Selasky if (ts->mm == NULL) { 98e54b103eSHans Petter Selasky /* setup new mm_struct */ 9905d4f501SHans Petter Selasky init_rwsem(&mm->mmap_sem); 10005d4f501SHans Petter Selasky atomic_set(&mm->mm_count, 1); 10105d4f501SHans Petter Selasky atomic_set(&mm->mm_users, 1); 102e54b103eSHans Petter Selasky /* set mm_struct pointer */ 103e54b103eSHans Petter Selasky ts->mm = mm; 104e54b103eSHans Petter Selasky /* clear pointer to not free memory */ 105e54b103eSHans Petter Selasky mm = NULL; 106e54b103eSHans Petter Selasky } 10705d4f501SHans Petter Selasky 10805d4f501SHans Petter Selasky /* store pointer to task struct */ 1091e3db1deSHans Petter Selasky td->td_lkpi_task = ts; 110e54b103eSHans Petter Selasky PROC_UNLOCK(proc); 111e54b103eSHans Petter Selasky 112e54b103eSHans Petter Selasky /* free mm_struct pointer, if any */ 113e54b103eSHans Petter Selasky free(mm, M_LINUX_CURRENT); 114e54b103eSHans Petter Selasky 1151e3db1deSHans Petter Selasky return (0); 1161e3db1deSHans Petter Selasky } 1171e3db1deSHans Petter Selasky 11805d4f501SHans Petter Selasky struct mm_struct * 11905d4f501SHans Petter Selasky linux_get_task_mm(struct task_struct *task) 12005d4f501SHans Petter Selasky { 12105d4f501SHans Petter Selasky struct mm_struct *mm; 12205d4f501SHans Petter Selasky 12305d4f501SHans Petter Selasky mm = task->mm; 12468b9f2f0SHans Petter Selasky if (mm != NULL) { 12505d4f501SHans Petter Selasky atomic_inc(&mm->mm_users); 12605d4f501SHans Petter Selasky return (mm); 12705d4f501SHans Petter Selasky } 12805d4f501SHans Petter Selasky return (NULL); 12905d4f501SHans Petter Selasky } 13005d4f501SHans Petter Selasky 13105d4f501SHans Petter Selasky void 13205d4f501SHans Petter Selasky linux_mm_dtor(struct mm_struct *mm) 13305d4f501SHans Petter Selasky { 13405d4f501SHans Petter Selasky free(mm, M_LINUX_CURRENT); 13505d4f501SHans Petter Selasky } 13605d4f501SHans Petter Selasky 1371e3db1deSHans Petter Selasky void 1381e3db1deSHans Petter Selasky linux_free_current(struct task_struct *ts) 1391e3db1deSHans Petter Selasky { 14005d4f501SHans Petter Selasky mmput(ts->mm); 1411e3db1deSHans Petter Selasky free(ts, M_LINUX_CURRENT); 1421e3db1deSHans Petter Selasky } 1431e3db1deSHans Petter Selasky 1441e3db1deSHans Petter Selasky static void 1451e3db1deSHans Petter Selasky linuxkpi_thread_dtor(void *arg __unused, struct thread *td) 1461e3db1deSHans Petter Selasky { 1471e3db1deSHans Petter Selasky struct task_struct *ts; 1481e3db1deSHans Petter Selasky 1491e3db1deSHans Petter Selasky ts = td->td_lkpi_task; 1501e3db1deSHans Petter Selasky if (ts == NULL) 1511e3db1deSHans Petter Selasky return; 1521e3db1deSHans Petter Selasky 1531e3db1deSHans Petter Selasky td->td_lkpi_task = NULL; 154a0699ebfSHans Petter Selasky put_task_struct(ts); 155a0699ebfSHans Petter Selasky } 156a0699ebfSHans Petter Selasky 157a0699ebfSHans Petter Selasky struct task_struct * 158a0699ebfSHans Petter Selasky linux_pid_task(pid_t pid) 159a0699ebfSHans Petter Selasky { 160a0699ebfSHans Petter Selasky struct thread *td; 1618402f058SHans Petter Selasky struct proc *p; 162a0699ebfSHans Petter Selasky 1638402f058SHans Petter Selasky /* try to find corresponding thread */ 164a0699ebfSHans Petter Selasky td = tdfind(pid, -1); 165a0699ebfSHans Petter Selasky if (td != NULL) { 166a0699ebfSHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 167a0699ebfSHans Petter Selasky PROC_UNLOCK(td->td_proc); 168a0699ebfSHans Petter Selasky return (ts); 169a0699ebfSHans Petter Selasky } 1708402f058SHans Petter Selasky 1718402f058SHans Petter Selasky /* try to find corresponding procedure */ 1728402f058SHans Petter Selasky p = pfind(pid); 1738402f058SHans Petter Selasky if (p != NULL) { 1748402f058SHans Petter Selasky FOREACH_THREAD_IN_PROC(p, td) { 1758402f058SHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 1768402f058SHans Petter Selasky if (ts != NULL) { 1778402f058SHans Petter Selasky PROC_UNLOCK(p); 1788402f058SHans Petter Selasky return (ts); 1798402f058SHans Petter Selasky } 1808402f058SHans Petter Selasky } 1818402f058SHans Petter Selasky PROC_UNLOCK(p); 1828402f058SHans Petter Selasky } 183a0699ebfSHans Petter Selasky return (NULL); 184a0699ebfSHans Petter Selasky } 185a0699ebfSHans Petter Selasky 186a0699ebfSHans Petter Selasky struct task_struct * 187a0699ebfSHans Petter Selasky linux_get_pid_task(pid_t pid) 188a0699ebfSHans Petter Selasky { 189a0699ebfSHans Petter Selasky struct thread *td; 1908402f058SHans Petter Selasky struct proc *p; 191a0699ebfSHans Petter Selasky 1928402f058SHans Petter Selasky /* try to find corresponding thread */ 193a0699ebfSHans Petter Selasky td = tdfind(pid, -1); 194a0699ebfSHans Petter Selasky if (td != NULL) { 195a0699ebfSHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 196a0699ebfSHans Petter Selasky if (ts != NULL) 197a0699ebfSHans Petter Selasky get_task_struct(ts); 198a0699ebfSHans Petter Selasky PROC_UNLOCK(td->td_proc); 199a0699ebfSHans Petter Selasky return (ts); 200a0699ebfSHans Petter Selasky } 2018402f058SHans Petter Selasky 2028402f058SHans Petter Selasky /* try to find corresponding procedure */ 2038402f058SHans Petter Selasky p = pfind(pid); 2048402f058SHans Petter Selasky if (p != NULL) { 2058402f058SHans Petter Selasky FOREACH_THREAD_IN_PROC(p, td) { 2068402f058SHans Petter Selasky struct task_struct *ts = td->td_lkpi_task; 2078402f058SHans Petter Selasky if (ts != NULL) { 2088402f058SHans Petter Selasky get_task_struct(ts); 2098402f058SHans Petter Selasky PROC_UNLOCK(p); 2108402f058SHans Petter Selasky return (ts); 2118402f058SHans Petter Selasky } 2128402f058SHans Petter Selasky } 2138402f058SHans Petter Selasky PROC_UNLOCK(p); 2148402f058SHans Petter Selasky } 215a0699ebfSHans Petter Selasky return (NULL); 2161e3db1deSHans Petter Selasky } 2171e3db1deSHans Petter Selasky 2181e3db1deSHans Petter Selasky static void 2191e3db1deSHans Petter Selasky linux_current_init(void *arg __unused) 2201e3db1deSHans Petter Selasky { 2211e3db1deSHans Petter Selasky linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 2221e3db1deSHans Petter Selasky linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 2231e3db1deSHans Petter Selasky } 2241e3db1deSHans Petter Selasky SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL); 2251e3db1deSHans Petter Selasky 2261e3db1deSHans Petter Selasky static void 2271e3db1deSHans Petter Selasky linux_current_uninit(void *arg __unused) 2281e3db1deSHans Petter Selasky { 2291e3db1deSHans Petter Selasky EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); 2301e3db1deSHans Petter Selasky } 2311e3db1deSHans Petter Selasky SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL); 232