diff options
| author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2017-10-09 17:58:15 +0000 |
|---|---|---|
| committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2017-10-09 20:58:58 +0000 |
| commit | 9793308df96de5fbb991049b785ac9b9f4b23bd7 (patch) | |
| tree | e93ffce2233f7ee42834ab4584ae6abd0d8233ed | |
| parent | 0ec9261447c52e79ab28e4c9ec594d2c6b040f3e (diff) | |
| download | illumos-joyent-9793308df96de5fbb991049b785ac9b9f4b23bd7.tar.gz | |
OS-6364 lx: USER_HZ of 1000 breaks broken code which assumes 100 HZ
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 9 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/signal.c | 9 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/time.c | 21 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_brand.c | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_misc.c | 13 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_syscall.c | 4 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_syscalls.h | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_userhz.h | 62 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/syscall/lx_time.c | 72 | ||||
| -rw-r--r-- | usr/src/uts/intel/Makefile.files | 1 |
11 files changed, 170 insertions, 34 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c index 99a0e64f01..fea15349c7 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c +++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c @@ -73,6 +73,7 @@ #include <sys/lx_syscall.h> #include <sys/lx_thread.h> #include <lx_auxv.h> +#include <sys/lx_userhz.h> /* * There is a block comment in "uts/common/brand/lx/os/lx_brand.c" that @@ -135,6 +136,8 @@ pid_t zoneinit_pid; /* zone init PID */ thread_key_t lx_tsd_key; +uint_t lx_hz_scale; /* USER_HZ scaling factor */ + int uucopy_unsafe(const void *src, void *dst, size_t n) { @@ -626,6 +629,8 @@ lx_init(int argc, char *argv[], char *envp[]) bzero(®, sizeof (reg)); stack_size = 2 * sysconf(_SC_PAGESIZE); + lx_hz_scale = sysconf(_SC_CLK_TCK) / LX_USERHZ; + /* * We need to shutdown all libc stdio. libc stdio normally goes to * file descriptors, but since we're actually part of a linux @@ -1110,7 +1115,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 97: getrlimit */ NULL, /* 98: getrusage */ NULL, /* 99: sysinfo */ - lx_times, /* 100: times */ + NULL, /* 100: times */ NULL, /* 101: ptrace */ NULL, /* 102: getuid */ NULL, /* 103: syslog */ @@ -1384,7 +1389,7 @@ static lx_syscall_handler_t lx_handlers[] = { lx_rmdir, /* 40: rmdir */ NULL, /* 41: dup */ NULL, /* 42: pipe */ - lx_times, /* 43: times */ + NULL, /* 43: times */ NULL, /* 44: prof */ NULL, /* 45: brk */ NULL, /* 46: setgid16 */ diff --git a/usr/src/lib/brand/lx/lx_brand/common/signal.c b/usr/src/lib/brand/lx/lx_brand/common/signal.c index 45de7615bc..5c754733cb 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/signal.c +++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c @@ -25,7 +25,7 @@ */ /* - * Copyright 2016 Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. All rights reserved. */ #include <sys/types.h> @@ -40,6 +40,7 @@ #include <sys/lx_sigstack.h> #include <sys/lx_syscall.h> #include <sys/lx_thread.h> +#include <sys/lx_userhz.h> #include <sys/syscall.h> #include <lx_provider_impl.h> #include <sys/stack.h> @@ -473,8 +474,10 @@ stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop) lx_siginfo.lsi_status = lx_stol_status( siginfop->si_status, -1); } - lx_siginfo.lsi_utime = siginfop->si_utime; - lx_siginfo.lsi_stime = siginfop->si_stime; + lx_siginfo.lsi_utime = + HZ_TO_LX_USERHZ(siginfop->si_utime); + lx_siginfo.lsi_stime = + HZ_TO_LX_USERHZ(siginfop->si_stime); break; case LX_SIGILL: diff --git a/usr/src/lib/brand/lx/lx_brand/common/time.c b/usr/src/lib/brand/lx/lx_brand/common/time.c index c810aa33f1..db63c5643c 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/time.c +++ b/usr/src/lib/brand/lx/lx_brand/common/time.c @@ -22,7 +22,7 @@ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2014 Joyent, Inc. All rights reserved. + * Copyright 2017 Joyent, Inc. All rights reserved. */ #include <errno.h> @@ -34,25 +34,6 @@ #include <sys/lx_misc.h> /* - * times() - The Linux implementation avoids writing to NULL, while Illumos - * returns EFAULT. - */ -long -lx_times(uintptr_t p1) -{ - clock_t ret; - struct tms buf, *tp = (struct tms *)p1; - - ret = times(&buf); - - if ((ret == -1) || - ((tp != NULL) && uucopy((void *)&buf, tp, sizeof (buf)) != 0)) - return (-errno); - - return ((ret == -1) ? -errno : ret); -} - -/* * setitimer() - the Linux implementation can handle tv_usec values greater * than 1,000,000 where Illumos would return EINVAL. * diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h index 2c8db5cd32..1ea278764f 100644 --- a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h +++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h @@ -97,7 +97,6 @@ extern long lx_setgroups16(uintptr_t, uintptr_t); extern long lx_query_module(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); -extern long lx_times(uintptr_t); extern long lx_setitimer(uintptr_t, uintptr_t, uintptr_t); extern long lx_clone(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c index 3646df26e5..a691b620b3 100644 --- a/usr/src/uts/common/brand/lx/os/lx_brand.c +++ b/usr/src/uts/common/brand/lx/os/lx_brand.c @@ -150,6 +150,7 @@ #include <sys/lx_futex.h> #include <sys/lx_brand.h> #include <sys/lx_types.h> +#include <sys/lx_userhz.h> #include <sys/param.h> #include <sys/termios.h> #include <sys/sunddi.h> @@ -178,6 +179,7 @@ #include <inet/udp_impl.h> int lx_debug = 0; +uint_t lx_hz_scale = 0; void lx_init_brand_data(zone_t *, kmutex_t *); void lx_free_brand_data(zone_t *); @@ -2435,7 +2437,8 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args, /* * We try to keep /proc's view of the aux vector consistent with - * what's on the process stack. + * what's on the process stack. See the comment on the lx_times + * syscall for an explanation of the hardcoded LX_USERHZ. */ if (args->to_model == DATAMODEL_NATIVE) { auxv_t phdr_auxv[4] = { @@ -2446,7 +2449,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args, }; phdr_auxv[0].a_un.a_val = edp.ed_phdr; phdr_auxv[1].a_un.a_val = ldaddr; - phdr_auxv[2].a_un.a_val = hz; + phdr_auxv[2].a_un.a_val = LX_USERHZ; phdr_auxv[3].a_un.a_val = lxpd->l_vdso; if (copyout(&phdr_auxv, args->auxp_brand, @@ -2573,6 +2576,10 @@ _init(void) { int err = 0; + /* Initialize USER_HZ scaling factor */ + ASSERT(hz >= LX_USERHZ); + lx_hz_scale = hz / LX_USERHZ; + lx_syscall_init(); lx_pid_init(); lx_ioctl_init(); diff --git a/usr/src/uts/common/brand/lx/os/lx_misc.c b/usr/src/uts/common/brand/lx/os/lx_misc.c index 05203c832d..53963c0f7d 100644 --- a/usr/src/uts/common/brand/lx/os/lx_misc.c +++ b/usr/src/uts/common/brand/lx/os/lx_misc.c @@ -40,6 +40,7 @@ #include <sys/lx_siginfo.h> #include <sys/lx_futex.h> #include <lx_errno.h> +#include <sys/lx_userhz.h> #include <sys/cmn_err.h> #include <sys/siginfo.h> #include <sys/contract/process_impl.h> @@ -713,6 +714,10 @@ lx_winfo(proc_t *pp, k_siginfo_t *ip, struct lx_proc_data *dat) ip->si_ctid = PRCTID(pp); ip->si_zoneid = pp->p_zone->zone_id; ip->si_status = pp->p_wdata; + /* + * These siginfo values are converted to USER_HZ in the user-land + * brand signal code. + */ ip->si_stime = pp->p_stime; ip->si_utime = pp->p_utime; } @@ -961,8 +966,8 @@ stol_ksiginfo_copyout(k_siginfo_t *sip, void *ulxsip) lsi.lsi_status = lx_stol_status(sip->si_status, SIGKILL); } - lsi.lsi_utime = sip->si_utime; - lsi.lsi_stime = sip->si_stime; + lsi.lsi_utime = HZ_TO_LX_USERHZ(sip->si_utime); + lsi.lsi_stime = HZ_TO_LX_USERHZ(sip->si_stime); break; case LX_SIGILL: @@ -1009,8 +1014,8 @@ stol_ksiginfo32_copyout(k_siginfo_t *sip, void *ulxsip) lsi.lsi_status = lx_stol_status(sip->si_status, SIGKILL); } - lsi.lsi_utime = sip->si_utime; - lsi.lsi_stime = sip->si_stime; + lsi.lsi_utime = HZ_TO_LX_USERHZ(sip->si_utime); + lsi.lsi_stime = HZ_TO_LX_USERHZ(sip->si_stime); break; case LX_SIGILL: diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c index ccabe9aa0d..d308d71661 100644 --- a/usr/src/uts/common/brand/lx/os/lx_syscall.c +++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c @@ -562,7 +562,7 @@ lx_sysent_t lx_sysent32[] = { {"rmdir", NULL, 0, 1}, /* 40 */ {"dup", lx_dup, 0, 1}, /* 41 */ {"pipe", lx_pipe, 0, 1}, /* 42 */ - {"times", NULL, 0, 1}, /* 43 */ + {"times", lx_times, 0, 1}, /* 43 */ {"prof", NULL, NOSYS_OBSOLETE, 0}, /* 44 */ {"brk", lx_brk, 0, 1}, /* 45 */ {"setgid16", lx_setgid16, 0, 1}, /* 46 */ @@ -990,7 +990,7 @@ lx_sysent_t lx_sysent64[] = { {"getrlimit", lx_getrlimit, 0, 2}, /* 97 */ {"getrusage", lx_getrusage, 0, 2}, /* 98 */ {"sysinfo", lx_sysinfo64, 0, 1}, /* 99 */ - {"times", NULL, 0, 1}, /* 100 */ + {"times", lx_times, 0, 1}, /* 100 */ {"ptrace", lx_ptrace, 0, 4}, /* 101 */ {"getuid", lx_getuid, 0, 0}, /* 102 */ {"syslog", lx_syslog, 0, 3}, /* 103 */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h index 54f11a71f2..20b0c2ed55 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h +++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h @@ -254,6 +254,7 @@ extern long lx_syslog(); extern long lx_removexattr(); extern long lx_tgkill(); extern long lx_time(); +extern long lx_times(); extern long lx_timer_create(); extern long lx_tkill(); extern long lx_umask(); diff --git a/usr/src/uts/common/brand/lx/sys/lx_userhz.h b/usr/src/uts/common/brand/lx/sys/lx_userhz.h new file mode 100644 index 0000000000..7f273744c8 --- /dev/null +++ b/usr/src/uts/common/brand/lx/sys/lx_userhz.h @@ -0,0 +1,62 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Joyent, Inc. + */ + +#ifndef _LX_USERHZ_H +#define _LX_USERHZ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Within the kernel, Linux implements an internal hz that they refer to as a + * "jiffy". Linux can be built with different hz, but on modern kernels + * it is frequently 250. However, Linux has a separate concept for the hz + * that is visible outside the kernel. This is called "USER_HZ" and is the + * value returned by 'sysconf(_SC_CLK_TCK)'. This is almost universally set to + * 100hz. Some (lazy) applications just hardcode 100hz instead of checking. + * To accommodate these broken applications, we always work with a USER_HZ of + * 100 and scale accordingly. See the Linux time(7) man page for a more + * detailed discussion of their behavior. See the comment in our + * uts/common/conf/param.c for a discussion of valid native hz values. + * + * There are a few interfaces which expose a clock_t to user-land and which + * need to be considered for USER_HZ adjustment. + * 1) The times(2) syscall. This is handled correctly. + * 2) The waitid(2) syscall passes a siginfo_t which contains si_stime and + * si_utime. Testing waitid(2) on various Linux distributions shows that the + * these fields are garbage. This aligns with the Linux waitid(2) man page, + * which describes the subset of the siginfo_t structure that is populated. + * Neither si_stime or si_utime are listed. + * 3) A sigaction(2) handler can pass a siginfo_t. This is only documented to + * occur when the sa_flags is SA_SIGINFO. The si_stime and si_utime are + * documented to only be populated when the signal is SIGCHLD. However, + * testing on Linux seems to show that these fields are not consistent + * with the corresponding times(2) data for the process, even for the + * SIGCHLD sigaction handler case. + * + * Although the siginfo_t si_stime and si_utime data for cases #2 and #3 is not + * consistent on Linux, we populate these fields correctly to be on the safe + * side. + */ +extern uint_t lx_hz_scale; +#define LX_USERHZ 100 +#define HZ_TO_LX_USERHZ(x) ((x) / lx_hz_scale) + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_USERHZ_H */ diff --git a/usr/src/uts/common/brand/lx/syscall/lx_time.c b/usr/src/uts/common/brand/lx/syscall/lx_time.c new file mode 100644 index 0000000000..b9bc8e5ab4 --- /dev/null +++ b/usr/src/uts/common/brand/lx/syscall/lx_time.c @@ -0,0 +1,72 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017, Joyent, Inc. + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/thread.h> +#include <sys/proc.h> +#include <sys/times.h> +#include <sys/msacct.h> +#include <sys/lx_userhz.h> + +/* See the comment on LX_USERHZ for more details. */ +#define LX_NSEC_PER_USERHZ (NANOSEC / LX_USERHZ) +#define NSEC_TO_LX_USERHZ(nsec) ((nsec) / LX_NSEC_PER_USERHZ) + +/* + * Our times(2) implementation is based on the native times(2), but with + * the necessary scaling to adjust to USER_HZ. Also, Linux avoids writing + * to a NULL tp, whereas our native code returns EFAULT. + */ +long +lx_times(struct tms *tp) +{ + proc_t *p = curproc; + struct tms p_time; + clock_t ret_lbolt; + + mutex_enter(&p->p_lock); + p_time.tms_utime = + (clock_t)NSEC_TO_LX_USERHZ(mstate_aggr_state(p, LMS_USER)); + p_time.tms_stime = + (clock_t)NSEC_TO_LX_USERHZ(mstate_aggr_state(p, LMS_SYSTEM)); + p_time.tms_cutime = HZ_TO_LX_USERHZ(p->p_cutime); + p_time.tms_cstime = HZ_TO_LX_USERHZ(p->p_cstime); + mutex_exit(&p->p_lock); + +#ifdef _SYSCALL32_IMPL + if (get_udatamodel() != DATAMODEL_NATIVE) { + struct tms32 t32; + + t32.tms_utime = p_time.tms_utime; + t32.tms_stime = p_time.tms_stime; + t32.tms_cutime = p_time.tms_cutime; + t32.tms_cstime = p_time.tms_cstime; + + if (tp != NULL && copyout(&t32, tp, sizeof (t32)) != 0) + return (set_errno(EFAULT)); + + ret_lbolt = ddi_get_lbolt(); + return ((clock32_t)HZ_TO_LX_USERHZ(ret_lbolt)); + } else +#endif /* _SYSCALL32_IMPL */ + { + if (tp != NULL && copyout(&p_time, tp, sizeof (p_time)) != 0) + return (set_errno(EFAULT)); + + ret_lbolt = ddi_get_lbolt(); + return (HZ_TO_LX_USERHZ(ret_lbolt)); + } +} diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index 8f8a70d22f..f118f1f157 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -359,6 +359,7 @@ LX_BRAND_OBJS = \ lx_syscall.o \ lx_sysinfo.o \ lx_thread_area.o \ + lx_time.o \ lx_timer.o \ lx_umask.o \ lx_uname.o \ |
