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 proc *proc; 46 struct thread *td_other; 47 struct task_struct *ts; 48 struct task_struct *ts_other; 49 struct mm_struct *mm; 50 struct mm_struct *mm_other; 51 52 MPASS(td->td_lkpi_task == NULL); 53 54 ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO); 55 if (ts == NULL) 56 return (ENOMEM); 57 58 mm = malloc(sizeof(*mm), M_LINUX_CURRENT, flags | M_ZERO); 59 if (mm == NULL) { 60 free(ts, M_LINUX_CURRENT); 61 return (ENOMEM); 62 } 63 64 /* setup new task structure */ 65 atomic_set(&ts->kthread_flags, 0); 66 ts->task_thread = td; 67 ts->comm = td->td_name; 68 ts->pid = td->td_tid; 69 atomic_set(&ts->usage, 1); 70 ts->state = TASK_RUNNING; 71 72 proc = td->td_proc; 73 74 /* check if another thread already has a mm_struct */ 75 PROC_LOCK(proc); 76 FOREACH_THREAD_IN_PROC(proc, td_other) { 77 ts_other = td_other->td_lkpi_task; 78 if (ts_other == NULL) 79 continue; 80 81 mm_other = ts_other->mm; 82 if (mm_other == NULL) 83 continue; 84 85 /* try to share other mm_struct */ 86 if (atomic_inc_not_zero(&mm_other->mm_users)) { 87 /* set mm_struct pointer */ 88 ts->mm = mm_other; 89 break; 90 } 91 } 92 93 /* use allocated mm_struct as a fallback */ 94 if (ts->mm == NULL) { 95 /* setup new mm_struct */ 96 init_rwsem(&mm->mmap_sem); 97 atomic_set(&mm->mm_count, 1); 98 atomic_set(&mm->mm_users, 1); 99 /* set mm_struct pointer */ 100 ts->mm = mm; 101 /* clear pointer to not free memory */ 102 mm = NULL; 103 } 104 105 /* store pointer to task struct */ 106 td->td_lkpi_task = ts; 107 PROC_UNLOCK(proc); 108 109 /* free mm_struct pointer, if any */ 110 free(mm, M_LINUX_CURRENT); 111 112 return (0); 113 } 114 115 struct mm_struct * 116 linux_get_task_mm(struct task_struct *task) 117 { 118 struct mm_struct *mm; 119 120 mm = task->mm; 121 if (mm != NULL) { 122 atomic_inc(&mm->mm_users); 123 return (mm); 124 } 125 return (NULL); 126 } 127 128 void 129 linux_mm_dtor(struct mm_struct *mm) 130 { 131 free(mm, M_LINUX_CURRENT); 132 } 133 134 void 135 linux_free_current(struct task_struct *ts) 136 { 137 mmput(ts->mm); 138 free(ts, M_LINUX_CURRENT); 139 } 140 141 static void 142 linuxkpi_thread_dtor(void *arg __unused, struct thread *td) 143 { 144 struct task_struct *ts; 145 146 ts = td->td_lkpi_task; 147 if (ts == NULL) 148 return; 149 150 td->td_lkpi_task = NULL; 151 put_task_struct(ts); 152 } 153 154 struct task_struct * 155 linux_pid_task(pid_t pid) 156 { 157 struct thread *td; 158 struct proc *p; 159 160 /* try to find corresponding thread */ 161 td = tdfind(pid, -1); 162 if (td != NULL) { 163 struct task_struct *ts = td->td_lkpi_task; 164 PROC_UNLOCK(td->td_proc); 165 return (ts); 166 } 167 168 /* try to find corresponding procedure */ 169 p = pfind(pid); 170 if (p != NULL) { 171 FOREACH_THREAD_IN_PROC(p, td) { 172 struct task_struct *ts = td->td_lkpi_task; 173 if (ts != NULL) { 174 PROC_UNLOCK(p); 175 return (ts); 176 } 177 } 178 PROC_UNLOCK(p); 179 } 180 return (NULL); 181 } 182 183 struct task_struct * 184 linux_get_pid_task(pid_t pid) 185 { 186 struct thread *td; 187 struct proc *p; 188 189 /* try to find corresponding thread */ 190 td = tdfind(pid, -1); 191 if (td != NULL) { 192 struct task_struct *ts = td->td_lkpi_task; 193 if (ts != NULL) 194 get_task_struct(ts); 195 PROC_UNLOCK(td->td_proc); 196 return (ts); 197 } 198 199 /* try to find corresponding procedure */ 200 p = pfind(pid); 201 if (p != NULL) { 202 FOREACH_THREAD_IN_PROC(p, td) { 203 struct task_struct *ts = td->td_lkpi_task; 204 if (ts != NULL) { 205 get_task_struct(ts); 206 PROC_UNLOCK(p); 207 return (ts); 208 } 209 } 210 PROC_UNLOCK(p); 211 } 212 return (NULL); 213 } 214 215 static void 216 linux_current_init(void *arg __unused) 217 { 218 linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 219 linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 220 } 221 SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL); 222 223 static void 224 linux_current_uninit(void *arg __unused) 225 { 226 EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag); 227 } 228 SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL); 229