From bc273677607433dc32f6586c964a469f19867818 Mon Sep 17 00:00:00 2001 From: Dmitry Chagin Date: Sun, 24 May 2015 15:54:58 +0000 Subject: [PATCH] Refund the proc emuldata struct for future use. For now move flags from thread emuldata to proc emuldata as it was originally intended. As we can have both 64 & 32 bit Linuxulator running any eventhandler can be called twice for us. To prevent this move eventhandlers code from linux_emul.c to the linux_common.ko module. Differential Revision: https://reviews.freebsd.org/D1073 --- sys/amd64/linux32/linux32_sysvec.c | 13 -- sys/compat/linux/linux_common.c | 25 +++- sys/compat/linux/linux_emul.c | 202 +++++++---------------------- sys/compat/linux/linux_emul.h | 21 ++- sys/compat/linux/linux_fork.c | 61 +++++++++ sys/compat/linux/linux_futex.c | 8 +- sys/compat/linux/linux_misc.c | 15 +++ sys/modules/linux/Makefile | 5 +- sys/modules/linux_common/Makefile | 2 +- 9 files changed, 164 insertions(+), 188 deletions(-) diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index aa98c96b230c..f07f56e0d0a4 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -130,10 +130,6 @@ static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); static void linux_vdso_install(void *param); static void linux_vdso_deinstall(void *param); -static eventhandler_tag linux_exit_tag; -static eventhandler_tag linux_exec_tag; -static eventhandler_tag linux_thread_dtor_tag; - /* * Linux syscalls return negative errno's, we do positive and map them * Reference: @@ -1170,12 +1166,6 @@ linux_elf_modevent(module_t mod, int type, void *data) linux_ioctl_register_handler(*lihp); LIST_INIT(&futex_list); mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); - linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, - linux_proc_exit, NULL, 1000); - linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, - linux_proc_exec, NULL, 1000); - linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, - linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); stclohz = (stathz ? stathz : hz); if (bootverbose) printf("Linux ELF exec handler installed\n"); @@ -1197,9 +1187,6 @@ linux_elf_modevent(module_t mod, int type, void *data) SET_FOREACH(lihp, linux_ioctl_handler_set) linux_ioctl_unregister_handler(*lihp); mtx_destroy(&futex_mtx); - EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); - EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); - EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag); if (bootverbose) printf("Linux ELF exec handler removed\n"); } else diff --git a/sys/compat/linux/linux_common.c b/sys/compat/linux/linux_common.c index 5427b61c7898..3cee92a4d624 100644 --- a/sys/compat/linux/linux_common.c +++ b/sys/compat/linux/linux_common.c @@ -28,13 +28,15 @@ __FBSDID("$FreeBSD$"); #include -#include -#include -#include -#include +#include +#include +#include +#include #include -#include +#include +#include +#include #include #include @@ -42,6 +44,10 @@ MODULE_VERSION(linux_common, 1); SET_DECLARE(linux_device_handler_set, struct linux_device_handler); +static eventhandler_tag linux_exec_tag; +static eventhandler_tag linux_thread_dtor_tag; +static eventhandler_tag linux_exit_tag; + static int linux_common_modevent(module_t mod, int type, void *data) @@ -51,6 +57,12 @@ linux_common_modevent(module_t mod, int type, void *data) switch(type) { case MOD_LOAD: linux_osd_jail_register(); + linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, + linux_proc_exit, NULL, 1000); + linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, + linux_proc_exec, NULL, 1000); + linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, + linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); SET_FOREACH(ldhp, linux_device_handler_set) linux_device_register_handler(*ldhp); break; @@ -58,6 +70,9 @@ linux_common_modevent(module_t mod, int type, void *data) linux_osd_jail_deregister(); SET_FOREACH(ldhp, linux_device_handler_set) linux_device_unregister_handler(*ldhp); + EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); + EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); + EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag); break; default: return (EOPNOTSUPP); diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c index 502e936a2c9f..b9f2373f2e67 100644 --- a/sys/compat/linux/linux_emul.c +++ b/sys/compat/linux/linux_emul.c @@ -30,8 +30,6 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_compat.h" - #include #include #include @@ -40,7 +38,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -48,60 +45,13 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef COMPAT_LINUX32 -#include -#include -#else -#include -#include -#endif - -#include #include -#include #include #include -/** - * Special DTrace provider for the linuxulator. - * - * In this file we define the provider for the entire linuxulator. All - * modules (= files of the linuxulator) use it. - * - * We define a different name depending on the emulated bitsize, see - * ../..//linux{,32}/linux.h, e.g.: - * native bitsize = linuxulator - * amd64, 32bit emulation = linuxulator32 - */ -LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); - -/** - * DTrace probes in this module. - */ -LIN_SDT_PROBE_DEFINE1(emul, em_find, entry, "struct thread *"); -LIN_SDT_PROBE_DEFINE0(emul, em_find, return); -LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", - "struct thread *", "int"); -LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread); -LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork); -LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec); -LIN_SDT_PROBE_DEFINE0(emul, proc_init, return); -LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *"); -LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, entry, "struct thread *"); -LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, futex_failed); -LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, child_clear_tid_error, "int"); -LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, return); -LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *", - "struct image_params *"); -LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return); -LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry); -LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int"); -LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return); -LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *"); -LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return); /* - * This returns reference to the emuldata entry (if found) + * This returns reference to the thread emuldata entry (if found) * * Hold PROC_LOCK when referencing emuldata from other threads. */ @@ -110,41 +60,51 @@ em_find(struct thread *td) { struct linux_emuldata *em; - LIN_SDT_PROBE1(emul, em_find, entry, td); - em = td->td_emuldata; - LIN_SDT_PROBE1(emul, em_find, return, em); - return (em); } +/* + * This returns reference to the proc pemuldata entry (if found) + * + * Hold PROC_LOCK when referencing proc pemuldata from other threads. + * Hold LINUX_PEM_LOCK wher referencing pemuldata members. + */ +struct linux_pemuldata * +pem_find(struct proc *p) +{ + struct linux_pemuldata *pem; + + pem = p->p_emuldata; + + return (pem); +} + void linux_proc_init(struct thread *td, struct thread *newtd, int flags) { struct linux_emuldata *em; - - LIN_SDT_PROBE3(emul, proc_init, entry, td, newtd, flags); + struct linux_pemuldata *pem; if (newtd != NULL) { /* non-exec call */ em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); em->pdeath_signal = 0; - em->flags = 0; em->robust_futexes = NULL; if (flags & LINUX_CLONE_THREAD) { - LIN_SDT_PROBE0(emul, proc_init, create_thread); - em->em_tid = newtd->td_tid; } else { - LIN_SDT_PROBE0(emul, proc_init, fork); em->em_tid = newtd->td_proc->p_pid; + + pem = malloc(sizeof(*pem), M_TEMP, M_WAITOK | M_ZERO); + sx_init(&pem->pem_sx, "lpemlk"); + newtd->td_proc->p_emuldata = pem; } newtd->td_emuldata = em; } else { /* exec */ - LIN_SDT_PROBE0(emul, proc_init, exec); /* lookup the old one */ em = em_find(td); @@ -155,24 +115,32 @@ linux_proc_init(struct thread *td, struct thread *newtd, int flags) em->child_clear_tid = NULL; em->child_set_tid = NULL; - - LIN_SDT_PROBE0(emul, proc_init, return); } void linux_proc_exit(void *arg __unused, struct proc *p) { + struct linux_pemuldata *pem; struct thread *td = curthread; - if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) { - LIN_SDT_PROBE1(emul, proc_exit, entry, p); - (p->p_sysent->sv_thread_detach)(td); - } + if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) + return; + + pem = pem_find(p); + if (pem == NULL) + return; + (p->p_sysent->sv_thread_detach)(td); + + p->p_emuldata = NULL; + + sx_destroy(&pem->pem_sx); + free(pem, M_TEMP); } int linux_common_execve(struct thread *td, struct image_args *eargs) { + struct linux_pemuldata *pem; struct linux_emuldata *em; struct proc *p; int error; @@ -199,16 +167,21 @@ linux_common_execve(struct thread *td, struct image_args *eargs) /* * In a case of transition from Linux binary execing to - * FreeBSD binary we destroy linux emuldata thread entry. + * FreeBSD binary we destroy linux emuldata thread & proc entries. */ if (SV_CURPROC_ABI() != SV_ABI_LINUX) { PROC_LOCK(p); em = em_find(td); - KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); + KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); td->td_emuldata = NULL; + + pem = pem_find(p); + KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); + p->p_emuldata = NULL; PROC_UNLOCK(p); free(em, M_TEMP); + free(pem, M_TEMP); } return (0); } @@ -224,70 +197,13 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) */ if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX)) { - LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp); if (SV_PROC_ABI(p) == SV_ABI_LINUX) linux_proc_init(td, NULL, 0); else linux_proc_init(td, td, 0); - - LIN_SDT_PROBE0(emul, proc_exec, return); } } -void -linux_thread_detach(struct thread *td) -{ - struct linux_sys_futex_args cup; - struct linux_emuldata *em; - int *child_clear_tid; - int null = 0; - int error; - - LIN_SDT_PROBE1(emul, linux_thread_detach, entry, td); - - em = em_find(td); - KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); - - LINUX_CTR1(exit, "thread detach(%d)", em->em_tid); - - release_futexes(td, em); - - child_clear_tid = em->child_clear_tid; - - if (child_clear_tid != NULL) { - - LINUX_CTR2(exit, "thread detach(%d) %p", - em->em_tid, child_clear_tid); - - error = copyout(&null, child_clear_tid, sizeof(null)); - if (error) { - LIN_SDT_PROBE1(emul, linux_thread_detach, - child_clear_tid_error, error); - - LIN_SDT_PROBE0(emul, linux_thread_detach, return); - return; - } - - cup.uaddr = child_clear_tid; - cup.op = LINUX_FUTEX_WAKE; - cup.val = 1; /* wake one */ - cup.timeout = NULL; - cup.uaddr2 = NULL; - cup.val3 = 0; - error = linux_sys_futex(td, &cup); - /* - * this cannot happen at the moment and if this happens it - * probably means there is a user space bug - */ - if (error) { - LIN_SDT_PROBE0(emul, linux_thread_detach, futex_failed); - printf(LMSG("futex stuff in thread_detach failed.\n")); - } - } - - LIN_SDT_PROBE0(emul, linux_thread_detach, return); -} - void linux_thread_dtor(void *arg __unused, struct thread *td) { @@ -311,12 +227,10 @@ linux_schedtail(struct thread *td) int error = 0; int *child_set_tid; - LIN_SDT_PROBE1(emul, linux_schedtail, entry, td); - p = td->td_proc; em = em_find(td); - KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); + KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); child_set_tid = em->child_set_tid; if (child_set_tid != NULL) { @@ -324,34 +238,6 @@ linux_schedtail(struct thread *td) sizeof(em->em_tid)); LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d", td->td_tid, child_set_tid, em->em_tid, error); - - if (error != 0) { - LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error, - error); - } } else LINUX_CTR1(clone, "schedtail(%d)", em->em_tid); - - LIN_SDT_PROBE0(emul, linux_schedtail, return); -} - -int -linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) -{ - struct linux_emuldata *em; - - LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr); - - em = em_find(td); - KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); - - em->child_clear_tid = args->tidptr; - - td->td_retval[0] = em->em_tid; - - LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", - em->em_tid, args->tidptr, td->td_retval[0]); - - LIN_SDT_PROBE0(emul, linux_set_tid_address, return); - return (0); } diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h index ae482f947f18..21787010bfbf 100644 --- a/sys/compat/linux/linux_emul.h +++ b/sys/compat/linux/linux_emul.h @@ -41,7 +41,7 @@ struct linux_emuldata { int *child_clear_tid;/* in clone(): Child's TID to clear on exit */ int pdeath_signal; /* parent death signal */ - int flags; /* different emuldata flags */ + int flags; /* thread emuldata flags */ int em_tid; /* thread id */ struct linux_robust_list_head *robust_futexes; @@ -49,10 +49,6 @@ struct linux_emuldata { struct linux_emuldata *em_find(struct thread *); -/* emuldata flags */ -#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated - futex REQUEUE op*/ - void linux_proc_init(struct thread *, struct thread *, int); void linux_proc_exit(void *, struct proc *); void linux_schedtail(struct thread *); @@ -61,4 +57,19 @@ void linux_thread_dtor(void *arg __unused, struct thread *); void linux_thread_detach(struct thread *); int linux_common_execve(struct thread *, struct image_args *); +/* process emuldata flags */ +#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated + futex REQUEUE op*/ +struct linux_pemuldata { + uint32_t flags; /* process emuldata flags */ + struct sx pem_sx; /* lock for this struct */ +}; + +#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx) +#define LINUX_PEM_XUNLOCK(p) sx_xunlock(&(p)->pem_sx) +#define LINUX_PEM_SLOCK(p) sx_slock(&(p)->pem_sx) +#define LINUX_PEM_SUNLOCK(p) sx_sunlock(&(p)->pem_sx) + +struct linux_pemuldata *pem_find(struct proc *); + #endif /* !_LINUX_EMUL_H_ */ diff --git a/sys/compat/linux/linux_fork.c b/sys/compat/linux/linux_fork.c index d83943180cbb..ce9744d6e513 100644 --- a/sys/compat/linux/linux_fork.c +++ b/sys/compat/linux/linux_fork.c @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #endif #include #include +#include #include #include @@ -404,3 +405,63 @@ linux_exit(struct thread *td, struct linux_exit_args *args) exit1(td, W_EXITCODE(args->rval, 0)); /* NOTREACHED */ } + +int +linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) +{ + struct linux_emuldata *em; + + em = em_find(td); + KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); + + em->child_clear_tid = args->tidptr; + + td->td_retval[0] = em->em_tid; + + LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", + em->em_tid, args->tidptr, td->td_retval[0]); + + return (0); +} + +void +linux_thread_detach(struct thread *td) +{ + struct linux_sys_futex_args cup; + struct linux_emuldata *em; + int *child_clear_tid; + int error; + + em = em_find(td); + KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); + + LINUX_CTR1(exit, "thread detach(%d)", em->em_tid); + + release_futexes(td, em); + + child_clear_tid = em->child_clear_tid; + + if (child_clear_tid != NULL) { + + LINUX_CTR2(exit, "thread detach(%d) %p", + em->em_tid, child_clear_tid); + + error = suword32(child_clear_tid, 0); + if (error != 0) + return; + + cup.uaddr = child_clear_tid; + cup.op = LINUX_FUTEX_WAKE; + cup.val = 1; /* wake one */ + cup.timeout = NULL; + cup.uaddr2 = NULL; + cup.val3 = 0; + error = linux_sys_futex(td, &cup); + /* + * this cannot happen at the moment and if this happens it + * probably means there is a user space bug + */ + if (error != 0) + linux_msg(td, "futex stuff in thread_detach failed."); + } +} diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 2c1187e6cee5..3338b46ae1e6 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -653,7 +653,7 @@ int linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) { int clockrt, nrwake, op_ret, ret; - struct linux_emuldata *em; + struct linux_pemuldata *pem; struct waiting_proc *wp; struct futex *f, *f2; struct l_timespec timeout; @@ -973,12 +973,12 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when * FUTEX_REQUEUE returned EINVAL. */ - em = em_find(td); - if ((em->flags & LINUX_XDEPR_REQUEUEOP) == 0) { + pem = pem_find(td->td_proc); + if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { linux_msg(td, "linux_sys_futex: " "unsupported futex_requeue op\n"); - em->flags |= LINUX_XDEPR_REQUEUEOP; + pem->flags |= LINUX_XDEPR_REQUEUEOP; LIN_SDT_PROBE0(futex, linux_sys_futex, deprecated_requeue); } diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 8c70d589af77..637ef8f5f196 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include #endif +#include #include #include #include @@ -91,6 +93,19 @@ __FBSDID("$FreeBSD$"); #include #include +/** + * Special DTrace provider for the linuxulator. + * + * In this file we define the provider for the entire linuxulator. All + * modules (= files of the linuxulator) use it. + * + * We define a different name depending on the emulated bitsize, see + * ../..//linux{,32}/linux.h, e.g.: + * native bitsize = linuxulator + * amd64, 32bit emulation = linuxulator32 + */ +LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); + int stclohz; /* Statistics clock frequency */ static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile index 27fc9b584b88..96fa94dc47b1 100644 --- a/sys/modules/linux/Makefile +++ b/sys/modules/linux/Makefile @@ -10,7 +10,7 @@ CFLAGS+=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32 VDSO= linux${SFX}_vdso KMOD= linux -SRCS= linux_fork.c linux${SFX}_dummy.c linux_emul.c linux_file.c \ +SRCS= linux_fork.c linux${SFX}_dummy.c linux_file.c \ linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \ linux${SFX}_machdep.c linux_misc.c linux_signal.c \ linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \ @@ -30,7 +30,8 @@ SRCS+= opt_apic.h OBJS= ${VDSO}.so .if ${MACHINE_CPUARCH} == "i386" -SRCS+= linux_ptrace.c imgact_linux.c linux_util.c linux_mib.c opt_cpu.h +SRCS+= linux_ptrace.c imgact_linux.c linux_util.c linux_mib.c \ + linux_emul.c opt_cpu.h .endif .if ${MACHINE_CPUARCH} == "i386" diff --git a/sys/modules/linux_common/Makefile b/sys/modules/linux_common/Makefile index 4384d0b6abdd..ebc475d63a82 100644 --- a/sys/modules/linux_common/Makefile +++ b/sys/modules/linux_common/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../compat/linux KMOD= linux_common -SRCS= linux_common.c linux_mib.c linux_util.c \ +SRCS= linux_common.c linux_mib.c linux_util.c linux_emul.c \ opt_compat.h device_if.h vnode_if.h bus_if.h EXPORT_SYMS=