xref: /freebsd/sys/compat/linux/linux_emul.c (revision 8a15ac837819d19bb5f7d2cfa4ed9b4aa7690148)
1ad2056f2SAlexander Leidinger /*-
2023b850bSEd Maste  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37f2d13d6SPedro F. Giffuni  *
4b267239dSEd Maste  * Copyright (c) 1994-1996 Søren Schmidt
5ad2056f2SAlexander Leidinger  * Copyright (c) 2006 Roman Divacky
681338031SDmitry Chagin  * Copyright (c) 2013 Dmitry Chagin
7ad2056f2SAlexander Leidinger  * All rights reserved.
8ad2056f2SAlexander Leidinger  *
9ad2056f2SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
10ad2056f2SAlexander Leidinger  * modification, are permitted provided that the following conditions
11ad2056f2SAlexander Leidinger  * are met:
12ad2056f2SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
13023b850bSEd Maste  *    notice, this list of conditions and the following disclaimer.
14ad2056f2SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
15ad2056f2SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
16ad2056f2SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
17ad2056f2SAlexander Leidinger  *
18023b850bSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19023b850bSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20023b850bSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21023b850bSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22023b850bSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23023b850bSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24023b850bSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25023b850bSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26023b850bSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27023b850bSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28023b850bSEd Maste  * SUCH DAMAGE.
29ad2056f2SAlexander Leidinger  */
30ad2056f2SAlexander Leidinger 
31ad2056f2SAlexander Leidinger #include <sys/cdefs.h>
32ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$");
33ad2056f2SAlexander Leidinger 
34ad2056f2SAlexander Leidinger #include <sys/param.h>
35ad2056f2SAlexander Leidinger #include <sys/systm.h>
36b267239dSEd Maste #include <sys/fcntl.h>
37ad2056f2SAlexander Leidinger #include <sys/imgact.h>
38b4bb5154SKonstantin Belousov #include <sys/kernel.h>
3981338031SDmitry Chagin #include <sys/ktr.h>
40ad2056f2SAlexander Leidinger #include <sys/lock.h>
41ad2056f2SAlexander Leidinger #include <sys/malloc.h>
42ad2056f2SAlexander Leidinger #include <sys/mutex.h>
43ad2056f2SAlexander Leidinger #include <sys/sx.h>
44ad2056f2SAlexander Leidinger #include <sys/proc.h>
458c5059e9SEdward Tomasz Napierala #include <sys/resourcevar.h>
46ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h>
4795353459SDimitry Andric #include <sys/sysent.h>
48ad2056f2SAlexander Leidinger 
494732e446SRoman Divacky #include <compat/linux/linux_emul.h>
508c5059e9SEdward Tomasz Napierala #include <compat/linux/linux_mib.h>
51d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h>
5223e8912cSDmitry Chagin #include <compat/linux/linux_persona.h>
5381338031SDmitry Chagin #include <compat/linux/linux_util.h>
544732e446SRoman Divacky 
55b267239dSEd Maste #if BYTE_ORDER == LITTLE_ENDIAN
56b267239dSEd Maste #define SHELLMAGIC	0x2123 /* #! */
57b267239dSEd Maste #else
58b267239dSEd Maste #define SHELLMAGIC	0x2321
59b267239dSEd Maste #endif
6019e252baSAlexander Leidinger 
6181338031SDmitry Chagin /*
62bc273677SDmitry Chagin  * This returns reference to the thread emuldata entry (if found)
6381338031SDmitry Chagin  *
6481338031SDmitry Chagin  * Hold PROC_LOCK when referencing emuldata from other threads.
6581338031SDmitry Chagin  */
66ad2056f2SAlexander Leidinger struct linux_emuldata *
6781338031SDmitry Chagin em_find(struct thread *td)
68ad2056f2SAlexander Leidinger {
69ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
70ad2056f2SAlexander Leidinger 
7181338031SDmitry Chagin 	em = td->td_emuldata;
72ad2056f2SAlexander Leidinger 
73ad2056f2SAlexander Leidinger 	return (em);
74ad2056f2SAlexander Leidinger }
75ad2056f2SAlexander Leidinger 
76bc273677SDmitry Chagin /*
77bc273677SDmitry Chagin  * This returns reference to the proc pemuldata entry (if found)
78bc273677SDmitry Chagin  *
79bc273677SDmitry Chagin  * Hold PROC_LOCK when referencing proc pemuldata from other threads.
80bc273677SDmitry Chagin  * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
81bc273677SDmitry Chagin  */
82bc273677SDmitry Chagin struct linux_pemuldata *
83bc273677SDmitry Chagin pem_find(struct proc *p)
84bc273677SDmitry Chagin {
85bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
86bc273677SDmitry Chagin 
87bc273677SDmitry Chagin 	pem = p->p_emuldata;
88bc273677SDmitry Chagin 
89bc273677SDmitry Chagin 	return (pem);
90bc273677SDmitry Chagin }
91bc273677SDmitry Chagin 
928c5059e9SEdward Tomasz Napierala /*
938c5059e9SEdward Tomasz Napierala  * Linux apps generally expect the soft open file limit to be set
948c5059e9SEdward Tomasz Napierala  * to 1024, often iterating over all the file descriptors up to that
958c5059e9SEdward Tomasz Napierala  * limit instead of using closefrom(2).  Give them what they want,
968c5059e9SEdward Tomasz Napierala  * unless there already is a resource limit in place.
978c5059e9SEdward Tomasz Napierala  */
988c5059e9SEdward Tomasz Napierala static void
998c5059e9SEdward Tomasz Napierala linux_set_default_openfiles(struct thread *td, struct proc *p)
1008c5059e9SEdward Tomasz Napierala {
1018c5059e9SEdward Tomasz Napierala 	struct rlimit rlim;
1028c5059e9SEdward Tomasz Napierala 	int error;
1038c5059e9SEdward Tomasz Napierala 
1048c5059e9SEdward Tomasz Napierala 	if (linux_default_openfiles < 0)
1058c5059e9SEdward Tomasz Napierala 		return;
1068c5059e9SEdward Tomasz Napierala 
1078c5059e9SEdward Tomasz Napierala 	PROC_LOCK(p);
1088c5059e9SEdward Tomasz Napierala 	lim_rlimit_proc(p, RLIMIT_NOFILE, &rlim);
1098c5059e9SEdward Tomasz Napierala 	PROC_UNLOCK(p);
1108c5059e9SEdward Tomasz Napierala 	if (rlim.rlim_cur != rlim.rlim_max ||
1118c5059e9SEdward Tomasz Napierala 	    rlim.rlim_cur <= linux_default_openfiles)
1128c5059e9SEdward Tomasz Napierala 		return;
1138c5059e9SEdward Tomasz Napierala 	rlim.rlim_cur = linux_default_openfiles;
1148c5059e9SEdward Tomasz Napierala 	error = kern_proc_setrlimit(td, p, RLIMIT_NOFILE, &rlim);
1158c5059e9SEdward Tomasz Napierala 	KASSERT(error == 0, ("kern_proc_setrlimit failed"));
1168c5059e9SEdward Tomasz Napierala }
1178c5059e9SEdward Tomasz Napierala 
11881338031SDmitry Chagin void
11981338031SDmitry Chagin linux_proc_init(struct thread *td, struct thread *newtd, int flags)
120ad2056f2SAlexander Leidinger {
12181338031SDmitry Chagin 	struct linux_emuldata *em;
122bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
123e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
12468cf0367SDmitry Chagin 	struct proc *p;
12519e252baSAlexander Leidinger 
12681338031SDmitry Chagin 	if (newtd != NULL) {
12768cf0367SDmitry Chagin 		p = newtd->td_proc;
12868cf0367SDmitry Chagin 
12981338031SDmitry Chagin 		/* non-exec call */
13081338031SDmitry Chagin 		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
131a4e3bad7SJung-uk Kim 		if (flags & LINUX_CLONE_THREAD) {
132e16fe1c7SDmitry Chagin 			LINUX_CTR1(proc_init, "thread newtd(%d)",
133e16fe1c7SDmitry Chagin 			    newtd->td_tid);
134e16fe1c7SDmitry Chagin 
13581338031SDmitry Chagin 			em->em_tid = newtd->td_tid;
13681338031SDmitry Chagin 		} else {
13768cf0367SDmitry Chagin 			LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid);
13819e252baSAlexander Leidinger 
13968cf0367SDmitry Chagin 			em->em_tid = p->p_pid;
140bc273677SDmitry Chagin 
141e0d3ea8cSDmitry Chagin 			pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO);
142bc273677SDmitry Chagin 			sx_init(&pem->pem_sx, "lpemlk");
14368cf0367SDmitry Chagin 			p->p_emuldata = pem;
144ad2056f2SAlexander Leidinger 		}
14581338031SDmitry Chagin 		newtd->td_emuldata = em;
1468c5059e9SEdward Tomasz Napierala 
1478c5059e9SEdward Tomasz Napierala 		linux_set_default_openfiles(td, p);
148ad2056f2SAlexander Leidinger 	} else {
14968cf0367SDmitry Chagin 		p = td->td_proc;
15068cf0367SDmitry Chagin 
15119e252baSAlexander Leidinger 		/* exec */
15268cf0367SDmitry Chagin 		LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid);
15319e252baSAlexander Leidinger 
154ad2056f2SAlexander Leidinger 		/* lookup the old one */
15581338031SDmitry Chagin 		em = em_find(td);
156ad2056f2SAlexander Leidinger 		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
15781338031SDmitry Chagin 
15868cf0367SDmitry Chagin 		em->em_tid = p->p_pid;
15997cfa5c8SDmitry Chagin 		em->flags = 0;
16097cfa5c8SDmitry Chagin 		em->robust_futexes = NULL;
16197cfa5c8SDmitry Chagin 		em->child_clear_tid = NULL;
16297cfa5c8SDmitry Chagin 		em->child_set_tid = NULL;
163e16fe1c7SDmitry Chagin 
164e16fe1c7SDmitry Chagin 		 /* epoll should be destroyed in a case of exec. */
16568cf0367SDmitry Chagin 		pem = pem_find(p);
166e16fe1c7SDmitry Chagin 		KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n"));
16723e8912cSDmitry Chagin 		pem->persona = 0;
168e16fe1c7SDmitry Chagin 		if (pem->epoll != NULL) {
169e16fe1c7SDmitry Chagin 			emd = pem->epoll;
170e16fe1c7SDmitry Chagin 			pem->epoll = NULL;
171e16fe1c7SDmitry Chagin 			free(emd, M_EPOLL);
172e16fe1c7SDmitry Chagin 		}
173ad2056f2SAlexander Leidinger 	}
174ad2056f2SAlexander Leidinger 
175ad2056f2SAlexander Leidinger }
176ad2056f2SAlexander Leidinger 
177ad2056f2SAlexander Leidinger void
178ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p)
179ad2056f2SAlexander Leidinger {
180bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
181e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
18281338031SDmitry Chagin 	struct thread *td = curthread;
183ad2056f2SAlexander Leidinger 
184bc273677SDmitry Chagin 	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
185bc273677SDmitry Chagin 		return;
186bc273677SDmitry Chagin 
1877d96520bSDmitry Chagin 	LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p",
1887d96520bSDmitry Chagin 	    td->td_tid, p->p_pid, p);
1897d96520bSDmitry Chagin 
190bc273677SDmitry Chagin 	pem = pem_find(p);
191bc273677SDmitry Chagin 	if (pem == NULL)
192bc273677SDmitry Chagin 		return;
19381338031SDmitry Chagin 	(p->p_sysent->sv_thread_detach)(td);
194bc273677SDmitry Chagin 
195bc273677SDmitry Chagin 	p->p_emuldata = NULL;
196bc273677SDmitry Chagin 
197e16fe1c7SDmitry Chagin 	if (pem->epoll != NULL) {
198e16fe1c7SDmitry Chagin 		emd = pem->epoll;
199e16fe1c7SDmitry Chagin 		pem->epoll = NULL;
200e16fe1c7SDmitry Chagin 		free(emd, M_EPOLL);
201e16fe1c7SDmitry Chagin 	}
202e16fe1c7SDmitry Chagin 
203bc273677SDmitry Chagin 	sx_destroy(&pem->pem_sx);
204e0d3ea8cSDmitry Chagin 	free(pem, M_LINUX);
205e8b8b834SAlexander Leidinger }
206ad2056f2SAlexander Leidinger 
207b267239dSEd Maste /*
208b267239dSEd Maste  * If a Linux binary is exec'ing something, try this image activator
209b267239dSEd Maste  * first.  We override standard shell script execution in order to
210b267239dSEd Maste  * be able to modify the interpreter path.  We only do this if a Linux
211b267239dSEd Maste  * binary is doing the exec, so we do not create an EXEC module for it.
212b267239dSEd Maste  */
213b267239dSEd Maste int
214b267239dSEd Maste linux_exec_imgact_try(struct image_params *imgp)
215b267239dSEd Maste {
216b267239dSEd Maste 	const char *head = (const char *)imgp->image_header;
217b267239dSEd Maste 	char *rpath;
218b267239dSEd Maste 	int error = -1;
219b267239dSEd Maste 
220b267239dSEd Maste 	/*
221b267239dSEd Maste 	 * The interpreter for shell scripts run from a Linux binary needs
222b267239dSEd Maste 	 * to be located in /compat/linux if possible in order to recursively
223b267239dSEd Maste 	 * maintain Linux path emulation.
224b267239dSEd Maste 	 */
225b267239dSEd Maste 	if (((const short *)head)[0] == SHELLMAGIC) {
226b267239dSEd Maste 		/*
227b267239dSEd Maste 		 * Run our normal shell image activator.  If it succeeds attempt
228b267239dSEd Maste 		 * to use the alternate path for the interpreter.  If an
229b267239dSEd Maste 		 * alternate path is found, use our stringspace to store it.
230b267239dSEd Maste 		 */
231b267239dSEd Maste 		if ((error = exec_shell_imgact(imgp)) == 0) {
232b267239dSEd Maste 			linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
233b267239dSEd Maste 			    imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0,
234b267239dSEd Maste 			    AT_FDCWD);
235b267239dSEd Maste 			if (rpath != NULL)
236b267239dSEd Maste 				imgp->args->fname_buf =
237b267239dSEd Maste 				    imgp->interpreter_name = rpath;
238b267239dSEd Maste 		}
239b267239dSEd Maste 	}
240b267239dSEd Maste 	return (error);
241b267239dSEd Maste }
242b267239dSEd Maste 
24381338031SDmitry Chagin int
24481338031SDmitry Chagin linux_common_execve(struct thread *td, struct image_args *eargs)
24581338031SDmitry Chagin {
246bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
247e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
248d707582fSDmitry Chagin 	struct vmspace *oldvmspace;
24981338031SDmitry Chagin 	struct linux_emuldata *em;
25081338031SDmitry Chagin 	struct proc *p;
25181338031SDmitry Chagin 	int error;
252ad2056f2SAlexander Leidinger 
25381338031SDmitry Chagin 	p = td->td_proc;
254ad2056f2SAlexander Leidinger 
255d707582fSDmitry Chagin 	error = pre_execve(td, &oldvmspace);
256d707582fSDmitry Chagin 	if (error != 0)
257d707582fSDmitry Chagin 		return (error);
25881338031SDmitry Chagin 
25981338031SDmitry Chagin 	error = kern_execve(td, eargs, NULL);
260d707582fSDmitry Chagin 	post_execve(td, error, oldvmspace);
261814629ddSEd Schouten 	if (error != EJUSTRETURN)
26281338031SDmitry Chagin 		return (error);
26381338031SDmitry Chagin 
26481338031SDmitry Chagin 	/*
26581338031SDmitry Chagin 	 * In a case of transition from Linux binary execing to
266eae594f7SEd Maste 	 * FreeBSD binary we destroy Linux emuldata thread & proc entries.
26781338031SDmitry Chagin 	 */
26881338031SDmitry Chagin 	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
26981338031SDmitry Chagin 		PROC_LOCK(p);
27081338031SDmitry Chagin 		em = em_find(td);
271bc273677SDmitry Chagin 		KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
27281338031SDmitry Chagin 		td->td_emuldata = NULL;
273bc273677SDmitry Chagin 
274bc273677SDmitry Chagin 		pem = pem_find(p);
275bc273677SDmitry Chagin 		KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
276bc273677SDmitry Chagin 		p->p_emuldata = NULL;
27781338031SDmitry Chagin 		PROC_UNLOCK(p);
27881338031SDmitry Chagin 
279e16fe1c7SDmitry Chagin 		if (pem->epoll != NULL) {
280e16fe1c7SDmitry Chagin 			emd = pem->epoll;
281e16fe1c7SDmitry Chagin 			pem->epoll = NULL;
282e16fe1c7SDmitry Chagin 			free(emd, M_EPOLL);
283e16fe1c7SDmitry Chagin 		}
284e16fe1c7SDmitry Chagin 
28581338031SDmitry Chagin 		free(em, M_TEMP);
286e0d3ea8cSDmitry Chagin 		free(pem, M_LINUX);
28781338031SDmitry Chagin 	}
288814629ddSEd Schouten 	return (EJUSTRETURN);
28981338031SDmitry Chagin }
29081338031SDmitry Chagin 
29181338031SDmitry Chagin void
29281338031SDmitry Chagin linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
29381338031SDmitry Chagin {
294*8a15ac83SKonstantin Belousov 	struct thread *td;
29532ba368bSDmitry Chagin 	struct thread *othertd;
29623e8912cSDmitry Chagin #if defined(__amd64__)
29723e8912cSDmitry Chagin 	struct linux_pemuldata *pem;
29823e8912cSDmitry Chagin #endif
29932ba368bSDmitry Chagin 
300*8a15ac83SKonstantin Belousov 	td = curthread;
30181338031SDmitry Chagin 
30281338031SDmitry Chagin 	/*
303eae594f7SEd Maste 	 * In a case of execing to Linux binary we create Linux
30481338031SDmitry Chagin 	 * emuldata thread entry.
30581338031SDmitry Chagin 	 */
30681338031SDmitry Chagin 	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
30781338031SDmitry Chagin 	    SV_ABI_LINUX)) {
308*8a15ac83SKonstantin Belousov 		if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
309*8a15ac83SKonstantin Belousov 			/*
310*8a15ac83SKonstantin Belousov 			 * Process already was under Linuxolator
311*8a15ac83SKonstantin Belousov 			 * before exec.  Update emuldata to reflect
312*8a15ac83SKonstantin Belousov 			 * single-threaded cleaned state after exec.
313*8a15ac83SKonstantin Belousov 			 */
31481338031SDmitry Chagin 			linux_proc_init(td, NULL, 0);
315*8a15ac83SKonstantin Belousov 		} else {
316*8a15ac83SKonstantin Belousov 			/*
317*8a15ac83SKonstantin Belousov 			 * We are switching the process to Linux emulator.
318*8a15ac83SKonstantin Belousov 			 */
31981338031SDmitry Chagin 			linux_proc_init(td, td, 0);
320*8a15ac83SKonstantin Belousov 
321*8a15ac83SKonstantin Belousov 			/*
322*8a15ac83SKonstantin Belousov 			 * Create a transient td_emuldata for all suspended
323*8a15ac83SKonstantin Belousov 			 * threads, so that p->p_sysent->sv_thread_detach() ==
324*8a15ac83SKonstantin Belousov 			 * linux_thread_detach() can find expected but unused
325*8a15ac83SKonstantin Belousov 			 * emuldata.
326*8a15ac83SKonstantin Belousov 			 */
327*8a15ac83SKonstantin Belousov 			FOREACH_THREAD_IN_PROC(td->td_proc, othertd) {
328*8a15ac83SKonstantin Belousov 				if (othertd != td) {
329*8a15ac83SKonstantin Belousov 					linux_proc_init(td, othertd,
330*8a15ac83SKonstantin Belousov 					    LINUX_CLONE_THREAD);
331*8a15ac83SKonstantin Belousov 				}
332*8a15ac83SKonstantin Belousov 			}
333*8a15ac83SKonstantin Belousov 		}
33423e8912cSDmitry Chagin #if defined(__amd64__)
33523e8912cSDmitry Chagin 		/*
33623e8912cSDmitry Chagin 		 * An IA32 executable which has executable stack will have the
33723e8912cSDmitry Chagin 		 * READ_IMPLIES_EXEC personality flag set automatically.
33823e8912cSDmitry Chagin 		 */
33923e8912cSDmitry Chagin 		if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
34023e8912cSDmitry Chagin 		    imgp->stack_prot & VM_PROT_EXECUTE) {
34123e8912cSDmitry Chagin 			pem = pem_find(p);
34223e8912cSDmitry Chagin 			pem->persona |= LINUX_READ_IMPLIES_EXEC;
34323e8912cSDmitry Chagin 		}
34423e8912cSDmitry Chagin #endif
34581338031SDmitry Chagin 	}
34681338031SDmitry Chagin }
34781338031SDmitry Chagin 
34881338031SDmitry Chagin void
34981338031SDmitry Chagin linux_thread_dtor(void *arg __unused, struct thread *td)
350ad2056f2SAlexander Leidinger {
351ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
352ad2056f2SAlexander Leidinger 
35381338031SDmitry Chagin 	em = em_find(td);
35481338031SDmitry Chagin 	if (em == NULL)
35581338031SDmitry Chagin 		return;
35681338031SDmitry Chagin 	td->td_emuldata = NULL;
357ad2056f2SAlexander Leidinger 
3587d96520bSDmitry Chagin 	LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
359ad2056f2SAlexander Leidinger 
36081338031SDmitry Chagin 	free(em, M_TEMP);
361ad2056f2SAlexander Leidinger }
362ad2056f2SAlexander Leidinger 
363ad2056f2SAlexander Leidinger void
364e5d81ef1SDmitry Chagin linux_schedtail(struct thread *td)
365ad2056f2SAlexander Leidinger {
366ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
367e5d81ef1SDmitry Chagin 	struct proc *p;
368ad2056f2SAlexander Leidinger 	int error = 0;
369ad2056f2SAlexander Leidinger 	int *child_set_tid;
370ad2056f2SAlexander Leidinger 
371e5d81ef1SDmitry Chagin 	p = td->td_proc;
372e5d81ef1SDmitry Chagin 
37381338031SDmitry Chagin 	em = em_find(td);
374bc273677SDmitry Chagin 	KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
375ad2056f2SAlexander Leidinger 	child_set_tid = em->child_set_tid;
376ad2056f2SAlexander Leidinger 
37719e252baSAlexander Leidinger 	if (child_set_tid != NULL) {
378e0327ddbSDmitry Chagin 		error = copyout(&em->em_tid, child_set_tid,
37981338031SDmitry Chagin 		    sizeof(em->em_tid));
3807d96520bSDmitry Chagin 		LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d",
38181338031SDmitry Chagin 		    td->td_tid, child_set_tid, em->em_tid, error);
38281338031SDmitry Chagin 	} else
3837d96520bSDmitry Chagin 		LINUX_CTR1(schedtail, "thread(%d)", em->em_tid);
384bb63fddeSAlexander Leidinger }
385