From 939deb433656eadcd7e74873a32a38411367cdc8 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 14:08:10 +0000 Subject: To facillitate an upcoming Linuxulator merging partially MFC r275121 (by kib). Only merge the syntax changes from r275121, PROC_*LOCK() macros still lock the same proc spinlock. The process spin lock currently has the following distinct uses: - Threads lifetime cycle, in particular, counting of the threads in the process, and interlocking with process mutex and thread lock. The main reason of this is that turnstile locks are after thread locks, so you e.g. cannot unlock blockable mutex (think process mutex) while owning thread lock. - Virtual and profiling itimers, since the timers activation is done from the clock interrupt context. Replace the p_slock by p_itimmtx and PROC_ITIMLOCK(). - Profiling code (profil(2)), for similar reason. Replace the p_slock by p_profmtx and PROC_PROFLOCK(). - Resource usage accounting. Need for the spinlock there is subtle, my understanding is that spinlock blocks context switching for the current thread, which prevents td_runtime and similar fields from changing (updates are done at the mi_switch()). Replace the p_slock by p_statmtx and PROC_STATLOCK(). Discussed with: kib --- sys/compat/linux/linux_misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index ac2384c..2bc91be 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -691,9 +691,9 @@ linux_times(struct thread *td, struct linux_times_args *args) if (args->buf != NULL) { p = td->td_proc; PROC_LOCK(p); - PROC_SLOCK(p); + PROC_STATLOCK(p); calcru(p, &utime, &stime); - PROC_SUNLOCK(p); + PROC_STATUNLOCK(p); calccru(p, &cutime, &cstime); PROC_UNLOCK(p); -- cgit v1.1 From fd9d33be2a51f313e557a77d61add75b4a80bedc Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 14:40:38 +0000 Subject: MFC r283374: In preparation for switching linuxulator to the use the native 1:1 threads refactor kern_sched_rr_get_interval() and sys_sched_rr_get_interval(). Add a kern_sched_rr_get_interval() counterpart which takes a targettd parameter to allow specify target thread directly by callee (new Linuxulator). Linuxulator temporarily uses first thread in proc. Move linux_sched_rr_get_interval() to the MI part. --- sys/compat/linux/linux_misc.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 2bc91be..cb6c038 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1926,3 +1926,33 @@ linux_sched_setaffinity(struct thread *td, return (sys_cpuset_setaffinity(td, &csa)); } + +int +linux_sched_rr_get_interval(struct thread *td, + struct linux_sched_rr_get_interval_args *uap) +{ + struct timespec ts; + struct l_timespec lts; + struct thread *tdt; + struct proc *p; + int error; + + if (uap->pid == 0) { + tdt = td; + p = tdt->td_proc; + PROC_LOCK(p); + } else { + p = pfind(uap->pid); + if (p == NULL) + return (ESRCH); + tdt = FIRST_THREAD_IN_PROC(p); + } + + error = kern_sched_rr_get_interval_td(td, tdt, &ts); + PROC_UNLOCK(p); + if (error != 0) + return (error); + lts.tv_sec = ts.tv_sec; + lts.tv_nsec = ts.tv_nsec; + return (copyout(<s, uap->interval, sizeof(lts))); +} -- cgit v1.1 From 31e61f67492a11c512c20a8287816fab97f9e44b Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 14:47:08 +0000 Subject: MFC r283379: Implement a Linux version of sched_getparam() && sched_setparam(). Temporarily use the first thread in proc. --- sys/compat/linux/linux_misc.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index cb6c038..f6e6d96 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1871,6 +1871,78 @@ linux_prctl(struct thread *td, struct linux_prctl_args *args) return (error); } +int +linux_sched_setparam(struct thread *td, + struct linux_sched_setparam_args *uap) +{ + struct sched_param sched_param; + struct thread *tdt; + struct proc *p; + int error; + +#ifdef DEBUG + if (ldebug(sched_setparam)) + printf(ARGS(sched_setparam, "%d, *"), uap->pid); +#endif + + error = copyin(uap->param, &sched_param, sizeof(sched_param)); + if (error) + return (error); + + if (uap->pid == 0) { + tdt = td; + p = tdt->td_proc; + PROC_LOCK(p); + } else { + p = pfind(uap->pid); + if (p == NULL) + return (ESRCH); + /* + * XXX. Scheduling parameters are in fact per-thread + * attributes in Linux. Temporarily use the first + * thread in proc. The same for get_param(). + */ + tdt = FIRST_THREAD_IN_PROC(p); + } + + error = kern_sched_setparam(td, tdt, &sched_param); + PROC_UNLOCK(p); + return (error); +} + +int +linux_sched_getparam(struct thread *td, + struct linux_sched_getparam_args *uap) +{ + struct sched_param sched_param; + struct thread *tdt; + struct proc *p; + int error; + +#ifdef DEBUG + if (ldebug(sched_getparam)) + printf(ARGS(sched_getparam, "%d, *"), uap->pid); +#endif + + if (uap->pid == 0) { + tdt = td; + p = tdt->td_proc; + PROC_LOCK(p); + } else { + p = pfind(uap->pid); + if (p == NULL) + return (ESRCH); + tdt = FIRST_THREAD_IN_PROC(p); + } + + error = kern_sched_getparam(td, tdt, &sched_param); + PROC_UNLOCK(p); + if (error == 0) + error = copyout(&sched_param, uap->param, + sizeof(sched_param)); + return (error); +} + /* * Get affinity of a process. */ -- cgit v1.1 From cb3b38d1640b6a07cdc16de9cc37c2da8cfff4c1 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:16:13 +0000 Subject: MFC r283383: Switch linuxulator to use the native 1:1 threads. The reasons: 1. Get rid of the stubs/quirks with process dethreading, process reparent when the process group leader exits and close to this problems on wait(), waitpid(), etc. 2. Reuse our kernel code instead of writing excessive thread managment routines in Linuxulator. Implementation details: 1. The thread is created via kern_thr_new() in the clone() call with the CLONE_THREAD parameter. Thus, everything else is a process. 2. The test that the process has a threads is done via P_HADTHREADS bit p_flag of struct proc. 3. Per thread emulator state data structure is now located in the struct thread and freed in the thread_dtor() hook. Mandatory holdig of the p_mtx required when referencing emuldata from the other threads. 4. PID mangling has changed. Now Linux pid is the native tid and Linux tgid is the native pid, with the exception of the first thread in the process where tid and pid are one and the same. Ugliness: In case when the Linux thread is the initial thread in the thread group thread id is equal to the process id. Glibc depends on this magic (assert in pthread_getattr_np.c). So for system calls that take thread id as a parameter we should use the special method to reference struct thread. --- sys/compat/linux/linux_misc.c | 248 +++++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 135 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index f6e6d96..6293c40 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -85,7 +84,6 @@ __FBSDID("$FreeBSD$"); #include #endif -#include #include #include #include @@ -94,17 +92,6 @@ __FBSDID("$FreeBSD$"); #include #include -/* DTrace init */ -LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); - -/* Linuxulator-global DTrace probes */ -LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); -LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); -LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, locked); -LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, unlock); -LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, locked); -LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, unlock); - int stclohz; /* Statistics clock frequency */ static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { @@ -1295,7 +1282,9 @@ int linux_sched_setscheduler(struct thread *td, struct linux_sched_setscheduler_args *args) { - struct sched_setscheduler_args bsd; + struct sched_param sched_param; + struct thread *tdt; + int error, policy; #ifdef DEBUG if (ldebug(sched_setscheduler)) @@ -1305,39 +1294,51 @@ linux_sched_setscheduler(struct thread *td, switch (args->policy) { case LINUX_SCHED_OTHER: - bsd.policy = SCHED_OTHER; + policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: - bsd.policy = SCHED_FIFO; + policy = SCHED_FIFO; break; case LINUX_SCHED_RR: - bsd.policy = SCHED_RR; + policy = SCHED_RR; break; default: return (EINVAL); } - bsd.pid = args->pid; - bsd.param = (struct sched_param *)args->param; - return (sys_sched_setscheduler(td, &bsd)); + error = copyin(args->param, &sched_param, sizeof(sched_param)); + if (error) + return (error); + + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_setscheduler(td, tdt, policy, &sched_param); + PROC_UNLOCK(tdt->td_proc); + return (error); } int linux_sched_getscheduler(struct thread *td, struct linux_sched_getscheduler_args *args) { - struct sched_getscheduler_args bsd; - int error; + struct thread *tdt; + int error, policy; #ifdef DEBUG if (ldebug(sched_getscheduler)) printf(ARGS(sched_getscheduler, "%d"), args->pid); #endif - bsd.pid = args->pid; - error = sys_sched_getscheduler(td, &bsd); + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + error = kern_sched_getscheduler(td, tdt, &policy); + PROC_UNLOCK(tdt->td_proc); - switch (td->td_retval[0]) { + switch (policy) { case SCHED_OTHER: td->td_retval[0] = LINUX_SCHED_OTHER; break; @@ -1348,7 +1349,6 @@ linux_sched_getscheduler(struct thread *td, td->td_retval[0] = LINUX_SCHED_RR; break; } - return (error); } @@ -1474,20 +1474,12 @@ linux_reboot(struct thread *td, struct linux_reboot_args *args) int linux_getpid(struct thread *td, struct linux_getpid_args *args) { - struct linux_emuldata *em; #ifdef DEBUG if (ldebug(getpid)) printf(ARGS(getpid, "")); #endif - - if (linux_use26(td)) { - em = em_find(td->td_proc, EMUL_DONTLOCK); - KASSERT(em != NULL, ("getpid: emuldata not found.\n")); - td->td_retval[0] = em->shared->group_pid; - } else { - td->td_retval[0] = td->td_proc->p_pid; - } + td->td_retval[0] = td->td_proc->p_pid; return (0); } @@ -1495,13 +1487,18 @@ linux_getpid(struct thread *td, struct linux_getpid_args *args) int linux_gettid(struct thread *td, struct linux_gettid_args *args) { + struct linux_emuldata *em; #ifdef DEBUG if (ldebug(gettid)) printf(ARGS(gettid, "")); #endif - td->td_retval[0] = td->td_proc->p_pid; + em = em_find(td); + KASSERT(em != NULL, ("gettid: emuldata not found.\n")); + + td->td_retval[0] = em->em_tid; + return (0); } @@ -1509,50 +1506,15 @@ linux_gettid(struct thread *td, struct linux_gettid_args *args) int linux_getppid(struct thread *td, struct linux_getppid_args *args) { - struct linux_emuldata *em; - struct proc *p, *pp; #ifdef DEBUG if (ldebug(getppid)) printf(ARGS(getppid, "")); #endif - if (!linux_use26(td)) { - PROC_LOCK(td->td_proc); - td->td_retval[0] = td->td_proc->p_pptr->p_pid; - PROC_UNLOCK(td->td_proc); - return (0); - } - - em = em_find(td->td_proc, EMUL_DONTLOCK); - - KASSERT(em != NULL, ("getppid: process emuldata not found.\n")); - - /* find the group leader */ - p = pfind(em->shared->group_pid); - - if (p == NULL) { -#ifdef DEBUG - printf(LMSG("parent process not found.\n")); -#endif - return (0); - } - - pp = p->p_pptr; /* switch to parent */ - PROC_LOCK(pp); - PROC_UNLOCK(p); - - /* if its also linux process */ - if (pp->p_sysent == &elf_linux_sysvec) { - em = em_find(pp, EMUL_DONTLOCK); - KASSERT(em != NULL, ("getppid: parent emuldata not found.\n")); - - td->td_retval[0] = em->shared->group_pid; - } else - td->td_retval[0] = pp->p_pid; - - PROC_UNLOCK(pp); - + PROC_LOCK(td->td_proc); + td->td_retval[0] = td->td_proc->p_pptr->p_pid; + PROC_UNLOCK(td->td_proc); return (0); } @@ -1657,22 +1619,14 @@ linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) int linux_exit_group(struct thread *td, struct linux_exit_group_args *args) { - struct linux_emuldata *em; #ifdef DEBUG if (ldebug(exit_group)) printf(ARGS(exit_group, "%i"), args->error_code); #endif - em = em_find(td->td_proc, EMUL_DONTLOCK); - if (em->shared->refs > 1) { - EMUL_SHARED_WLOCK(&emul_shared_lock); - em->shared->flags |= EMUL_SHARED_HASXSTAT; - em->shared->xstat = W_EXITCODE(args->error_code, 0); - EMUL_SHARED_WUNLOCK(&emul_shared_lock); - if (linux_use26(td)) - linux_kill_threads(td, SIGKILL); - } + LINUX_CTR2(exit_group, "thread(%d) (%d)", td->td_tid, + args->error_code); /* * XXX: we should send a signal to the parent if @@ -1680,8 +1634,7 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args) * as it doesnt occur often. */ exit1(td, W_EXITCODE(args->error_code, 0)); - - return (0); + /* NOTREACHED */ } #define _LINUX_CAPABILITY_VERSION 0x19980330 @@ -1797,16 +1750,14 @@ linux_prctl(struct thread *td, struct linux_prctl_args *args) case LINUX_PR_SET_PDEATHSIG: if (!LINUX_SIG_VALID(args->arg2)) return (EINVAL); - em = em_find(p, EMUL_DOLOCK); + em = em_find(td); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); em->pdeath_signal = args->arg2; - EMUL_UNLOCK(&emul_lock); break; case LINUX_PR_GET_PDEATHSIG: - em = em_find(p, EMUL_DOLOCK); + em = em_find(td); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); pdeath_signal = em->pdeath_signal; - EMUL_UNLOCK(&emul_lock); error = copyout(&pdeath_signal, (void *)(register_t)args->arg2, sizeof(pdeath_signal)); @@ -1877,7 +1828,6 @@ linux_sched_setparam(struct thread *td, { struct sched_param sched_param; struct thread *tdt; - struct proc *p; int error; #ifdef DEBUG @@ -1889,24 +1839,12 @@ linux_sched_setparam(struct thread *td, if (error) return (error); - if (uap->pid == 0) { - tdt = td; - p = tdt->td_proc; - PROC_LOCK(p); - } else { - p = pfind(uap->pid); - if (p == NULL) - return (ESRCH); - /* - * XXX. Scheduling parameters are in fact per-thread - * attributes in Linux. Temporarily use the first - * thread in proc. The same for get_param(). - */ - tdt = FIRST_THREAD_IN_PROC(p); - } + tdt = linux_tdfind(td, uap->pid, -1); + if (tdt == NULL) + return (ESRCH); error = kern_sched_setparam(td, tdt, &sched_param); - PROC_UNLOCK(p); + PROC_UNLOCK(tdt->td_proc); return (error); } @@ -1916,7 +1854,6 @@ linux_sched_getparam(struct thread *td, { struct sched_param sched_param; struct thread *tdt; - struct proc *p; int error; #ifdef DEBUG @@ -1924,19 +1861,12 @@ linux_sched_getparam(struct thread *td, printf(ARGS(sched_getparam, "%d, *"), uap->pid); #endif - if (uap->pid == 0) { - tdt = td; - p = tdt->td_proc; - PROC_LOCK(p); - } else { - p = pfind(uap->pid); - if (p == NULL) - return (ESRCH); - tdt = FIRST_THREAD_IN_PROC(p); - } + tdt = linux_tdfind(td, uap->pid, -1); + if (tdt == NULL) + return (ESRCH); error = kern_sched_getparam(td, tdt, &sched_param); - PROC_UNLOCK(p); + PROC_UNLOCK(tdt->td_proc); if (error == 0) error = copyout(&sched_param, uap->param, sizeof(sched_param)); @@ -1951,6 +1881,7 @@ linux_sched_getaffinity(struct thread *td, struct linux_sched_getaffinity_args *args) { int error; + struct thread *tdt; struct cpuset_getaffinity_args cga; #ifdef DEBUG @@ -1961,9 +1892,14 @@ linux_sched_getaffinity(struct thread *td, if (args->len < sizeof(cpuset_t)) return (EINVAL); + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + PROC_UNLOCK(tdt->td_proc); cga.level = CPU_LEVEL_WHICH; - cga.which = CPU_WHICH_PID; - cga.id = args->pid; + cga.which = CPU_WHICH_TID; + cga.id = tdt->td_tid; cga.cpusetsize = sizeof(cpuset_t); cga.mask = (cpuset_t *) args->user_mask_ptr; @@ -1981,6 +1917,7 @@ linux_sched_setaffinity(struct thread *td, struct linux_sched_setaffinity_args *args) { struct cpuset_setaffinity_args csa; + struct thread *tdt; #ifdef DEBUG if (ldebug(sched_setaffinity)) @@ -1990,9 +1927,14 @@ linux_sched_setaffinity(struct thread *td, if (args->len < sizeof(cpuset_t)) return (EINVAL); + tdt = linux_tdfind(td, args->pid, -1); + if (tdt == NULL) + return (ESRCH); + + PROC_UNLOCK(tdt->td_proc); csa.level = CPU_LEVEL_WHICH; - csa.which = CPU_WHICH_PID; - csa.id = args->pid; + csa.which = CPU_WHICH_TID; + csa.id = tdt->td_tid; csa.cpusetsize = sizeof(cpuset_t); csa.mask = (cpuset_t *) args->user_mask_ptr; @@ -2006,25 +1948,61 @@ linux_sched_rr_get_interval(struct thread *td, struct timespec ts; struct l_timespec lts; struct thread *tdt; - struct proc *p; int error; - if (uap->pid == 0) { - tdt = td; - p = tdt->td_proc; - PROC_LOCK(p); - } else { - p = pfind(uap->pid); - if (p == NULL) - return (ESRCH); - tdt = FIRST_THREAD_IN_PROC(p); - } + tdt = linux_tdfind(td, uap->pid, -1); + if (tdt == NULL) + return (ESRCH); error = kern_sched_rr_get_interval_td(td, tdt, &ts); - PROC_UNLOCK(p); + PROC_UNLOCK(tdt->td_proc); if (error != 0) return (error); lts.tv_sec = ts.tv_sec; lts.tv_nsec = ts.tv_nsec; return (copyout(<s, uap->interval, sizeof(lts))); } + +/* + * In case when the Linux thread is the initial thread in + * the thread group thread id is equal to the process id. + * Glibc depends on this magic (assert in pthread_getattr_np.c). + */ +struct thread * +linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid) +{ + struct linux_emuldata *em; + struct thread *tdt; + struct proc *p; + + tdt = NULL; + if (tid == 0 || tid == td->td_tid) { + tdt = td; + PROC_LOCK(tdt->td_proc); + } else if (tid > PID_MAX) + tdt = tdfind(tid, pid); + else { + /* + * Initial thread where the tid equal to the pid. + */ + p = pfind(tid); + if (p != NULL) { + if (SV_PROC_ABI(p) != SV_ABI_LINUX) { + /* + * p is not a Linuxulator process. + */ + PROC_UNLOCK(p); + return (NULL); + } + FOREACH_THREAD_IN_PROC(p, tdt) { + em = em_find(tdt); + if (tid == em->em_tid) + return (tdt); + } + PROC_UNLOCK(p); + } + return (NULL); + } + + return (tdt); +} -- cgit v1.1 From 778af4f786b2616dc167e39728e9ccd274f98fa1 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:22:50 +0000 Subject: MFC r283390: Add a function for converting wait options. --- sys/compat/linux/linux_misc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 6293c40..345dd22 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2006,3 +2006,22 @@ linux_tdfind(struct thread *td, lwpid_t tid, pid_t pid) return (tdt); } + +void +linux_to_bsd_waitopts(int options, int *bsdopts) +{ + + if (options & LINUX_WNOHANG) + *bsdopts |= WNOHANG; + if (options & LINUX_WUNTRACED) + *bsdopts |= WUNTRACED; + if (options & LINUX_WEXITED) + *bsdopts |= WEXITED; + if (options & LINUX_WCONTINUED) + *bsdopts |= WCONTINUED; + if (options & LINUX_WNOWAIT) + *bsdopts |= WNOWAIT; + + if (options & __WCLONE) + *bsdopts |= WLINUXCLONE; +} -- cgit v1.1 From a14064e328e84be7d749f513956026f7f22e60b2 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:23:54 +0000 Subject: MFC r283391: To reduce code duplication introduce linux_copyout_rusage() method. Use it in linux_wait4() system call and move linux_wait4() to the MI path. While here add a prototype for the static bsd_to_linux_rusage(). --- sys/compat/linux/linux_misc.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 345dd22..d9e1834 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -885,6 +885,35 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args) return (linux_common_wait(td, args->pid, args->status, options, NULL)); } +int +linux_wait4(struct thread *td, struct linux_wait4_args *args) +{ + int error, options; + struct rusage ru, *rup; + +#ifdef DEBUG + if (ldebug(wait4)) + printf(ARGS(wait4, "%d, %p, %d, %p"), + args->pid, (void *)args->status, args->options, + (void *)args->rusage); +#endif + + options = (args->options & (WNOHANG | WUNTRACED)); + /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ + if (args->options & __WCLONE) + options |= WLINUXCLONE; + + if (args->rusage != NULL) + rup = &ru; + else + rup = NULL; + error = linux_common_wait(td, args->pid, args->status, options, rup); + if (error != 0) + return (error); + if (args->rusage != NULL) + error = linux_copyout_rusage(&ru, args->rusage); + return (error); +} int linux_mknod(struct thread *td, struct linux_mknod_args *args) -- cgit v1.1 From 3c97a0093809814b043c4b6e6f23a66a38d564d3 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:28:05 +0000 Subject: MFC r283394: Implement waitid() system call. --- sys/compat/linux/linux_misc.c | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index d9e1834..f54018d 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -916,6 +916,68 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args) } int +linux_waitid(struct thread *td, struct linux_waitid_args *args) +{ + int status, options, sig; + struct __wrusage wru; + siginfo_t siginfo; + l_siginfo_t lsi; + idtype_t idtype; + struct proc *p; + int error; + + options = 0; + linux_to_bsd_waitopts(args->options, &options); + + if (options & ~(WNOHANG | WNOWAIT | WEXITED | WUNTRACED | WCONTINUED)) + return (EINVAL); + if (!(options & (WEXITED | WUNTRACED | WCONTINUED))) + return (EINVAL); + + switch (args->idtype) { + case LINUX_P_ALL: + idtype = P_ALL; + break; + case LINUX_P_PID: + if (args->id <= 0) + return (EINVAL); + idtype = P_PID; + break; + case LINUX_P_PGID: + if (args->id <= 0) + return (EINVAL); + idtype = P_PGID; + break; + default: + return (EINVAL); + } + + error = kern_wait6(td, idtype, args->id, &status, options, + &wru, &siginfo); + if (error != 0) + return (error); + if (args->rusage != NULL) { + error = linux_copyout_rusage(&wru.wru_children, + args->rusage); + if (error != 0) + return (error); + } + if (args->info != NULL) { + p = td->td_proc; + if (td->td_retval[0] == 0) + bzero(&lsi, sizeof(lsi)); + else { + sig = BSD_TO_LINUX_SIGNAL(siginfo.si_signo); + siginfo_to_lsiginfo(&siginfo, &lsi, sig); + } + error = copyout(&lsi, args->info, sizeof(lsi)); + } + td->td_retval[0] = 0; + + return (error); +} + +int linux_mknod(struct thread *td, struct linux_mknod_args *args) { char *path; -- cgit v1.1 From 9ef9a018392248ab5f911960b69a3af51ad14c4a Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:33:48 +0000 Subject: MFC r283398: Sched_rr_get_interval returns EINVAL in case when the invalid pid specified. This silence the ltp tests. --- sys/compat/linux/linux_misc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index f54018d..17a153b 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2041,6 +2041,13 @@ linux_sched_rr_get_interval(struct thread *td, struct thread *tdt; int error; + /* + * According to man in case the invalid pid specified + * EINVAL should be returned. + */ + if (uap->pid < 0) + return (EINVAL); + tdt = linux_tdfind(td, uap->pid, -1); if (tdt == NULL) return (ESRCH); -- cgit v1.1 From 027f6631c01acb6b110e8175335f323e7f8567fb Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:37:10 +0000 Subject: MFC r283401: Implement prlimit64() system call. --- sys/compat/linux/linux_misc.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 17a153b..e128bb4 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2032,6 +2032,79 @@ linux_sched_setaffinity(struct thread *td, return (sys_cpuset_setaffinity(td, &csa)); } +struct linux_rlimit64 { + uint64_t rlim_cur; + uint64_t rlim_max; +}; + +int +linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) +{ + struct rlimit rlim, nrlim; + struct linux_rlimit64 lrlim; + struct proc *p; + u_int which; + int flags; + int error; + +#ifdef DEBUG + if (ldebug(prlimit64)) + printf(ARGS(prlimit64, "%d, %d, %p, %p"), args->pid, + args->resource, (void *)args->new, (void *)args->old); +#endif + + if (args->resource >= LINUX_RLIM_NLIMITS) + return (EINVAL); + + which = linux_to_bsd_resource[args->resource]; + if (which == -1) + return (EINVAL); + + if (args->new != NULL) { + /* + * Note. Unlike FreeBSD where rlim is signed 64-bit Linux + * rlim is unsigned 64-bit. FreeBSD treats negative limits + * as INFINITY so we do not need a conversion even. + */ + error = copyin(args->new, &nrlim, sizeof(nrlim)); + if (error != 0) + return (error); + } + + flags = PGET_HOLD | PGET_NOTWEXIT; + if (args->new != NULL) + flags |= PGET_CANDEBUG; + else + flags |= PGET_CANSEE; + error = pget(args->pid, flags, &p); + if (error != 0) + return (error); + + if (args->old != NULL) { + PROC_LOCK(p); + lim_rlimit(p, which, &rlim); + PROC_UNLOCK(p); + if (rlim.rlim_cur == RLIM_INFINITY) + lrlim.rlim_cur = LINUX_RLIM_INFINITY; + else + lrlim.rlim_cur = rlim.rlim_cur; + if (rlim.rlim_max == RLIM_INFINITY) + lrlim.rlim_max = LINUX_RLIM_INFINITY; + else + lrlim.rlim_max = rlim.rlim_max; + error = copyout(&lrlim, args->old, sizeof(lrlim)); + if (error != 0) + goto out; + } + + if (args->new != NULL) + error = kern_proc_setrlimit(td, p, which, &nrlim); + + out: + PRELE(p); + return (error); +} + int linux_sched_rr_get_interval(struct thread *td, struct linux_sched_rr_get_interval_args *uap) -- cgit v1.1 From 4ed27590e5c71931347430107294760f55c94b9e Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:39:41 +0000 Subject: MFC r283403: Implement pselect6() system call. --- sys/compat/linux/linux_misc.c | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index e128bb4..21e5bfc 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -117,6 +117,12 @@ struct l_sysinfo { l_uint mem_unit; char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ }; + +struct l_pselect6arg { + l_uintptr_t ss; + l_size_t ss_len; +}; + int linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) { @@ -2106,6 +2112,84 @@ linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args) } int +linux_pselect6(struct thread *td, struct linux_pselect6_args *args) +{ + struct timeval utv, tv0, tv1, *tvp; + struct l_pselect6arg lpse6; + struct l_timespec lts; + struct timespec uts; + l_sigset_t l_ss; + sigset_t *ssp; + sigset_t ss; + int error; + + ssp = NULL; + if (args->sig != NULL) { + error = copyin(args->sig, &lpse6, sizeof(lpse6)); + if (error != 0) + return (error); + if (lpse6.ss_len != sizeof(l_ss)) + return (EINVAL); + if (lpse6.ss != 0) { + error = copyin(PTRIN(lpse6.ss), &l_ss, + sizeof(l_ss)); + if (error != 0) + return (error); + linux_to_bsd_sigset(&l_ss, &ss); + ssp = &ss; + } + } + + /* + * Currently glibc changes nanosecond number to microsecond. + * This mean losing precision but for now it is hardly seen. + */ + if (args->tsp != NULL) { + error = copyin(args->tsp, <s, sizeof(lts)); + if (error != 0) + return (error); + uts.tv_sec = lts.tv_sec; + uts.tv_nsec = lts.tv_nsec; + + TIMESPEC_TO_TIMEVAL(&utv, &uts); + if (itimerfix(&utv)) + return (EINVAL); + + microtime(&tv0); + tvp = &utv; + } else + tvp = NULL; + + error = kern_pselect(td, args->nfds, args->readfds, args->writefds, + args->exceptfds, tvp, ssp, sizeof(l_int) * 8); + + if (error == 0 && args->tsp != NULL) { + if (td->td_retval[0] != 0) { + /* + * Compute how much time was left of the timeout, + * by subtracting the current time and the time + * before we started the call, and subtracting + * that result from the user-supplied value. + */ + + microtime(&tv1); + timevalsub(&tv1, &tv0); + timevalsub(&utv, &tv1); + if (utv.tv_sec < 0) + timevalclear(&utv); + } else + timevalclear(&utv); + + TIMEVAL_TO_TIMESPEC(&utv, &uts); + lts.tv_sec = uts.tv_sec; + lts.tv_nsec = uts.tv_nsec; + error = copyout(<s, args->tsp, sizeof(lts)); + } + + return (error); +} + +int linux_sched_rr_get_interval(struct thread *td, struct linux_sched_rr_get_interval_args *uap) { -- cgit v1.1 From a034df74fdb12c279d0096abb6d6f7b2b2fec24b Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:48:11 +0000 Subject: MFC r283410: Put linux_platform into the vdso to avoid copying it onto the stack at every exec. --- sys/compat/linux/linux_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 21e5bfc..b1a583d 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -732,7 +732,7 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args) *p = '\0'; break; } - strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME); + strlcpy(utsname.machine, linux_kplatform, LINUX_MAX_UTSNAME); return (copyout(&utsname, args->buf, sizeof(utsname))); } -- cgit v1.1 From 0a1120ef093d9730dc72cdda6f4ff89d8c577d0f Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:54:55 +0000 Subject: MFC r283415: Disable i386 call for x86-64 Linux. --- sys/compat/linux/linux_misc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index b1a583d..22b934a 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -737,7 +737,6 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args) return (copyout(&utsname, args->buf, sizeof(utsname))); } -#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) struct l_utimbuf { l_time_t l_actime; l_time_t l_modtime; @@ -840,7 +839,6 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args) LFREEPATH(fname); return (error); } -#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_common_wait(struct thread *td, int pid, int *status, @@ -866,6 +864,7 @@ linux_common_wait(struct thread *td, int pid, int *status, return (error); } +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_waitpid(struct thread *td, struct linux_waitpid_args *args) { @@ -890,6 +889,7 @@ linux_waitpid(struct thread *td, struct linux_waitpid_args *args) return (linux_common_wait(td, args->pid, args->status, options, NULL)); } +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_wait4(struct thread *td, struct linux_wait4_args *args) @@ -1163,6 +1163,7 @@ linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) return (copyout(&ls, uap->itv, sizeof(ls))); } +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_nice(struct thread *td, struct linux_nice_args *args) { @@ -1173,6 +1174,7 @@ linux_nice(struct thread *td, struct linux_nice_args *args) bsd_args.prio = args->inc; return (sys_setpriority(td, &bsd_args)); } +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) @@ -1302,6 +1304,7 @@ linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) return (kern_setrlimit(td, which, &bsd_rlim)); } +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) int linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) { @@ -1344,6 +1347,7 @@ linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) #endif return (copyout(&rlim, args->rlim, sizeof(rlim))); } +#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) -- cgit v1.1 From de7c911268b73d6b9e6b3583c413db9759b8320c Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 15:58:42 +0000 Subject: MFC r283419: Fix compilation with -DDEBUG option. --- sys/compat/linux/linux_misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 22b934a..a9d5580 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -993,7 +993,8 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args) #ifdef DEBUG if (ldebug(mknod)) - printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); + printf(ARGS(mknod, "%s, %d, %ju"), path, args->mode, + (uintmax_t)args->dev); #endif switch (args->mode & S_IFMT) { @@ -1843,8 +1844,9 @@ linux_prctl(struct thread *td, struct linux_prctl_args *args) #ifdef DEBUG if (ldebug(prctl)) - printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, - args->arg2, args->arg3, args->arg4, args->arg5); + printf(ARGS(prctl, "%d, %ju, %ju, %ju, %ju"), args->option, + (uintmax_t)args->arg2, (uintmax_t)args->arg3, + (uintmax_t)args->arg4, (uintmax_t)args->arg5); #endif switch (args->option) { -- cgit v1.1 From d30e84112a87337209ea45237f3d9b12e29abaa9 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:08:22 +0000 Subject: MFC r283421: Introduce a new module linux_common.ko which is intended for the following primary purposes: 1. Remove the dependency of linsysfs and linprocfs modules from linux.ko, which will be architecture specific on amd64. 2. Incorporate into linux_common.ko general code for platforms on which we'll support two Linuxulator modules (for both instruction set - 32 & 64 bit). 3. Move malloc(9) declaration to linux_common.ko, to enable getting memory usage statistics properly. Currently linux_common.ko incorporates a code from linux_mib.c and linux_util.c and linprocfs, linsysfs and linux kernel modules depend on linux_common.ko. Temporarily remove dtrace garbage from linux_mib.c and linux_util.c --- sys/compat/linux/linux_misc.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index a9d5580..550e36d 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2195,6 +2195,63 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args) return (error); } +#if defined(DEBUG) || defined(KTR) +/* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ + +u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; + +static int +linux_debug(int syscall, int toggle, int global) +{ + + if (global) { + char c = toggle ? 0 : 0xff; + + memset(linux_debug_map, c, sizeof(linux_debug_map)); + return (0); + } + if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) + return (EINVAL); + if (toggle) + clrbit(linux_debug_map, syscall); + else + setbit(linux_debug_map, syscall); + return (0); +} + +/* + * Usage: sysctl linux.debug=.<0/1> + * + * E.g.: sysctl linux.debug=21.0 + * + * As a special case, syscall "all" will apply to all syscalls globally. + */ +#define LINUX_MAX_DEBUGSTR 16 +int +linux_sysctl_debug(SYSCTL_HANDLER_ARGS) +{ + char value[LINUX_MAX_DEBUGSTR], *p; + int error, sysc, toggle; + int global = 0; + + value[0] = '\0'; + error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); + if (error || req->newptr == NULL) + return (error); + for (p = value; *p != '\0' && *p != '.'; p++); + if (*p == '\0') + return (EINVAL); + *p++ = '\0'; + sysc = strtol(value, NULL, 0); + toggle = strtol(p, NULL, 0); + if (strcmp(value, "all") == 0) + global = 1; + error = linux_debug(sysc, toggle, global); + return (error); +} + +#endif /* DEBUG || KTR */ + int linux_sched_rr_get_interval(struct thread *td, struct linux_sched_rr_get_interval_args *uap) -- cgit v1.1 From 6c12e20ac1e5ea5573246049365409feabb20095 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:11:09 +0000 Subject: MFC r283422: 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. --- sys/compat/linux/linux_misc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 550e36d..2106dcd 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -84,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include #endif +#include #include #include #include @@ -92,6 +94,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] = { -- cgit v1.1 From 9bb36bc01cd74565fb879d43a4431edff14a2741 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:20:29 +0000 Subject: MFC r283427: Where possible we will use M_LINUX malloc(9) type. Move M_FUTEX defines to the linux_common.ko. --- sys/compat/linux/linux_misc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 2106dcd..e1db59e 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1204,7 +1204,7 @@ linux_setgroups(struct thread *td, struct linux_setgroups_args *args) ngrp = args->gidsetsize; if (ngrp < 0 || ngrp >= ngroups_max + 1) return (EINVAL); - linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); if (error) goto out; @@ -1243,7 +1243,7 @@ linux_setgroups(struct thread *td, struct linux_setgroups_args *args) crfree(oldcred); error = 0; out: - free(linux_gidset, M_TEMP); + free(linux_gidset, M_LINUX); return (error); } @@ -1275,14 +1275,14 @@ linux_getgroups(struct thread *td, struct linux_getgroups_args *args) ngrp = 0; linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), - M_TEMP, M_WAITOK); + M_LINUX, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); - free(linux_gidset, M_TEMP); + free(linux_gidset, M_LINUX); if (error) return (error); -- cgit v1.1 From 711049c77b1b3ac708f86965e53280f134689263 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:27:33 +0000 Subject: MFC r283434: Set WIFCONTINUED to the wait status if needed. --- sys/compat/linux/linux_misc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index e1db59e..b9218d8 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -873,6 +873,8 @@ linux_common_wait(struct thread *td, int pid, int *status, else if (WIFSTOPPED(tmpstat)) tmpstat = (tmpstat & 0xffff00ff) | (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); + else if (WIFCONTINUED(tmpstat)) + tmpstat = 0xffff; error = copyout(&tmpstat, status, sizeof(int)); } -- cgit v1.1 From cda33c12b343f1c255629b1f7611655e3b29e3ac Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:28:40 +0000 Subject: MFC r283435: Convert Linux wait options to the FreeBSD. Check wait options as a Linux do. Linux always set WEXITED option not a WUNTRACED|WNOHANG which is a strange bug. --- sys/compat/linux/linux_misc.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index b9218d8..bf8c462 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -885,26 +885,20 @@ linux_common_wait(struct thread *td, int pid, int *status, int linux_waitpid(struct thread *td, struct linux_waitpid_args *args) { - int options; - + struct linux_wait4_args wait4_args; + #ifdef DEBUG if (ldebug(waitpid)) printf(ARGS(waitpid, "%d, %p, %d"), args->pid, (void *)args->status, args->options); #endif - /* - * this is necessary because the test in kern_wait doesn't work - * because we mess with the options here - */ - if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE)) - return (EINVAL); - - options = (args->options & (WNOHANG | WUNTRACED)); - /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ - if (args->options & __WCLONE) - options |= WLINUXCLONE; - return (linux_common_wait(td, args->pid, args->status, options, NULL)); + wait4_args.pid = args->pid; + wait4_args.status = args->status; + wait4_args.options = args->options; + wait4_args.rusage = NULL; + + return (linux_wait4(td, &wait4_args)); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ @@ -920,11 +914,12 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args) args->pid, (void *)args->status, args->options, (void *)args->rusage); #endif + if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG | + LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL)) + return (EINVAL); - options = (args->options & (WNOHANG | WUNTRACED)); - /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ - if (args->options & __WCLONE) - options |= WLINUXCLONE; + options = WEXITED; + linux_to_bsd_waitopts(args->options, &options); if (args->rusage != NULL) rup = &ru; -- cgit v1.1 From 623ca9818819fc3b87701ba39c1fcc6bd40ca9e5 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:47:36 +0000 Subject: MFC r283443: Put the correct value for the abi_nfdbits parameter of kern_select() for all supported Linuxulators. --- sys/compat/linux/linux_misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index bf8c462..abf59c7 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -532,7 +532,7 @@ linux_select(struct thread *td, struct linux_select_args *args) tvp = NULL; error = kern_select(td, args->nfds, args->readfds, args->writefds, - args->exceptfds, tvp, sizeof(l_int) * 8); + args->exceptfds, tvp, LINUX_NFDBITS); #ifdef DEBUG if (ldebug(select)) @@ -2179,7 +2179,7 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args) tvp = NULL; error = kern_pselect(td, args->nfds, args->readfds, args->writefds, - args->exceptfds, tvp, ssp, sizeof(l_int) * 8); + args->exceptfds, tvp, ssp, LINUX_NFDBITS); if (error == 0 && args->tsp != NULL) { if (td->td_retval[0] != 0) { -- cgit v1.1 From 682bdd605d1e6239366f2c09a908ff48b95fad0c Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 16:58:57 +0000 Subject: MFC r283451: Implement ppoll() system call. --- sys/compat/linux/linux_misc.c | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index abf59c7..45d6bb2 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -2207,6 +2207,59 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args) return (error); } +int +linux_ppoll(struct thread *td, struct linux_ppoll_args *args) +{ + struct timespec ts0, ts1; + struct l_timespec lts; + struct timespec uts, *tsp; + l_sigset_t l_ss; + sigset_t *ssp; + sigset_t ss; + int error; + + if (args->sset != NULL) { + if (args->ssize != sizeof(l_ss)) + return (EINVAL); + error = copyin(args->sset, &l_ss, sizeof(l_ss)); + if (error) + return (error); + linux_to_bsd_sigset(&l_ss, &ss); + ssp = &ss; + } else + ssp = NULL; + if (args->tsp != NULL) { + error = copyin(args->tsp, <s, sizeof(lts)); + if (error) + return (error); + uts.tv_sec = lts.tv_sec; + uts.tv_nsec = lts.tv_nsec; + + nanotime(&ts0); + tsp = &uts; + } else + tsp = NULL; + + error = kern_poll(td, args->fds, args->nfds, tsp, ssp); + + if (error == 0 && args->tsp != NULL) { + if (td->td_retval[0]) { + nanotime(&ts1); + timespecsub(&ts1, &ts0); + timespecsub(&uts, &ts1); + if (uts.tv_sec < 0) + timespecclear(&uts); + } else + timespecclear(&uts); + + lts.tv_sec = uts.tv_sec; + lts.tv_nsec = uts.tv_nsec; + error = copyout(<s, args->tsp, sizeof(lts)); + } + + return (error); +} + #if defined(DEBUG) || defined(KTR) /* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ -- cgit v1.1 From 0e75fd64e782579dbb101bf9698adbedec1c2806 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 17:11:25 +0000 Subject: MFC r283463: Do not use struct l_timespec without conversion. While here move args->timeout handling before acquiring the futex key at FUTEX_WAIT path. --- sys/compat/linux/linux_misc.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 45d6bb2..9806e03 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -2166,8 +2167,9 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args) error = copyin(args->tsp, <s, sizeof(lts)); if (error != 0) return (error); - uts.tv_sec = lts.tv_sec; - uts.tv_nsec = lts.tv_nsec; + error = linux_to_native_timespec(&uts, <s); + if (error != 0) + return (error); TIMESPEC_TO_TIMEVAL(&utv, &uts); if (itimerfix(&utv)) @@ -2199,8 +2201,8 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args) timevalclear(&utv); TIMEVAL_TO_TIMESPEC(&utv, &uts); - lts.tv_sec = uts.tv_sec; - lts.tv_nsec = uts.tv_nsec; + + native_to_linux_timespec(<s, &uts); error = copyout(<s, args->tsp, sizeof(lts)); } @@ -2232,8 +2234,9 @@ linux_ppoll(struct thread *td, struct linux_ppoll_args *args) error = copyin(args->tsp, <s, sizeof(lts)); if (error) return (error); - uts.tv_sec = lts.tv_sec; - uts.tv_nsec = lts.tv_nsec; + error = linux_to_native_timespec(&uts, <s); + if (error != 0) + return (error); nanotime(&ts0); tsp = &uts; @@ -2252,8 +2255,7 @@ linux_ppoll(struct thread *td, struct linux_ppoll_args *args) } else timespecclear(&uts); - lts.tv_sec = uts.tv_sec; - lts.tv_nsec = uts.tv_nsec; + native_to_linux_timespec(<s, &uts); error = copyout(<s, args->tsp, sizeof(lts)); } @@ -2341,8 +2343,7 @@ linux_sched_rr_get_interval(struct thread *td, PROC_UNLOCK(tdt->td_proc); if (error != 0) return (error); - lts.tv_sec = ts.tv_sec; - lts.tv_nsec = ts.tv_nsec; + native_to_linux_timespec(<s, &ts); return (copyout(<s, uap->interval, sizeof(lts))); } -- cgit v1.1 From 05243c722867c54470c4a8757c8c05652a7ad919 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 17:29:08 +0000 Subject: MFC r283474: Rework signal code to allow using it by other modules, like linprocfs: 1. Linux sigset always 64 bit on all platforms. In order to move Linux sigset code to the linux_common module define it as 64 bit int. Move Linux sigset manipulation routines to the MI path. 2. Move Linux signal number definitions to the MI path. In general, they are the same on all platforms except for a few signals. 3. Map Linux RT signals to the FreeBSD RT signals and hide signal conversion tables to avoid conversion errors. 4. Emulate Linux SIGPWR signal via FreeBSD SIGRTMIN signal which is outside of allowed on Linux signal numbers. PR: 197216 --- sys/compat/linux/linux_misc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 9806e03..b377f7f 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -870,10 +870,10 @@ linux_common_wait(struct thread *td, int pid, int *status, tmpstat &= 0xffff; if (WIFSIGNALED(tmpstat)) tmpstat = (tmpstat & 0xffffff80) | - BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); + bsd_to_linux_signal(WTERMSIG(tmpstat)); else if (WIFSTOPPED(tmpstat)) tmpstat = (tmpstat & 0xffff00ff) | - (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); + (bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8); else if (WIFCONTINUED(tmpstat)) tmpstat = 0xffff; error = copyout(&tmpstat, status, sizeof(int)); @@ -986,7 +986,7 @@ linux_waitid(struct thread *td, struct linux_waitid_args *args) if (td->td_retval[0] == 0) bzero(&lsi, sizeof(lsi)); else { - sig = BSD_TO_LINUX_SIGNAL(siginfo.si_signo); + sig = bsd_to_linux_signal(siginfo.si_signo); siginfo_to_lsiginfo(&siginfo, &lsi, sig); } error = copyout(&lsi, args->info, sizeof(lsi)); -- cgit v1.1 From 1e80f16f0f3065e31e936081a69ab880a5266732 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 17:41:00 +0000 Subject: MFC r283480: Add utimensat() system call. --- sys/compat/linux/linux_misc.c | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index b377f7f..1c626ad 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -823,6 +823,87 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args) return (error); } +int +linux_utimensat(struct thread *td, struct linux_utimensat_args *args) +{ + struct l_timespec l_times[2]; + struct timespec times[2], *timesp = NULL; + char *path = NULL; + int error, dfd, flags = 0; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + +#ifdef DEBUG + if (ldebug(utimensat)) + printf(ARGS(utimensat, "%d, *"), dfd); +#endif + + if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW) + return (EINVAL); + + if (args->times != NULL) { + error = copyin(args->times, l_times, sizeof(l_times)); + if (error != 0) + return (error); + + if (l_times[0].tv_nsec > 999999999 || + l_times[1].tv_nsec > 999999999) + return (EINVAL); + + times[0].tv_sec = l_times[0].tv_sec; + switch (l_times[0].tv_nsec) + { + case LINUX_UTIME_OMIT: + times[0].tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times[0].tv_nsec = UTIME_NOW; + break; + default: + times[0].tv_nsec = l_times[0].tv_nsec; + } + + times[1].tv_sec = l_times[1].tv_sec; + switch (l_times[1].tv_nsec) + { + case LINUX_UTIME_OMIT: + times[1].tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times[1].tv_nsec = UTIME_NOW; + break; + default: + times[1].tv_nsec = l_times[1].tv_nsec; + break; + } + timesp = times; + } + + if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) + /* This breaks POSIX, but is what the Linux kernel does + * _on purpose_ (documented in the man page for utimensat(2)), + * so we must follow that behaviour. */ + return (0); + + if (args->pathname != NULL) + LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); + else if (args->flags != 0) + return (EINVAL); + + if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) + flags |= AT_SYMLINK_NOFOLLOW; + + if (path == NULL) + error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE); + else { + error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp, + UIO_SYSSPACE, flags); + LFREEPATH(path); + } + + return (error); +} + int linux_futimesat(struct thread *td, struct linux_futimesat_args *args) { -- cgit v1.1 From 5835d4a5eb53fc51fba660a04f87d6fbee2561b1 Mon Sep 17 00:00:00 2001 From: dchagin Date: Sat, 9 Jan 2016 17:53:32 +0000 Subject: MFC r283491: Properly check tv_nsec value. The tv_nsec field can also be one of the special value UTIME_NOW or UTIME_OMIT. --- sys/compat/linux/linux_misc.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sys/compat/linux/linux_misc.c') diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 1c626ad..d87d786 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -139,6 +139,9 @@ struct l_pselect6arg { l_size_t ss_len; }; +static int linux_utimensat_nsec_valid(l_long); + + int linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) { @@ -823,6 +826,17 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args) return (error); } +static int +linux_utimensat_nsec_valid(l_long nsec) +{ + + if (nsec == LINUX_UTIME_OMIT || nsec == LINUX_UTIME_NOW) + return (0); + if (nsec >= 0 && nsec <= 999999999) + return (0); + return (1); +} + int linux_utimensat(struct thread *td, struct linux_utimensat_args *args) { @@ -846,8 +860,8 @@ linux_utimensat(struct thread *td, struct linux_utimensat_args *args) if (error != 0) return (error); - if (l_times[0].tv_nsec > 999999999 || - l_times[1].tv_nsec > 999999999) + if (linux_utimensat_nsec_valid(l_times[0].tv_nsec) != 0 || + linux_utimensat_nsec_valid(l_times[1].tv_nsec) != 0) return (EINVAL); times[0].tv_sec = l_times[0].tv_sec; -- cgit v1.1