summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2017-10-09 17:58:15 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2017-10-09 20:58:58 +0000
commit9793308df96de5fbb991049b785ac9b9f4b23bd7 (patch)
treee93ffce2233f7ee42834ab4584ae6abd0d8233ed
parent0ec9261447c52e79ab28e4c9ec594d2c6b040f3e (diff)
downloadillumos-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.c9
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/signal.c9
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/time.c21
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h1
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c11
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_misc.c13
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_syscall.c4
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_syscalls.h1
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_userhz.h62
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_time.c72
-rw-r--r--usr/src/uts/intel/Makefile.files1
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(&reg, 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 \