From c23bc8d401427f3c772b71b4ec4e5129ce597146 Mon Sep 17 00:00:00 2001 From: Ken Sato Date: Wed, 5 Sep 2018 16:07:43 +0900 Subject: [PATCH] syscall_time: Handle by McKernel refs: #1036 Change-Id: Ifa81b613c7ee8d95ae7cdf3dd54643f60526fa73 --- arch/x86_64/kernel/include/syscall_list.h | 2 +- arch/x86_64/kernel/syscall.c | 23 ++++- arch/x86_64/kernel/vsyscall.c | 45 --------- kernel/include/syscall.h | 1 + kernel/syscall.c | 3 +- test/issues/1036/C1036.sh | 112 ++++++++++++++++++++++ test/issues/1036/CT_001.c | 47 +++++++++ test/issues/1036/Makefile | 17 ++++ test/issues/1036/README | 38 ++++++++ test/issues/1036/result.log | 73 ++++++++++++++ test/issues/1036/test_chk.h | 23 +++++ 11 files changed, 332 insertions(+), 52 deletions(-) create mode 100644 test/issues/1036/C1036.sh create mode 100644 test/issues/1036/CT_001.c create mode 100644 test/issues/1036/Makefile create mode 100644 test/issues/1036/README create mode 100644 test/issues/1036/result.log create mode 100644 test/issues/1036/test_chk.h diff --git a/arch/x86_64/kernel/include/syscall_list.h b/arch/x86_64/kernel/include/syscall_list.h index 60f01476..6de0cccc 100644 --- a/arch/x86_64/kernel/include/syscall_list.h +++ b/arch/x86_64/kernel/include/syscall_list.h @@ -114,7 +114,7 @@ SYSCALL_HANDLED(160, setrlimit) SYSCALL_HANDLED(164, settimeofday) SYSCALL_HANDLED(186, gettid) SYSCALL_HANDLED(200, tkill) -SYSCALL_DELEGATED(201, time) +SYSCALL_HANDLED(201, time) SYSCALL_HANDLED(202, futex) SYSCALL_HANDLED(203, sched_setaffinity) SYSCALL_HANDLED(204, sched_getaffinity) diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c index d1f2e438..d60ae4c7 100644 --- a/arch/x86_64/kernel/syscall.c +++ b/arch/x86_64/kernel/syscall.c @@ -1719,6 +1719,11 @@ SYSCALL_DECLARE(arch_prctl) ihk_mc_syscall_arg1(ctx)); } +SYSCALL_DECLARE(time) +{ + return time(); +} + static int vdso_get_vdso_info(void) { int error; @@ -2683,10 +2688,20 @@ out: time_t time(void) { struct syscall_request sreq IHK_DMA_ALIGN; struct thread *thread = cpu_local_var(current); - time_t ret; - sreq.number = __NR_time; - sreq.args[0] = (uintptr_t)NULL; - ret = (time_t)do_syscall(&sreq, ihk_mc_get_processor_id(), thread->proc->pid); + struct timespec ats; + time_t ret = 0; + + if (gettime_local_support) { + calculate_time_from_tsc(&ats); + ret = ats.tv_sec; + } + else { + sreq.number = __NR_time; + sreq.args[0] = (uintptr_t)NULL; + ret = (time_t)do_syscall(&sreq, ihk_mc_get_processor_id(), + thread->proc->pid); + } + return ret; } diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 1de7c452..e6e93e5e 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -31,51 +31,6 @@ struct tod_data_s tod_data .version = IHK_ATOMIC64_INIT(0), }; -static inline void cpu_pause_for_vsyscall(void) -{ - asm volatile ("pause" ::: "memory"); - return; -} /* cpu_pause_for_vsyscall() */ - -static inline void calculate_time_from_tsc(struct timespec *ts) -{ - long ver; - unsigned long current_tsc; - __time_t sec_delta; - long ns_delta; - - for (;;) { - while ((ver = ihk_atomic64_read(&tod_data.version)) & 1) { - /* settimeofday() is in progress */ - cpu_pause_for_vsyscall(); - } - rmb(); - *ts = tod_data.origin; - rmb(); - if (ver == ihk_atomic64_read(&tod_data.version)) { - break; - } - - /* settimeofday() has intervened */ - cpu_pause_for_vsyscall(); - } - - current_tsc = rdtsc(); - sec_delta = current_tsc / tod_data.clocks_per_sec; - ns_delta = NS_PER_SEC * (current_tsc % tod_data.clocks_per_sec) - / tod_data.clocks_per_sec; - /* calc. of ns_delta overflows if clocks_per_sec exceeds 18.44 GHz */ - - ts->tv_sec += sec_delta; - ts->tv_nsec += ns_delta; - if (ts->tv_nsec >= NS_PER_SEC) { - ts->tv_nsec -= NS_PER_SEC; - ++ts->tv_sec; - } - - return; -} /* calculate_time_from_tsc() */ - int vsyscall_gettimeofday(struct timeval *tv, void *tz) { int error; diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 5b13dc73..cdf7cd96 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -484,6 +484,7 @@ int arch_setup_vdso(void); int arch_cpu_read_write_register(struct ihk_os_cpu_register *desc, enum mcctrl_os_cpu_operation op); struct vm_range_numa_policy *vm_range_policy_search(struct process_vm *vm, uintptr_t addr); +void calculate_time_from_tsc(struct timespec *ts); time_t time(void); long do_futex(int n, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, diff --git a/kernel/syscall.c b/kernel/syscall.c index 7d22c8f8..83c57453 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -114,7 +114,6 @@ char *syscall_name[] MCKERNEL_UNUSED = { static ihk_spinlock_t tod_data_lock = SPIN_LOCK_UNLOCKED; static unsigned long uti_desc; /* Address of struct uti_desc object in syscall_intercept.c */ -static void calculate_time_from_tsc(struct timespec *ts); void save_syscall_return_value(int num, unsigned long rc); extern long alloc_debugreg(struct thread *thread); @@ -6954,7 +6953,7 @@ SYSCALL_DECLARE(get_cpu_id) return ihk_mc_get_processor_id(); } -static void calculate_time_from_tsc(struct timespec *ts) +void calculate_time_from_tsc(struct timespec *ts) { long ver; unsigned long current_tsc; diff --git a/test/issues/1036/C1036.sh b/test/issues/1036/C1036.sh new file mode 100644 index 00000000..5502bc1c --- /dev/null +++ b/test/issues/1036/C1036.sh @@ -0,0 +1,112 @@ +#!/bin/sh +if [ -f $HOME/mck_test_config ]; then + . $HOME/mck_test_config +else + BIN= + SBIN= + OSTEST= + LTP= +fi +BOOTPARAM="-c 1-7,9-15,17-23,25-31 -m 10G@0,10G@1 -r 1-7:0+9-15:8+17-23:16+25-31:24" + +if [ "x$BINDIR" = x ];then + BINDIR="$BIN" +fi + +if [ "x$SBINDIR" = x ];then + SBINDIR="$SBIN" +fi + +if [ "x$OSTESTDIR" = x ]; then + OSTESTDIR="$OSTEST" +fi + +if [ "x$LTPDIR" = x ]; then + LTPDIR="$LTP/testcases" +fi + +if [ ! -x $SBINDIR/mcstop+release.sh ]; then + echo mcstop+release: not found >&2 + exit 1 +fi +echo -n "mcstop+release.sh ... " +sudo $SBINDIR/mcstop+release.sh +echo "done" + +if [ ! -x $SBINDIR/mcreboot.sh ]; then + echo mcreboot: not found >&2 + exit 1 +fi +echo -n "mcreboot.sh $BOOTPARAM ... " +sudo $SBINDIR/mcreboot.sh $BOOTPARAM +echo "done" + +if [ ! -x $BINDIR/mcexec ]; then + echo mcexec: not found >&2 + exit 1 +fi + +strace -f -c -o ./CT_001.strc $BINDIR/mcexec ./CT_001 + +tid=002 +echo "*** CT_$tid start *******************************" +echo "* Check syscall_time is not delegated to mcexec" +echo "* Result of strace -f -c (expect time is NOT contained)" +cat ./CT_001.strc + +grep -e "time$" ./CT_001.strc &> /dev/null +if [ $? != 0 ]; then + echo "*** CT_$tid: PASSED" +else + echo "*** CT_$tid: FAILED" +fi +echo "" + +tid=001 +echo "*** LT_$tid start *******************************" +$BINDIR/mcexec $LTPDIR/bin/time01 2>&1 | tee ./LT_${tid}.txt +ok=`grep TPASS LT_${tid}.txt | wc -l` +ng=`grep TFAIL LT_${tid}.txt | wc -l` +if [ $ng = 0 ]; then + echo "*** LT_$tid: PASSED (ok:$ok)" +else + echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)" +fi +echo "" + +tid=002 +echo "*** LT_$tid start *******************************" +$BINDIR/mcexec $LTPDIR/bin/time02 2>&1 | tee ./LT_${tid}.txt +ok=`grep TPASS LT_${tid}.txt | wc -l` +ng=`grep TFAIL LT_${tid}.txt | wc -l` +if [ $ng = 0 ]; then + echo "*** LT_$tid: PASSED (ok:$ok)" +else + echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)" +fi +echo "" + +tid=003 +echo "*** LT_$tid start *******************************" +$BINDIR/mcexec $LTPDIR/bin/gettimeofday01 2>&1 | tee ./LT_${tid}.txt +ok=`grep TPASS LT_${tid}.txt | wc -l` +ng=`grep TFAIL LT_${tid}.txt | wc -l` +if [ $ng = 0 ]; then + echo "*** LT_$tid: PASSED (ok:$ok)" +else + echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)" +fi +echo "" + +tid=004 +echo "*** LT_$tid start *******************************" +$BINDIR/mcexec $LTPDIR/bin/gettimeofday02 2>&1 | tee ./LT_${tid}.txt +ok=`grep PASS LT_${tid}.txt | wc -l` +ng=`grep TFAIL LT_${tid}.txt | wc -l` +if [ $ng = 0 ]; then + echo "*** LT_$tid: PASSED (ok:$ok)" +else + echo "*** LT_$tid: FAILED (ok:$ok, ng:$ng)" +fi +echo "" + diff --git a/test/issues/1036/CT_001.c b/test/issues/1036/CT_001.c new file mode 100644 index 00000000..f31e89d9 --- /dev/null +++ b/test/issues/1036/CT_001.c @@ -0,0 +1,47 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "./test_chk.h" + +#define TEST_NAME "CT_001" + +int main(int argc, char *argv[]) +{ + time_t now; + long sys_ret; + int ng_flag = 0; + + printf("*** %s start *******************************\n", TEST_NAME); + + /* get seconds since the Epoch by glibc time() */ + now = time(NULL); + + /* get seconds since the Epoch by syscall_time */ + sys_ret = syscall(__NR_time, NULL); + + if (now != sys_ret) { + /* check again only once */ + now = time(NULL); + if (now != sys_ret) { + ng_flag = 1; + } + } + printf("glibc time(): %ld seconds\n", now); + printf("sys_time : %ld seconds\n", sys_ret); + + OKNG(ng_flag != 0, "check seconds since the Epoch"); + printf("*** %s PASSED\n\n", TEST_NAME); + + return 0; + +fn_fail: + + printf("*** %s FAILED\n\n", TEST_NAME); + + return -1; +} + diff --git a/test/issues/1036/Makefile b/test/issues/1036/Makefile new file mode 100644 index 00000000..75685285 --- /dev/null +++ b/test/issues/1036/Makefile @@ -0,0 +1,17 @@ +CC = gcc +TARGET=CT_001 + +CPPFLAGS = +LDFLAGS = + +all: $(TARGET) + +CT_001: CT_001.c + $(CC) -o $@ $^ $(LDFLAGS) + +test: all + @sh ./C1036.sh + +clean: + rm -f $(TARGET) *.o + diff --git a/test/issues/1036/README b/test/issues/1036/README new file mode 100644 index 00000000..2a7c054e --- /dev/null +++ b/test/issues/1036/README @@ -0,0 +1,38 @@ +【Issue#1036 動作確認】 +□ テスト内容 +1. Issueで報告された要望が実現されていることの確認 +CT_001: timeシステムコールで取得される秒数の確認 + timeシステムコールで取得された秒数と、glibcのtime()関数で + 取得された秒数が等しいことを確認する +CT_002: timeシステムコールがLinuxに移譲されないことを確認 + straceコマンドを用いて、mcexecがtimeシステムコールを + 呼び出していないことを確認する + +2. 既存のtime機能に影響がないことをLTPを用いて確認 +LT_001: ltp-syscall_time01 + time(2)の基本動作の確認 +LT_002: ltp-syscall_time02 + time(2)の返り値と、引数に指定した領域に格納される値が一致することを確認 +LT_003: ltp-syscall_gettimeofday01 + 不正な引数を指定してgettimeofday(2)を実行した場合、エラー値が返り、 + errnoにEFAULTが設定されることを確認 +LT_004: ltp-syscall_gettimeofday02 + gettimeofday(2)で取得される時刻が増加し続けることを確認する + +□ 実行手順 +McKernelのインストール先や、OSTEST, LTPの配置場所は、 +$HOME/mck_test_config を参照している +mck_test_config は、McKernelをビルドした際に生成される +mck_test_config.sample ファイルを$HOMEにコピーし、適宜編集する + +$ make test + +実行できない場合は、C1036.shの以下の行を適切に書き換えた後に実行。 +BIN= mcexec が存在するパス +SBIN= mcreboot.sh が存在するパス +OSTEST= OSTESTが存在するパス +LTP= LTPが存在するパス + +□ 実行結果 +result.log 参照。 +すべての項目をPASSしていることを確認。 diff --git a/test/issues/1036/result.log b/test/issues/1036/result.log new file mode 100644 index 00000000..6156cccb --- /dev/null +++ b/test/issues/1036/result.log @@ -0,0 +1,73 @@ +*** CT_001 start ******************************* +glibc time(): 1536804078 seconds +sys_time : 1536804078 seconds + [OK] check seconds since the Epoch +*** CT_001 PASSED + +*** CT_002 start ******************************* +* Check syscall_time is not delegated to mcexec +* Result of strace -f -c (expect time is NOT contained) +% time seconds usecs/call calls errors syscall +------ ----------- ----------- --------- --------- ---------------- + 58.26 0.033991 1133 30 futex + 31.92 0.018621 71 264 ioctl + 4.48 0.002614 7 392 356 open + 1.44 0.000839 6 146 108 stat + 0.84 0.000491 5 97 mmap + 0.80 0.000468 6 81 read + 0.51 0.000299 5 66 mprotect + 0.26 0.000151 5 32 set_robust_list + 0.21 0.000120 4 30 gettid + 0.19 0.000110 3 35 fstat + 0.17 0.000099 3 33 close + 0.14 0.000079 16 5 3 access + 0.12 0.000071 2 30 clone + 0.10 0.000057 3 19 getrlimit + 0.08 0.000048 5 10 munmap + 0.07 0.000043 0 122 rt_sigaction + 0.06 0.000033 7 5 write + 0.05 0.000032 6 5 1 openat + 0.05 0.000027 3 9 lseek + 0.05 0.000027 3 8 getdents + 0.03 0.000019 3 6 brk + 0.03 0.000018 4 5 personality + 0.03 0.000017 17 1 mlock + 0.03 0.000016 16 1 epoll_ctl + 0.02 0.000011 6 2 execve + 0.01 0.000007 7 1 pread + 0.01 0.000007 4 2 arch_prctl + 0.01 0.000006 6 1 lstat + 0.01 0.000004 2 2 rt_sigprocmask + 0.01 0.000004 4 1 getcwd + 0.01 0.000004 2 2 sched_getaffinity + 0.01 0.000003 3 1 getpgid + 0.01 0.000003 2 2 set_tid_address + 0.00 0.000000 0 1 epoll_create + 0.00 0.000000 0 1 eventfd2 +------ ----------- ----------- --------- --------- ---------------- +100.00 0.058339 1448 468 total +*** CT_002: PASSED + +*** LT_001 start ******************************* +time01 1 TPASS : time(0) returned 1536804078 +*** LT_001: PASSED (ok:1) + +*** LT_002 start ******************************* +time02 1 TPASS : time() returned value 1536804078, stored value 1536804078 are same +*** LT_002: PASSED (ok:1) + +*** LT_003 start ******************************* +gettimeofday01 1 TPASS : gettimeofday(2) set the errno EFAULT correctly +*** LT_003: PASSED (ok:1) + +*** LT_004 start ******************************* +tst_test.c:934: INFO: Timeout per run is 0h 05m 00s +gettimeofday02.c:89: INFO: gettimeofday() called 7968855 times +gettimeofday02.c:90: PASS: gettimeofday() monotonous in 10 seconds + +Summary: +passed 1 +failed 0 +skipped 0 +warnings 0 +*** LT_004: PASSED (ok:0) diff --git a/test/issues/1036/test_chk.h b/test/issues/1036/test_chk.h new file mode 100644 index 00000000..4cef42e8 --- /dev/null +++ b/test/issues/1036/test_chk.h @@ -0,0 +1,23 @@ +#ifndef HEADER_TEST_CHK_H +#define HEADER_TEST_CHK_H + +#define CHKANDJUMP(cond, ...) do {\ + if (cond) {\ + fprintf(stderr, " [NG] ");\ + fprintf(stderr, __VA_ARGS__);\ + fprintf(stderr, " failed\n");\ + goto fn_fail;\ + } \ + } while (0) + +#define OKNG(cond, ...) do {\ + if (cond) {\ + CHKANDJUMP(cond, __VA_ARGS__);\ + } else {\ + fprintf(stdout, " [OK] ");\ + fprintf(stdout, __VA_ARGS__);\ + fprintf(stdout, "\n");\ + } \ + } while (0) + +#endif