1 /*- 2 * Copyright (c) 2017 Hans Petter Selasky 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <linux/compat.h> 31 #include <linux/mm.h> 32 #include <linux/kthread.h> 33 34 #include <sys/kernel.h> 35 #include <sys/eventhandler.h> 36 #include <sys/malloc.h> 37 38 static eventhandler_tag linuxkpi_thread_dtor_tag; 39 40 static MALLOC_DEFINE(M_LINUX_CURRENT, "linuxcurrent", "LinuxKPI task structure"); 41 42 int 43 linux_alloc_current(struct thread *td, int flags) 44 { 45 struct task_struct *ts; 46 struct mm_struct *mm; 47 48 MPASS(td->td_lkpi_task == NULL); 49 50 ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO); 51 if (ts == NULL) 52 return (ENOMEM); 53 54 mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO); 55 if (mm == NULL) { 56 free(ts, M_LINUX_CURRENT); 57 return (ENOMEM); 58 } 59 60 atomic_set(&ts->kthread_flags, 0); 61 ts->task_thread = td; 62 ts->comm = td->td_name; 63 ts->pid = td->td_tid; 64 ts->mm = mm; 65 atomic_set(&ts->usage, 1); 66 ts->state = TASK_RUNNING; 67 68 /* setup mm_struct */ 69 init_rwsem(&mm->mmap_sem); 70 atomic_set(&mm->mm_count, 1); 71 atomic_set(&mm->mm_users, 1); 72 mm->vmspace = vmspace_acquire_ref(td->td_proc); 73 74 /* store pointer to task struct */ 75 td->td_lkpi_task = ts; 76 return (0); 77 } 78 79 struct mm_struct * 80 linux_get_task_mm(struct task_struct *task) 81 { 82 struct mm_struct *mm; 83 84 mm = task->mm; 85 if (mm != NULL && mm->vmspace != NULL) { 86 atomic_inc(&mm->mm_users); 87 return (mm); 88 } 89 return (NULL); 90 } 91 92 void 93 linux_mm_dtor(struct mm_struct *mm) 94 { 95 if (mm->vmspace != NULL) 96 vmspace_free(mm->vmspace); 97 free(mm, M_LINUX_CURRENT); 98 } 99 100 void 101 linux_free_current(struct task_struct *ts) 102 { 103 mmput(ts->mm); 104 free(ts, M_LINUX_CURRENT); 105 } 106 107 static void 108 linuxkpi_thread_dtor(void *arg __unused, struct thread *td) 109 { 110 struct task_struct *ts; 111 112 ts = td->td_lkpi_task; 113 if (ts == NULL) 114 return; 115 116 td->td_lkpi_task = NULL; 117 put_task_struct(ts); 118 } 119 120 struct task_struct * 121 linux_pid_task(pid_t pid) 122 { 123 struct thread *td; 124 125 td = tdfind(pid, -1); 126 if (td != NULL) { 127 struct task_struct *ts = td->td_lkpi_task; 128 PROC_UNLOCK(td->td_proc); 129 return (ts); 130 } 131 return (NULL); 132 } 133 134 struct task_struct * 135 linux_get_pid_task(pid_t pid) 136 { 137 struct thread *td; 138 139 td = tdfind(pid, -1); 140 if (td != NULL) { 141 struct task_struct *ts = td->td_lkpi_task; 142 if (ts != NULL) 143 get_task_struct(ts); 144 PROC_UNLOCK(td->td_proc); 145 return (ts); 146 } 147 return (NULL); 148 } 149 150 static void 151 linux_current_init(void *arg __unused) 152 { 153 linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 154 linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 155 } 156 SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL); 157 158 static void 159 linux_current_uninit(void *arg __unused) 160 { 161 EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); 162 } 163 SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL); 164