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