Skip to content

Commit

Permalink
OS-6364 lx: USER_HZ of 1000 breaks broken code which assumes 100 HZ
Browse files Browse the repository at this point in the history
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
  • Loading branch information
jjelinek committed Oct 9, 2017
1 parent 0ec9261 commit 9793308
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 34 deletions.
9 changes: 7 additions & 2 deletions usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
9 changes: 6 additions & 3 deletions usr/src/lib/brand/lx/lx_brand/common/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/

/*
* Copyright 2016 Joyent, Inc. All rights reserved.
* Copyright 2017 Joyent, Inc. All rights reserved.
*/

#include <sys/types.h>
Expand All @@ -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>
Expand Down Expand Up @@ -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:
Expand Down
21 changes: 1 addition & 20 deletions usr/src/lib/brand/lx/lx_brand/common/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -33,25 +33,6 @@
#include <sys/lx_syscall.h>
#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.
Expand Down
1 change: 0 additions & 1 deletion usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 9 additions & 2 deletions usr/src/uts/common/brand/lx/os/lx_brand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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] = {
Expand All @@ -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,
Expand Down Expand Up @@ -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();
Expand Down
13 changes: 9 additions & 4 deletions usr/src/uts/common/brand/lx/os/lx_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions usr/src/uts/common/brand/lx/os/lx_syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/brand/lx/sys/lx_syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
62 changes: 62 additions & 0 deletions usr/src/uts/common/brand/lx/sys/lx_userhz.h
Original file line number Diff line number Diff line change
@@ -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 */
72 changes: 72 additions & 0 deletions usr/src/uts/common/brand/lx/syscall/lx_time.c
Original file line number Diff line number Diff line change
@@ -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));
}
}
1 change: 1 addition & 0 deletions usr/src/uts/intel/Makefile.files
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down

0 comments on commit 9793308

Please sign in to comment.