All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH 1/2] lib: include SAFE_CLOCK_ADJTIME() macro
@ 2019-02-21 20:05 Rafael David Tinoco
  2019-02-21 20:05 ` [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  0 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-21 20:05 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index 553f8464a..304207f6b 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,6 +6,8 @@
 
 #include <time.h>
 #include "tst_test.h"
+#include <sys/timex.h>
+#include "lapi/syscalls.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
 	clockid_t clk_id, struct timespec *res)
@@ -42,6 +44,17 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline void safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+
+	if (rval != 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed", file, lineno);
+}
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -50,3 +63,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-21 20:05 [LTP] [PATCH 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-02-21 20:05 ` Rafael David Tinoco
  2019-02-21 20:19   ` Rafael David Tinoco
  2019-02-21 20:30   ` [LTP] [PATCH v2 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  0 siblings, 2 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-21 20:05 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

  1) a regular POSIX clock (only REALTIME clock implements adjtime())
  	- will behave exactly like adjtimex() system call.
  	- only one being tested here.

  2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
  	- will trigger the PTP clock driver function "adjtime()"
  	- different implementations from one PTP clock to another
  	- might return EOPNOTSUPP (like ptp_kvm_caps, for example)
  	- no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 249 +++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 261 ++++++++++++++++++
 5 files changed, 525 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 7bccda996..093e7f2ef 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..958b08802
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *   	- will behave exactly like adjtimex() system call.
+ *   	- only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *   	- will trigger the PTP clock driver function "adjtime()"
+ *   	- different implementations from one PTP clock to another
+ *   	- might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *   	- no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 512000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr -= (2 * tc[i].delta);
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i=0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..74893a4e3
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *   	- will behave exactly like adjtimex() system call.
+ *   	- only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *   	- will trigger the PTP clock driver function "adjtime()"
+ *   	- different implementations from one PTP clock to another
+ *   	- might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *   	- no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+#include <pwd.h>
+
+#include <stdio.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+#define MAX_CLOCKS 16
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: 0x%x\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: 0x%x\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami=0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	static char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/* special case - if txcptr != NULL, SIGSEGV is throwed */
+	if (tc[i].exp_err == EFAULT)
+		txcptr = NULL;
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	 if (TST_ERR != tc[i].exp_err) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+	 	return;
+	 }
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i=0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-21 20:05 ` [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-02-21 20:19   ` Rafael David Tinoco
  2019-02-21 20:30   ` [LTP] [PATCH v2 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-21 20:19 UTC (permalink / raw)
  To: ltp

> On 21 Feb 2019, at 17:05, Rafael David Tinoco <rafael.tinoco@linaro.org> wrote:
> 
> Fixes: 270
> 
> clock_adjtime{01,02} are created using the new API, based on existing
> adjtimex(2) tests. clock_adjtime() syscall might have as execution
> path:
> 
>  1) a regular POSIX clock (only REALTIME clock implements adjtime())
>  	- will behave exactly like adjtimex() system call.
>  	- only one being tested here.
> 
>  2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
>  	- will trigger the PTP clock driver function "adjtime()"
>  	- different implementations from one PTP clock to another
>  	- might return EOPNOTSUPP (like ptp_kvm_caps, for example)
>  	- no observed execution entry point for clock_adjtime()
> 
> Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>

Sorry, forgot to checkpatch before sending. Doing it now and submitting patchset as v2.

Thank you!

-Rafael


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 1/2] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-02-21 20:05 ` [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2019-02-21 20:19   ` Rafael David Tinoco
@ 2019-02-21 20:30   ` Rafael David Tinoco
  2019-02-21 20:30     ` [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  1 sibling, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-21 20:30 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index 553f8464a..304207f6b 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,6 +6,8 @@
 
 #include <time.h>
 #include "tst_test.h"
+#include <sys/timex.h>
+#include "lapi/syscalls.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
 	clockid_t clk_id, struct timespec *res)
@@ -42,6 +44,17 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline void safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+
+	if (rval != 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed", file, lineno);
+}
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -50,3 +63,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-21 20:30   ` [LTP] [PATCH v2 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-02-21 20:30     ` Rafael David Tinoco
  2019-02-26  0:17       ` Petr Vorel
  0 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-21 20:30 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

 1) a regular POSIX clock (only REALTIME clock implements adjtime())
 	- will behave exactly like adjtimex() system call.
 	- only one being tested here.

 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
 	- will trigger the PTP clock driver function "adjtime()"
 	- different implementations from one PTP clock to another
 	- might return EOPNOTSUPP (like ptp_kvm_caps, for example)
 	- no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 249 +++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 261 ++++++++++++++++++
 5 files changed, 525 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 7bccda996..093e7f2ef 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..541d9437d
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 512000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr -= (2 * tc[i].delta);
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..ec1071c11
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+#include <pwd.h>
+
+#include <stdio.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+#define MAX_CLOCKS 16
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: 0x%x\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: 0x%x\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami = 0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	const char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/* special case - if txcptr != NULL, SIGSEGV is throwed */
+	if (tc[i].exp_err == EFAULT)
+		txcptr = NULL;
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	if (tc[i].exp_err != TST_ERR) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+		return;
+	}
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-21 20:30     ` [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-02-26  0:17       ` Petr Vorel
  2019-02-26  0:24         ` Enji Cooper
  2019-02-26 16:08         ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  0 siblings, 2 replies; 37+ messages in thread
From: Petr Vorel @ 2019-02-26  0:17 UTC (permalink / raw)
  To: ltp

Hi Rafael,

> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> new file mode 100644
> index 000000000..541d9437d
...

> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
> +	timex_show("SET", ttxc);
> +
> +	if (tc[i].ptr) {
> +
> +		/* adjtimex field being tested so we can verify later */
> +
> +		ptroff = (long) tc[i].ptr - (long) &ttxc;
> +		ptr = (void *) &verify + ptroff;
> +	}
> +
> +	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
> +	timex_show("VERIFY", verify);
> +
> +	if (tc[i].ptr && *tc[i].ptr != *ptr) {
Can you please fix this compiler error:
clock_adjtime01.c: In function ‘verify_clock_adjtime’:
clock_adjtime01.c:199:33: warning: ‘ptr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  if (tc[i].ptr && *tc[i].ptr != *ptr) {


Kind regards,
Petr

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-26  0:17       ` Petr Vorel
@ 2019-02-26  0:24         ` Enji Cooper
  2019-02-26 16:08         ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Enji Cooper @ 2019-02-26  0:24 UTC (permalink / raw)
  To: ltp



> On Feb 25, 2019, at 4:17 PM, Petr Vorel <pvorel@suse.cz> wrote:
> 
> Hi Rafael,
> 
>> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
>> new file mode 100644
>> index 000000000..541d9437d
> ...
> 
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
>> +	timex_show("SET", ttxc);
>> +
>> +	if (tc[i].ptr) {
>> +
>> +		/* adjtimex field being tested so we can verify later */
>> +
>> +		ptroff = (long) tc[i].ptr - (long) &ttxc;
>> +		ptr = (void *) &verify + ptroff;
>> +	}
>> +
>> +	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
>> +	timex_show("VERIFY", verify);
>> +
>> +	if (tc[i].ptr && *tc[i].ptr != *ptr) {
> Can you please fix this compiler error:
> clock_adjtime01.c: In function ‘verify_clock_adjtime’:
> clock_adjtime01.c:199:33: warning: ‘ptr’ may be used uninitialized in this function [-Wmaybe-uninitialized]
>  if (tc[i].ptr && *tc[i].ptr != *ptr) {

Wow. That’s a really dumb, tautologically impossible compiler error :(…
-Enji

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-02-26  0:17       ` Petr Vorel
  2019-02-26  0:24         ` Enji Cooper
@ 2019-02-26 16:08         ` Rafael David Tinoco
  2019-02-26 16:08           ` [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2019-03-13 16:09           ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
  1 sibling, 2 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-26 16:08 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index 553f8464a..304207f6b 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,6 +6,8 @@
 
 #include <time.h>
 #include "tst_test.h"
+#include <sys/timex.h>
+#include "lapi/syscalls.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
 	clockid_t clk_id, struct timespec *res)
@@ -42,6 +44,17 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline void safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+
+	if (rval != 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed", file, lineno);
+}
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -50,3 +63,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-26 16:08         ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-02-26 16:08           ` Rafael David Tinoco
  2019-03-13 16:32             ` Cyril Hrubis
  2019-03-13 16:09           ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
  1 sibling, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-02-26 16:08 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

 1) a regular POSIX clock (only REALTIME clock implements adjtime())
    - will behave exactly like adjtimex() system call.
    - only one being tested here.

 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
    - will trigger the PTP clock driver function "adjtime()"
    - different implementations from one PTP clock to another
    - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
    - no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 249 +++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 261 ++++++++++++++++++
 5 files changed, 525 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 0af0f4475..49411d65c 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..999865b96
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 512000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr = NULL;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr -= (2 * tc[i].delta);
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..05b4b0a18
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include <sys/timex.h>
+#include <pwd.h>
+
+#include <stdio.h>
+
+static long hz;
+static struct timex saved, ttxc;
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
+	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
+
+#define MAX_CLOCKS 16
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: 0x%x\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: 0x%x\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami = 0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	static const char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/* special case - if txcptr != NULL, SIGSEGV is throwed */
+	if (tc[i].exp_err == EFAULT)
+		txcptr = NULL;
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	if (tc[i].exp_err != TST_ERR) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+		return;
+	}
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-02-26 16:08         ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-02-26 16:08           ` [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-03-13 16:09           ` Cyril Hrubis
  2019-03-13 16:26             ` Rafael David Tinoco
  1 sibling, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-13 16:09 UTC (permalink / raw)
  To: ltp

Hi!
> +static inline void safe_clock_adjtime(const char *file, const int lineno,
> +	clockid_t clk_id, struct timex *txc)
> +{
> +	int rval;
> +
> +	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);

Any reason why we don't use clock_adjtime() here?

Or is the glibc wrapper missing?

> +	if (rval != 0)
> +		tst_brk(TBROK | TERRNO,
> +			"%s:%d clock_adjtime() failed", file, lineno);
> +}
>  #define SAFE_CLOCK_GETRES(clk_id, res)\
>  	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
>  
> @@ -50,3 +63,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
>  
>  #define SAFE_CLOCK_SETTIME(clk_id, tp)\
>  	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
> +
> +#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
> +	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
> -- 
> 2.20.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-03-13 16:09           ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
@ 2019-03-13 16:26             ` Rafael David Tinoco
  0 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-13 16:26 UTC (permalink / raw)
  To: ltp

> On 13 Mar 2019, at 13:09, Cyril Hrubis <chrubis@suse.cz <mailto:chrubis@suse.cz>> wrote:
> 
> Hi!
>> +static inline void safe_clock_adjtime(const char *file, const int lineno,
>> +	clockid_t clk_id, struct timex *txc)
>> +{
>> +	int rval;
>> +
>> +	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
> 
> Any reason why we don't use clock_adjtime() here?
> 
> Or is the glibc wrapper missing?

Yes, it is missing. It was added in glibc NEWS in a “new Linux interfaces” list and put into the syscalls list, but, at the moment, there is nothing wrapping it. 

> 
>> +	if (rval != 0)
>> +		tst_brk(TBROK | TERRNO,
>> +			"%s:%d clock_adjtime() failed", file, lineno);
>> +}
>> #define SAFE_CLOCK_GETRES(clk_id, res)\
>> 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
>> 
>> @@ -50,3 +63,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
>> 
>> #define SAFE_CLOCK_SETTIME(clk_id, tp)\
>> 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
>> +
>> +#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
>> +	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
>> -- 
>> 2.20.1
>> 
>> 
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp <https://lists.linux.it/listinfo/ltp>
> -- 
> Cyril Hrubis
> chrubis@suse.cz <mailto:chrubis@suse.cz>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20190313/40e5e580/attachment.html>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-02-26 16:08           ` [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-03-13 16:32             ` Cyril Hrubis
  2019-03-15 11:07               ` Rafael David Tinoco
  2019-03-20 21:41               ` [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-13 16:32 UTC (permalink / raw)
  To: ltp

Hi!
I finally had time to read the manual page for adjtime and look into
these tests. They look more or less fine, the only problem here is that
we merely scratch the surface here, i.e. most of the STA_* constants are
not tested etc. I guess that with CLOCK_MONOTONIC_RAW we should be even
able measure that the time has been adjusted, leap second inserted, etc.
However such tests would require quite a lot of effort. Even triggering
leap second insertion/deletion requires fiddling with system time and
sleeping till the kernel state machine does it job.

> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> new file mode 100644
> index 000000000..999865b96
> --- /dev/null
> +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> @@ -0,0 +1,249 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Linaro Limited. All rights reserved.
> + * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
> + */
> +
> +/*
> + * clock_adjtime() syscall might have as execution path:
> + *
> + *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
> + *      - will behave exactly like adjtimex() system call.
> + *      - only one being tested here.
> + *
> + *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
> + *      - will trigger the PTP clock driver function "adjtime()"
> + *      - different implementations from one PTP clock to another
> + *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
> + *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
> + *
> + * so it is sane to check possible adjustments:
> + *
> + *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
> + *                       (-512000 < offset < 512000)
> + *    - ADJ_FREQUENCY  - system clock frequency offset
> + *    - ADJ_MAXERROR   - maximum error (usec)
> + *    - ADJ_ESTERROR   - estimated time error in us
> + *    - ADJ_STATUS     - clock command/status of ntp implementation
> + *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
> + *    - ADJ_TICK       - us between clock ticks
> + *                       (>= 900000/HZ, <= 1100000/HZ)
> + *
> + * and also the standalone ones (using .offset variable):
> + *
> + *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
> + *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
> + *
> + * For ADJ_STATUS, consider the following flags:
> + *
> + *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
> + *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
> + *      rw  STA_PPSTIME - enable PPS time discipline
> + *      rw  STA_FLL - select freq-locked loop mode.
> + *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
> + *      rw  STA_DEL - del leap sec at last sec of UTC day (all days)
> + *      rw  STA_UNSYNC - clock unsynced
> + *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
> + *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
> + *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
> + *      ro  STA_PPSWANDER - PPS signal wander exceeded.
> + *      ro  STA_PPSERROR - PPS signal calibration error.
> + *      ro  STA_CLOKERR - clock HW fault.
> + *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
> + *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
> + *      ro  STA_CLK - clock source. unused.
> + */
> +
> +#include "config.h"
> +#include "tst_test.h"
> +#include "lapi/syscalls.h"
> +#include "lapi/posix_clocks.h"
> +#include "tst_timer.h"
> +#include "tst_safe_clocks.h"
> +#include <sys/timex.h>
> +
> +static long hz;
> +static struct timex saved, ttxc;
> +
> +#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
> +	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
> +
> +struct test_case {
> +	unsigned int modes;
> +	long highlimit;
> +	long *ptr;
> +	long delta;
> +};
> +
> +struct test_case tc[] = {
> +	{
> +	 .modes = ADJ_OFFSET_SINGLESHOT,
> +	},
> +	{
> +	 .modes = ADJ_OFFSET_SS_READ,
> +	},
> +	{
> +	 .modes = ADJ_ALL,
> +	},
> +	{
> +	 .modes = ADJ_OFFSET,
> +	 .highlimit = 512000,
> +	 .ptr = &ttxc.offset,
> +	 .delta = 10000,
> +	},

I wonder what we should do with STA_NANO vs STA_MICRO if a ntp daemon
set STA_NANO this limit would be three orders of magnitude off, maybe we
should check for this in the setup as well.

Also manual states that the limit is -0.5, +0.5 range, we should really
set the limit to 500000 then, then we can just clamp the value instead
of decreasing by 2 * delta (why do we do even do that) donw in the test
function.

> +	{
> +	 .modes = ADJ_FREQUENCY,
> +	 .ptr = &ttxc.freq,
> +	 .delta = 100,
> +	},
> +	{
> +	 .modes = ADJ_MAXERROR,
> +	 .ptr = &ttxc.maxerror,
> +	 .delta = 100,
> +	},
> +	{
> +	 .modes = ADJ_ESTERROR,
> +	 .ptr = &ttxc.esterror,
> +	 .delta = 100,
> +	},
> +	{
> +	 .modes = ADJ_TIMECONST,
> +	 .ptr = &ttxc.constant,
> +	 .delta = 1,
> +	},
> +	{
> +	 .modes = ADJ_TICK,
> +	 .highlimit = 1100000,
> +	 .ptr = &ttxc.tick,
> +	 .delta = 1000,
> +	},
> +};
> +
> +/*
> + * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
> + */
> +static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
> +{
> +	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
> +}
> +
> +static void timex_show(char *given, struct timex txc)
> +{
> +	tst_res(TINFO,  "%s\n"
> +			"             mode: %d\n"
> +			"           offset: %ld\n"
> +			"        frequency: %ld\n"
> +			"         maxerror: %ld\n"
> +			"         esterror: %ld\n"
> +			"           status: %d (0x%x)\n"
> +			"    time_constant: %ld\n"
> +			"        precision: %ld\n"
> +			"        tolerance: %ld\n"
> +			"             tick: %ld\n"
> +			"         raw time: %d(s) %d(us)",
> +			given,
> +			txc.modes,
> +			txc.offset,
> +			txc.freq,
> +			txc.maxerror,
> +			txc.esterror,
> +			txc.status,
> +			txc.status,
> +			txc.constant,
> +			txc.precision,
> +			txc.tolerance,
> +			txc.tick,
> +			(int)txc.time.tv_sec,
> +			(int)txc.time.tv_usec);
> +}
> +
> +static void verify_clock_adjtime(unsigned int i)
> +{
> +	long ptroff, *ptr = NULL;
> +	struct timex verify;
> +
> +	memset(&ttxc, 0, sizeof(struct timex));
> +	memset(&verify, 0, sizeof(struct timex));
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
> +	timex_show("GET", ttxc);
> +
> +	ttxc.modes = tc[i].modes;
> +
> +	if (tc[i].ptr && tc[i].delta) {
> +
> +		*tc[i].ptr += tc[i].delta;
> +
> +		/* fix limits, if existent, so no errors occur */
> +
> +		if (tc[i].highlimit) {
> +			if (*tc[i].ptr >= tc[i].highlimit)
> +				*tc[i].ptr -= (2 * tc[i].delta);
> +		}

Here if we had the highlimit correct we can just do:


		if (tc[i].highlimit) {
			if (*tc[i].ptr > tc[i].highlimit)
				*tc[i].ptr = tc[i].highlimit;
		}

Or is there a reason why this cannot work?


> +	}
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
> +	timex_show("SET", ttxc);
> +
> +	if (tc[i].ptr) {
> +
> +		/* adjtimex field being tested so we can verify later */
> +
> +		ptroff = (long) tc[i].ptr - (long) &ttxc;
> +		ptr = (void *) &verify + ptroff;
> +	}
> +
> +	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
> +	timex_show("VERIFY", verify);
> +
> +	if (tc[i].ptr && *tc[i].ptr != *ptr) {
> +
> +		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
> +				tc[i].modes);
> +	}
> +
> +	if (TST_RET < 0) {
> +		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
> +				"error", tc[i].modes);
> +	}
> +
> +	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
> +}
> +
> +static void setup(void)
> +{
> +	size_t i;
> +
> +	hz = SAFE_SYSCONF(_SC_CLK_TCK);
> +
> +	/* fix high and low limits by dividing it per HZ value */
> +	for (i = 0; i < ARRAY_SIZE(tc); i++) {
> +		if (tc[i].modes == ADJ_TICK)
> +			tc[i].highlimit /= hz;
> +	}
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +}
> +
> +static void cleanup(void)
> +{
> +	saved.modes = ADJ_ALL;
> +
> +	/* restore clock resolution based on original status flag */
> +
> +	if (saved.status & STA_NANO)
> +		saved.modes |= ADJ_NANO;
> +	else
> +		saved.modes |= ADJ_MICRO;
> +
> +	/* restore original clock flags */
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +}
> +
> +static struct tst_test test = {
> +	.test = verify_clock_adjtime,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.tcnt = ARRAY_SIZE(tc),
> +	.needs_root = 1,

I wonder if we should set .restore_wallclock here, is the wallclock
significantly distorted by fiddling with adjtimex.

> +};
> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
> new file mode 100644
> index 000000000..05b4b0a18
> --- /dev/null
> +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
> @@ -0,0 +1,261 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Linaro Limited. All rights reserved.
> + * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
> + */
> +
> +/*
> + * clock_adjtime() syscall might have as execution path:
> + *
> + *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
> + *      - will behave exactly like adjtimex() system call.
> + *      - only one being tested here.
> + *
> + *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
> + *      - will trigger the PTP clock driver function "adjtime()"
> + *      - different implementations from one PTP clock to another
> + *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
> + *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
> + *
> + * so it is sane to check for the following errors:
> + *
> + *   EINVAL -  clock id being used does not exist
> + *
> + *   EFAULT - (struct timex *) does not point to valid memory
> + *
> + *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
> + *            (after 2.6.26, kernels normalize to the limit if outside range)
> + *
> + *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
> + *            (after 2.6.26, kernels normalize to the limit if outside range)
> + *
> + *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
> + *
> + *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
> + *
> + *   EINVAL - .status other than those listed bellow
> + *
> + * For ADJ_STATUS, consider the following flags:
> + *
> + *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
> + *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
> + *      rw  STA_PPSTIME - enable PPS time discipline
> + *      rw  STA_FLL - select freq-locked loop mode.
> + *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
> + *      rw  STA_DEL - del leap sec at last sec of UTC day (all days)
> + *      rw  STA_UNSYNC - clock unsynced
> + *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
> + *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
> + *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
> + *      ro  STA_PPSWANDER - PPS signal wander exceeded.
> + *      ro  STA_PPSERROR - PPS signal calibration error.
> + *      ro  STA_CLOKERR - clock HW fault.
> + *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
> + *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
> + *      ro  STA_CLK - clock source. unused.
> + */
> +
> +#include "config.h"
> +#include "tst_test.h"
> +#include "lapi/syscalls.h"
> +#include "lapi/posix_clocks.h"
> +#include "tst_timer.h"
> +#include "tst_safe_clocks.h"
> +#include <sys/timex.h>
> +#include <pwd.h>
> +
> +#include <stdio.h>
> +
> +static long hz;
> +static struct timex saved, ttxc;
> +
> +#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
> +	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
> +
> +#define MAX_CLOCKS 16

Can we put this into include/lapi/posix_clocks.h and use that in all
clock testcases?

Otherwise we will end up adjusting five different places once kernel
devs happen to add a few more clocks.

> +struct test_case {
> +	clockid_t clktype;
> +	unsigned int modes;
> +	long lowlimit;
> +	long highlimit;
> +	long *ptr;
> +	long delta;
> +	int exp_err;
> +	int droproot;
> +};
> +
> +struct test_case tc[] = {
> +	{
> +	 .clktype = MAX_CLOCKS,
> +	 .exp_err = EINVAL,
> +	},
> +	{
> +	 .clktype = MAX_CLOCKS + 1,
> +	 .exp_err = EINVAL,
> +	},
> +	{
> +	 .clktype = CLOCK_REALTIME,
> +	 .modes = ADJ_ALL,
> +	 .exp_err = EFAULT,
> +	},
> +	{
> +	 .clktype = CLOCK_REALTIME,
> +	 .modes = ADJ_TICK,
> +	 .lowlimit = 900000,
> +	 .ptr = &ttxc.tick,
> +	 .delta = 1,
> +	 .exp_err = EINVAL,
> +	},
> +	{
> +	 .clktype = CLOCK_REALTIME,
> +	 .modes = ADJ_TICK,
> +	 .highlimit = 1100000,
> +	 .ptr = &ttxc.tick,
> +	 .delta = 1,
> +	 .exp_err = EINVAL,
> +	},
> +	{
> +	 .clktype = CLOCK_REALTIME,
> +	 .modes = ADJ_ALL,
> +	 .exp_err = EPERM,
> +	 .droproot = 1,
> +	},
> +};
> +
> +/*
> + * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
> + */
> +static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
> +{
> +	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
> +}
> +
> +static void timex_show(char *given, struct timex txc)
> +{
> +	tst_res(TINFO,  "%s\n"
> +			"             mode: 0x%x\n"
> +			"           offset: %ld\n"
> +			"        frequency: %ld\n"
> +			"         maxerror: %ld\n"
> +			"         esterror: %ld\n"
> +			"           status: 0x%x\n"
> +			"    time_constant: %ld\n"
> +			"        precision: %ld\n"
> +			"        tolerance: %ld\n"
> +			"             tick: %ld\n"
> +			"         raw time: %d(s) %d(us)",
> +			given,
> +			txc.modes,
> +			txc.offset,
> +			txc.freq,
> +			txc.maxerror,
> +			txc.esterror,
> +			txc.status,
> +			txc.constant,
> +			txc.precision,
> +			txc.tolerance,
> +			txc.tick,
> +			(int)txc.time.tv_sec,
> +			(int)txc.time.tv_usec);
> +}

You should really put this into a header in the clock_adjtime directory
and include it in both test.

> +static void verify_clock_adjtime(unsigned int i)
> +{
> +	uid_t whoami = 0;
> +	struct timex *txcptr;
> +	struct passwd *nobody;
> +	static const char name[] = "nobody";
> +
> +	txcptr = &ttxc;
> +
> +	memset(txcptr, 0, sizeof(struct timex));
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
> +	timex_show("GET", *txcptr);
> +
> +	if (tc[i].droproot) {
> +		nobody = SAFE_GETPWNAM(name);
> +		whoami = nobody->pw_uid;
> +		SAFE_SETEUID(whoami);
> +	}
> +
> +	txcptr->modes = tc[i].modes;
> +
> +	if (tc[i].ptr) {
> +
> +		if (tc[i].lowlimit)
> +			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
> +
> +		if (tc[i].highlimit)
> +			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
> +	}
> +
> +	/* special case - if txcptr != NULL, SIGSEGV is throwed */
> +	if (tc[i].exp_err == EFAULT)
> +		txcptr = NULL;

Please use tst_get_bad_addr()

> +	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
> +	if (txcptr)
> +		timex_show("TEST", *txcptr);
> +
> +	if (TST_RET >= 0) {
> +		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
> +				"uid=%d)", tc[i].modes, whoami);
> +		return;
> +	}
> +
> +	if (tc[i].exp_err != TST_ERR) {
> +		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
> +				"failed with %d (mode=%x, uid=%d)",
> +				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
> +		return;
> +	}
> +
> +	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
> +			"uid=%d)", tc[i].modes, whoami);
> +
> +	if (tc[i].droproot)
> +		SAFE_SETEUID(0);
> +}
> +
> +static void setup(void)
> +{
> +	size_t i;
> +
> +	hz = SAFE_SYSCONF(_SC_CLK_TCK);
> +
> +	/* fix high and low limits by dividing it per HZ value */
> +	for (i = 0; i < ARRAY_SIZE(tc); i++) {
> +		if (tc[i].modes == ADJ_TICK) {
> +			tc[i].highlimit /= hz;
> +			tc[i].lowlimit /= hz;
> +		}
> +	}
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +}
> +
> +static void cleanup(void)
> +{
> +	saved.modes = ADJ_ALL;
> +
> +	/* restore clock resolution based on original status flag */
> +
> +	if (saved.status & STA_NANO)
> +		saved.modes |= ADJ_NANO;
> +	else
> +		saved.modes |= ADJ_MICRO;
> +
> +	/* restore original clock flags */
> +
> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +}
> +
> +static struct tst_test test = {
> +	.test = verify_clock_adjtime,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.tcnt = ARRAY_SIZE(tc),
> +	.needs_root = 1,
> +};
> -- 
> 2.20.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-13 16:32             ` Cyril Hrubis
@ 2019-03-15 11:07               ` Rafael David Tinoco
  2019-03-20 21:41               ` [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-15 11:07 UTC (permalink / raw)
  To: ltp

> On 13 Mar 2019, at 13:32, Cyril Hrubis <chrubis@suse.cz> wrote:
> 
> Hi!
> I finally had time to read the manual page for adjtime and look into
> these tests. They look more or less fine, the only problem here is that
> we merely scratch the surface here, i.e. most of the STA_* constants are
> not tested etc. I guess that with CLOCK_MONOTONIC_RAW we should be even
> able measure that the time has been adjusted, leap second inserted, etc.

adjtime() is only implemented by clock_realtime (time/posix-timers.c)
and clock_posix_dynamic (time/posix-clock.c). monotonic clocks don’t
implement clock_adj() (time/posix-timers.h) and would return EOPNOTSUPP
(time/posix-timers.c).

> However such tests would require quite a lot of effort. Even triggering
> leap second insertion/deletion requires fiddling with system time and
> sleeping till the kernel state machine does it job.

Yes =( … its not *trivial* but, definitely, could be done as test 03 in
a near future.

>> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
>> new file mode 100644
>> index 000000000..999865b96
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
>> @@ -0,0 +1,249 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2019 Linaro Limited. All rights reserved.
>> + * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
>> + */
>> +
>> +/*
>> + * clock_adjtime() syscall might have as execution path:
>> + *
>> + *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
>> + *      - will behave exactly like adjtimex() system call.
>> + *      - only one being tested here.
>> + *
>> + *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
>> + *      - will trigger the PTP clock driver function "adjtime()"
>> + *      - different implementations from one PTP clock to another
>> + *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
>> + *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
>> + *
>> + * so it is sane to check possible adjustments:
>> + *
>> + *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
>> + *                       (-512000 < offset < 512000)
>> + *    - ADJ_FREQUENCY  - system clock frequency offset
>> + *    - ADJ_MAXERROR   - maximum error (usec)
>> + *    - ADJ_ESTERROR   - estimated time error in us
>> + *    - ADJ_STATUS     - clock command/status of ntp implementation
>> + *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
>> + *    - ADJ_TICK       - us between clock ticks
>> + *                       (>= 900000/HZ, <= 1100000/HZ)
>> + *
>> + * and also the standalone ones (using .offset variable):
>> + *
>> + *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
>> + *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
>> + *
>> + * For ADJ_STATUS, consider the following flags:
>> + *
>> + *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
>> + *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
>> + *      rw  STA_PPSTIME - enable PPS time discipline
>> + *      rw  STA_FLL - select freq-locked loop mode.
>> + *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
>> + *      rw  STA_DEL - del leap sec at last sec of UTC day (all days)
>> + *      rw  STA_UNSYNC - clock unsynced
>> + *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
>> + *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
>> + *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
>> + *      ro  STA_PPSWANDER - PPS signal wander exceeded.
>> + *      ro  STA_PPSERROR - PPS signal calibration error.
>> + *      ro  STA_CLOKERR - clock HW fault.
>> + *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
>> + *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
>> + *      ro  STA_CLK - clock source. unused.
>> + */
>> +
>> +#include "config.h"
>> +#include "tst_test.h"
>> +#include "lapi/syscalls.h"
>> +#include "lapi/posix_clocks.h"
>> +#include "tst_timer.h"
>> +#include "tst_safe_clocks.h"
>> +#include <sys/timex.h>
>> +
>> +static long hz;
>> +static struct timex saved, ttxc;
>> +
>> +#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
>> +	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
>> +
>> +struct test_case {
>> +	unsigned int modes;
>> +	long highlimit;
>> +	long *ptr;
>> +	long delta;
>> +};
>> +
>> +struct test_case tc[] = {
>> +	{
>> +	 .modes = ADJ_OFFSET_SINGLESHOT,
>> +	},
>> +	{
>> +	 .modes = ADJ_OFFSET_SS_READ,
>> +	},
>> +	{
>> +	 .modes = ADJ_ALL,
>> +	},
>> +	{
>> +	 .modes = ADJ_OFFSET,
>> +	 .highlimit = 512000,
>> +	 .ptr = &ttxc.offset,
>> +	 .delta = 10000,
>> +	},
> 
> I wonder what we should do with STA_NANO vs STA_MICRO if a ntp daemon
> set STA_NANO this limit would be three orders of magnitude off, maybe we
> should check for this in the setup as well.

Nice catch!

> Also manual states that the limit is -0.5, +0.5 range, we should really
> set the limit to 500000 then, then we can just clamp the value instead
> of decreasing by 2 * delta (why do we do even do that) donw in the test
> function.

Okay.

> 
>> +	{
>> +	 .modes = ADJ_FREQUENCY,
>> +	 .ptr = &ttxc.freq,
>> +	 .delta = 100,
>> +	},
>> +	{
>> +	 .modes = ADJ_MAXERROR,
>> +	 .ptr = &ttxc.maxerror,
>> +	 .delta = 100,
>> +	},
>> +	{
>> +	 .modes = ADJ_ESTERROR,
>> +	 .ptr = &ttxc.esterror,
>> +	 .delta = 100,
>> +	},
>> +	{
>> +	 .modes = ADJ_TIMECONST,
>> +	 .ptr = &ttxc.constant,
>> +	 .delta = 1,
>> +	},
>> +	{
>> +	 .modes = ADJ_TICK,
>> +	 .highlimit = 1100000,
>> +	 .ptr = &ttxc.tick,
>> +	 .delta = 1000,
>> +	},
>> +};
>> +
>> +/*
>> + * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
>> + */
>> +static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
>> +{
>> +	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
>> +}
>> +
>> +static void timex_show(char *given, struct timex txc)
>> +{
>> +	tst_res(TINFO,  "%s\n"
>> +			"             mode: %d\n"
>> +			"           offset: %ld\n"
>> +			"        frequency: %ld\n"
>> +			"         maxerror: %ld\n"
>> +			"         esterror: %ld\n"
>> +			"           status: %d (0x%x)\n"
>> +			"    time_constant: %ld\n"
>> +			"        precision: %ld\n"
>> +			"        tolerance: %ld\n"
>> +			"             tick: %ld\n"
>> +			"         raw time: %d(s) %d(us)",
>> +			given,
>> +			txc.modes,
>> +			txc.offset,
>> +			txc.freq,
>> +			txc.maxerror,
>> +			txc.esterror,
>> +			txc.status,
>> +			txc.status,
>> +			txc.constant,
>> +			txc.precision,
>> +			txc.tolerance,
>> +			txc.tick,
>> +			(int)txc.time.tv_sec,
>> +			(int)txc.time.tv_usec);
>> +}
>> +
>> +static void verify_clock_adjtime(unsigned int i)
>> +{
>> +	long ptroff, *ptr = NULL;
>> +	struct timex verify;
>> +
>> +	memset(&ttxc, 0, sizeof(struct timex));
>> +	memset(&verify, 0, sizeof(struct timex));
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
>> +	timex_show("GET", ttxc);
>> +
>> +	ttxc.modes = tc[i].modes;
>> +
>> +	if (tc[i].ptr && tc[i].delta) {
>> +
>> +		*tc[i].ptr += tc[i].delta;
>> +
>> +		/* fix limits, if existent, so no errors occur */
>> +
>> +		if (tc[i].highlimit) {
>> +			if (*tc[i].ptr >= tc[i].highlimit)
>> +				*tc[i].ptr -= (2 * tc[i].delta);
>> +		}
> 
> Here if we had the highlimit correct we can just do:
> 
> 
> 		if (tc[i].highlimit) {
> 			if (*tc[i].ptr > tc[i].highlimit)
> 				*tc[i].ptr = tc[i].highlimit;
> 		}
> 
> Or is there a reason why this cannot work?

Nope, having subtracting 2 * delta is a leftover from previous idea that
“kept working” I guess, will review.

>> +	}
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
>> +	timex_show("SET", ttxc);
>> +
>> +	if (tc[i].ptr) {
>> +
>> +		/* adjtimex field being tested so we can verify later */
>> +
>> +		ptroff = (long) tc[i].ptr - (long) &ttxc;
>> +		ptr = (void *) &verify + ptroff;
>> +	}
>> +
>> +	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
>> +	timex_show("VERIFY", verify);
>> +
>> +	if (tc[i].ptr && *tc[i].ptr != *ptr) {
>> +
>> +		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
>> +				tc[i].modes);
>> +	}
>> +
>> +	if (TST_RET < 0) {
>> +		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
>> +				"error", tc[i].modes);
>> +	}
>> +
>> +	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
>> +}
>> +
>> +static void setup(void)
>> +{
>> +	size_t i;
>> +
>> +	hz = SAFE_SYSCONF(_SC_CLK_TCK);
>> +
>> +	/* fix high and low limits by dividing it per HZ value */
>> +	for (i = 0; i < ARRAY_SIZE(tc); i++) {
>> +		if (tc[i].modes == ADJ_TICK)
>> +			tc[i].highlimit /= hz;
>> +	}
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	saved.modes = ADJ_ALL;
>> +
>> +	/* restore clock resolution based on original status flag */
>> +
>> +	if (saved.status & STA_NANO)
>> +		saved.modes |= ADJ_NANO;
>> +	else
>> +		saved.modes |= ADJ_MICRO;
>> +
>> +	/* restore original clock flags */
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
>> +}
>> +
>> +static struct tst_test test = {
>> +	.test = verify_clock_adjtime,
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.tcnt = ARRAY_SIZE(tc),
>> +	.needs_root = 1,
> 
> I wonder if we should set .restore_wallclock here, is the wallclock
> significantly distorted by fiddling with adjtimex.

I was also in doubt about this, if any deviation caused by playing with
clock will jitter more than the monotonic clock resolution coming from
the .restore_wallclock logic. I guess its safer to “guarantee” good
clock status by using it, since its acceptable for other tests.

>> +};
>> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
>> new file mode 100644
>> index 000000000..05b4b0a18
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
>> @@ -0,0 +1,261 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2019 Linaro Limited. All rights reserved.
>> + * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
>> + */
>> +
>> +/*
>> + * clock_adjtime() syscall might have as execution path:
>> + *
>> + *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
>> + *      - will behave exactly like adjtimex() system call.
>> + *      - only one being tested here.
>> + *
>> + *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
>> + *      - will trigger the PTP clock driver function "adjtime()"
>> + *      - different implementations from one PTP clock to another
>> + *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
>> + *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
>> + *
>> + * so it is sane to check for the following errors:
>> + *
>> + *   EINVAL -  clock id being used does not exist
>> + *
>> + *   EFAULT - (struct timex *) does not point to valid memory
>> + *
>> + *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
>> + *            (after 2.6.26, kernels normalize to the limit if outside range)
>> + *
>> + *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
>> + *            (after 2.6.26, kernels normalize to the limit if outside range)
>> + *
>> + *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
>> + *
>> + *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
>> + *
>> + *   EINVAL - .status other than those listed bellow
>> + *
>> + * For ADJ_STATUS, consider the following flags:
>> + *
>> + *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
>> + *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
>> + *      rw  STA_PPSTIME - enable PPS time discipline
>> + *      rw  STA_FLL - select freq-locked loop mode.
>> + *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
>> + *      rw  STA_DEL - del leap sec at last sec of UTC day (all days)
>> + *      rw  STA_UNSYNC - clock unsynced
>> + *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
>> + *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
>> + *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
>> + *      ro  STA_PPSWANDER - PPS signal wander exceeded.
>> + *      ro  STA_PPSERROR - PPS signal calibration error.
>> + *      ro  STA_CLOKERR - clock HW fault.
>> + *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
>> + *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
>> + *      ro  STA_CLK - clock source. unused.
>> + */
>> +
>> +#include "config.h"
>> +#include "tst_test.h"
>> +#include "lapi/syscalls.h"
>> +#include "lapi/posix_clocks.h"
>> +#include "tst_timer.h"
>> +#include "tst_safe_clocks.h"
>> +#include <sys/timex.h>
>> +#include <pwd.h>
>> +
>> +#include <stdio.h>
>> +
>> +static long hz;
>> +static struct timex saved, ttxc;
>> +
>> +#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
>> +	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
>> +
>> +#define MAX_CLOCKS 16
> 
> Can we put this into include/lapi/posix_clocks.h and use that in all
> clock testcases?
> 
> Otherwise we will end up adjusting five different places once kernel
> devs happen to add a few more clocks.

Yep!

> 
>> +struct test_case {
>> +	clockid_t clktype;
>> +	unsigned int modes;
>> +	long lowlimit;
>> +	long highlimit;
>> +	long *ptr;
>> +	long delta;
>> +	int exp_err;
>> +	int droproot;
>> +};
>> +
>> +struct test_case tc[] = {
>> +	{
>> +	 .clktype = MAX_CLOCKS,
>> +	 .exp_err = EINVAL,
>> +	},
>> +	{
>> +	 .clktype = MAX_CLOCKS + 1,
>> +	 .exp_err = EINVAL,
>> +	},
>> +	{
>> +	 .clktype = CLOCK_REALTIME,
>> +	 .modes = ADJ_ALL,
>> +	 .exp_err = EFAULT,
>> +	},
>> +	{
>> +	 .clktype = CLOCK_REALTIME,
>> +	 .modes = ADJ_TICK,
>> +	 .lowlimit = 900000,
>> +	 .ptr = &ttxc.tick,
>> +	 .delta = 1,
>> +	 .exp_err = EINVAL,
>> +	},
>> +	{
>> +	 .clktype = CLOCK_REALTIME,
>> +	 .modes = ADJ_TICK,
>> +	 .highlimit = 1100000,
>> +	 .ptr = &ttxc.tick,
>> +	 .delta = 1,
>> +	 .exp_err = EINVAL,
>> +	},
>> +	{
>> +	 .clktype = CLOCK_REALTIME,
>> +	 .modes = ADJ_ALL,
>> +	 .exp_err = EPERM,
>> +	 .droproot = 1,
>> +	},
>> +};
>> +
>> +/*
>> + * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
>> + */
>> +static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
>> +{
>> +	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
>> +}
>> +
>> +static void timex_show(char *given, struct timex txc)
>> +{
>> +	tst_res(TINFO,  "%s\n"
>> +			"             mode: 0x%x\n"
>> +			"           offset: %ld\n"
>> +			"        frequency: %ld\n"
>> +			"         maxerror: %ld\n"
>> +			"         esterror: %ld\n"
>> +			"           status: 0x%x\n"
>> +			"    time_constant: %ld\n"
>> +			"        precision: %ld\n"
>> +			"        tolerance: %ld\n"
>> +			"             tick: %ld\n"
>> +			"         raw time: %d(s) %d(us)",
>> +			given,
>> +			txc.modes,
>> +			txc.offset,
>> +			txc.freq,
>> +			txc.maxerror,
>> +			txc.esterror,
>> +			txc.status,
>> +			txc.constant,
>> +			txc.precision,
>> +			txc.tolerance,
>> +			txc.tick,
>> +			(int)txc.time.tv_sec,
>> +			(int)txc.time.tv_usec);
>> +}
> 
> You should really put this into a header in the clock_adjtime directory
> and include it in both test.

Yep!

> 
>> +static void verify_clock_adjtime(unsigned int i)
>> +{
>> +	uid_t whoami = 0;
>> +	struct timex *txcptr;
>> +	struct passwd *nobody;
>> +	static const char name[] = "nobody";
>> +
>> +	txcptr = &ttxc;
>> +
>> +	memset(txcptr, 0, sizeof(struct timex));
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
>> +	timex_show("GET", *txcptr);
>> +
>> +	if (tc[i].droproot) {
>> +		nobody = SAFE_GETPWNAM(name);
>> +		whoami = nobody->pw_uid;
>> +		SAFE_SETEUID(whoami);
>> +	}
>> +
>> +	txcptr->modes = tc[i].modes;
>> +
>> +	if (tc[i].ptr) {
>> +
>> +		if (tc[i].lowlimit)
>> +			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
>> +
>> +		if (tc[i].highlimit)
>> +			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
>> +	}
>> +
>> +	/* special case - if txcptr != NULL, SIGSEGV is throwed */
>> +	if (tc[i].exp_err == EFAULT)
>> +		txcptr = NULL;
> 
> Please use tst_get_bad_addr()

I used it and had problems, will re-check.

> 
>> +	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
>> +	if (txcptr)
>> +		timex_show("TEST", *txcptr);
>> +
>> +	if (TST_RET >= 0) {
>> +		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
>> +				"uid=%d)", tc[i].modes, whoami);
>> +		return;
>> +	}
>> +
>> +	if (tc[i].exp_err != TST_ERR) {
>> +		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
>> +				"failed with %d (mode=%x, uid=%d)",
>> +				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
>> +		return;
>> +	}
>> +
>> +	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
>> +			"uid=%d)", tc[i].modes, whoami);
>> +
>> +	if (tc[i].droproot)
>> +		SAFE_SETEUID(0);
>> +}
>> +
>> +static void setup(void)
>> +{
>> +	size_t i;
>> +
>> +	hz = SAFE_SYSCONF(_SC_CLK_TCK);
>> +
>> +	/* fix high and low limits by dividing it per HZ value */
>> +	for (i = 0; i < ARRAY_SIZE(tc); i++) {
>> +		if (tc[i].modes == ADJ_TICK) {
>> +			tc[i].highlimit /= hz;
>> +			tc[i].lowlimit /= hz;
>> +		}
>> +	}
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	saved.modes = ADJ_ALL;
>> +
>> +	/* restore clock resolution based on original status flag */
>> +
>> +	if (saved.status & STA_NANO)
>> +		saved.modes |= ADJ_NANO;
>> +	else
>> +		saved.modes |= ADJ_MICRO;
>> +
>> +	/* restore original clock flags */
>> +
>> +	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
>> +}
>> +
>> +static struct tst_test test = {
>> +	.test = verify_clock_adjtime,
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.tcnt = ARRAY_SIZE(tc),
>> +	.needs_root = 1,
>> +};
>> -- 
>> 2.20.1
>> 
>> 
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp
> 
> -- 
> Cyril Hrubis
> chrubis@suse.cz

Thanks, will post a v2.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-03-13 16:32             ` Cyril Hrubis
  2019-03-15 11:07               ` Rafael David Tinoco
@ 2019-03-20 21:41               ` Rafael David Tinoco
  2019-03-20 21:41                 ` [LTP] [PATCH v2 2/3] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
  2019-03-20 21:41                 ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  1 sibling, 2 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-20 21:41 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index d5cd83394..a952be4bf 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,7 +6,9 @@
  */
 
 #include <time.h>
+#include <sys/timex.h>
 #include "tst_test.h"
+#include "lapi/syscalls.h"
 #include "lapi/posix_clocks.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
@@ -44,6 +46,18 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline void safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+
+	if (rval != 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed", file, lineno);
+}
+
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -52,3 +66,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 2/3] lapi/posix_clocks.h: add MAX_CLOCKS definition
  2019-03-20 21:41               ` [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-03-20 21:41                 ` Rafael David Tinoco
  2019-03-20 21:41                 ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-20 21:41 UTC (permalink / raw)
  To: ltp

Used by clock_XXXtime() tests, defining MAX_CLOCKS in common header.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                               | 2 ++
 testcases/kernel/syscalls/clock_gettime/clock_gettime02.c | 2 --
 testcases/kernel/syscalls/clock_settime/clock_settime02.c | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 0d1f0e99c..4914479ac 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -9,6 +9,8 @@
 #ifndef POSIX_CLOCKS_H__
 #define POSIX_CLOCKS_H__
 
+#define MAX_CLOCKS 16
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
index 2a29a71e6..b4bc6e2d5 100644
--- a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
+++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
@@ -24,8 +24,6 @@
 #include "tst_timer.h"
 #include "tst_safe_clocks.h"
 
-#define MAX_CLOCKS 16
-
 struct test_case {
 	clockid_t clktype;
 	int exp_err;
diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime02.c b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
index 8db417b6b..e16e9061a 100644
--- a/testcases/kernel/syscalls/clock_settime/clock_settime02.c
+++ b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
@@ -16,7 +16,6 @@
 
 #define DELTA_SEC 10
 #define NSEC_PER_SEC (1000000000L)
-#define MAX_CLOCKS 16
 
 struct test_case {
 	clockid_t type;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-20 21:41               ` [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-03-20 21:41                 ` [LTP] [PATCH v2 2/3] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
@ 2019-03-20 21:41                 ` Rafael David Tinoco
  2019-03-20 21:48                   ` Rafael David Tinoco
  2019-03-21 13:54                   ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Cyril Hrubis
  1 sibling, 2 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-20 21:41 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

 1) a regular POSIX clock (only REALTIME clock implements adjtime())
    - will behave exactly like adjtimex() system call.
    - only one being tested here.

 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
    - will trigger the PTP clock driver function "adjtime()"
    - different implementations from one PTP clock to another
    - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
    - no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                   |   4 +
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime.h    |  57 +++++
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 216 +++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 218 ++++++++++++++++++
 7 files changed, 510 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 4914479ac..b1f7a7c55 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -11,6 +11,10 @@
 
 #define MAX_CLOCKS 16
 
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR |  \
+		 ADJ_ESTERROR | ADJ_STATUS | ADJ_TIMECONST |  \
+		 ADJ_TICK)
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/runtest/syscalls b/runtest/syscalls
index a13d51918..817f3576b 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
new file mode 100644
index 000000000..34b97fdfa
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include <time.h>
+#include <pwd.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+
+static int sys_clock_adjtime(clockid_t, struct timex *);
+static void timex_show(char *, struct timex);
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..48cfbe6c5
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 500000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr = NULL;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr = tc[i].highlimit;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	/* save original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+
+		/* fix high and low limits by dividing it per HZ value */
+
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+
+		/* fix usec as being test default resolution */
+
+		if (saved.modes & ADJ_NANO) {
+			if (tc[i].modes == ADJ_OFFSET) {
+				tc[i].highlimit *= 1000;
+				tc[i].delta *= 1000;
+			}
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..de9bae860
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+static void cleanup(void);
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami = 0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	static const char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/*
+	 * special case: EFAULT for NULL pointers
+	 * txcptr = tst_get_bad_addr() -> SIGSEGV is thrown (and not EFAULT)
+	 */
+
+	if (tc[i].exp_err == EFAULT)
+		txcptr = NULL;
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	if (tc[i].exp_err != TST_ERR) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+		return;
+	}
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-20 21:41                 ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-03-20 21:48                   ` Rafael David Tinoco
  2019-03-21 13:42                     ` Cyril Hrubis
  2019-03-21 13:54                   ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Cyril Hrubis
  1 sibling, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-20 21:48 UTC (permalink / raw)
  To: ltp

> On 20 Mar 2019, at 18:41, Rafael David Tinoco <rafael.tinoco@linaro.org> wrote:
> 
> +	/*
> +	 * special case: EFAULT for NULL pointers
> +	 * txcptr = tst_get_bad_addr() -> SIGSEGV is thrown (and not EFAULT)
> +	 */
> +
> +	if (tc[i].exp_err == EFAULT)
> +		txcptr = NULL;

Cyril,

clock_adjtime() returns an EFAULT in case copy_from_user() returns
errors.

Thing is that, using tst_get_bad_addr(), and having a page with no
permissions, before getting an error from copy_from_user() and returning
- thus getting EFAULT back - we get a SIGSEGV from _copy_from_user()
itself, because it tries to sanitize given address, with memset(0),
before returning to userland (to avoid leaks of some sort ?).

With this, the EFAULT is only got when using NULL pointers, and not a
*bad* pointer… So, right now, I can’tuse tst_get_bad_addr() like you
suggested. Should I remove this test and send a v3 ?

Thanks for reviewing all this.

Best Regards

Rafael D. Tinoco

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-20 21:48                   ` Rafael David Tinoco
@ 2019-03-21 13:42                     ` Cyril Hrubis
  2019-03-21 13:57                       ` Rafael David Tinoco
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-21 13:42 UTC (permalink / raw)
  To: ltp

Hi!
> > +	/*
> > +	 * special case: EFAULT for NULL pointers
> > +	 * txcptr = tst_get_bad_addr() -> SIGSEGV is thrown (and not EFAULT)
> > +	 */
> > +
> > +	if (tc[i].exp_err == EFAULT)
> > +		txcptr = NULL;
> 
> Cyril,
> 
> clock_adjtime() returns an EFAULT in case copy_from_user() returns
> errors.
> 
> Thing is that, using tst_get_bad_addr(), and having a page with no
> permissions, before getting an error from copy_from_user() and returning
> - thus getting EFAULT back - we get a SIGSEGV from _copy_from_user()
> itself, because it tries to sanitize given address, with memset(0),
> before returning to userland (to avoid leaks of some sort ?).
> 
> With this, the EFAULT is only got when using NULL pointers, and not a
> *bad* pointer??? So, right now, I can???tuse tst_get_bad_addr() like you
> suggested. Should I remove this test and send a v3 ?

Hmm that's strange, memseting the structure does not make much sense.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-20 21:41                 ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2019-03-20 21:48                   ` Rafael David Tinoco
@ 2019-03-21 13:54                   ` Cyril Hrubis
  2019-03-21 14:00                     ` Rafael David Tinoco
  1 sibling, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-21 13:54 UTC (permalink / raw)
  To: ltp

Hi!
This test fails for me and clock_adjtime() returns 5 (TIME_ERROR) for me.

Looks like the SAFE_ADJTIME() should fail only on rval < 0 and return the rval
too so that we can possibly make use of the return value, the test passes for
me with:

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index a952be4bf..f7776a548 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -46,16 +46,18 @@ static inline void safe_clock_settime(const char *file, const int lineno,
                        "%s:%d clock_gettime() failed", file, lineno);
 }
 
-static inline void safe_clock_adjtime(const char *file, const int lineno,
+static inline int safe_clock_adjtime(const char *file, const int lineno,
        clockid_t clk_id, struct timex *txc)
 {
        int rval;
 
        rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
 
-       if (rval != 0)
+       if (rval < 0)
                tst_brk(TBROK | TERRNO,
-                       "%s:%d clock_adjtime() failed", file, lineno);
+                       "%s:%d clock_adjtime() failed %i", file, lineno, rval);
+
+       return rval;
 }


Also we should restore the adjtimex only if we actually managed to save it,
with something as:

diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
index 48cfbe6c5..6eb823387 100644
--- a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -58,6 +58,7 @@
 
 static long hz;
 static struct timex saved, ttxc;
+static int clock_saved;
 
 struct test_case {
        unsigned int modes;
@@ -165,10 +166,13 @@ static void verify_clock_adjtime(unsigned int i)
 static void setup(void)
 {
        size_t i;
+       int rval;
 
        /* save original clock flags */
 
-       SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+       rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+       clock_saved = 1;
+       tst_res(TINFO, "clock_adjtime() = %i", rval);
 
        hz = SAFE_SYSCONF(_SC_CLK_TCK);
 
@@ -203,7 +207,8 @@ static void cleanup(void)
 
        /* restore original clock flags */
 
-       SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+       if (clock_saved)
+               SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
 }
 
 static struct tst_test test = {


-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 13:42                     ` Cyril Hrubis
@ 2019-03-21 13:57                       ` Rafael David Tinoco
  2019-03-21 14:05                         ` Cyril Hrubis
  0 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 13:57 UTC (permalink / raw)
  To: ltp

> On 21 Mar 2019, at 10:42, Cyril Hrubis <chrubis@suse.cz> wrote:
> 
> Hi!
>>> +	/*
>>> +	 * special case: EFAULT for NULL pointers
>>> +	 * txcptr = tst_get_bad_addr() -> SIGSEGV is thrown (and not EFAULT)
>>> +	 */
>>> +
>>> +	if (tc[i].exp_err == EFAULT)
>>> +		txcptr = NULL;
>> 
>> Cyril,
>> 
>> clock_adjtime() returns an EFAULT in case copy_from_user() returns
>> errors.
>> 
>> Thing is that, using tst_get_bad_addr(), and having a page with no
>> permissions, before getting an error from copy_from_user() and returning
>> - thus getting EFAULT back - we get a SIGSEGV from _copy_from_user()
>> itself, because it tries to sanitize given address, with memset(0),
>> before returning to userland (to avoid leaks of some sort ?).
>> 
>> With this, the EFAULT is only got when using NULL pointers, and not a
>> *bad* pointer??? So, right now, I can???tuse tst_get_bad_addr() like you
>> suggested. Should I remove this test and send a v3 ?
> 
> Hmm that's strange, memseting the structure does not make much sense.

checking lib/usercopy.c -> _copy_from_user(), memset() is only done in
kernel buffer if there was an error in raw_copy_from_user(), so.. you’re
right. Since mmap’ed buffer has PROT_NONE, I guess the SIGSEGV is thrown
during “raw_copy_from_user()” when referencing the user page with no
permissions. This might not happen when a NULL is passed, making adjtime
to ret EFAULT. Anyway, can’t use tst_get_bad_addr() as it seems...

> -- 
> Cyril Hrubis
> chrubis@suse.cz



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 13:54                   ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Cyril Hrubis
@ 2019-03-21 14:00                     ` Rafael David Tinoco
  2019-03-21 14:06                       ` Cyril Hrubis
  0 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 14:00 UTC (permalink / raw)
  To: ltp

> On 21 Mar 2019, at 10:54, Cyril Hrubis <chrubis@suse.cz> wrote:
> 
> Hi!
> This test fails for me and clock_adjtime() returns 5 (TIME_ERROR) for me.
> 
> Looks like the SAFE_ADJTIME() should fail only on rval < 0 and return the rval
> too so that we can possibly make use of the return value, the test passes for
> me with:
> 
> diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
> index a952be4bf..f7776a548 100644
> --- a/include/tst_safe_clocks.h
> +++ b/include/tst_safe_clocks.h
> @@ -46,16 +46,18 @@ static inline void safe_clock_settime(const char *file, const int lineno,
>                        "%s:%d clock_gettime() failed", file, lineno);
> }
> 
> -static inline void safe_clock_adjtime(const char *file, const int lineno,
> +static inline int safe_clock_adjtime(const char *file, const int lineno,
>        clockid_t clk_id, struct timex *txc)
> {
>        int rval;
> 
>        rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
> 
> -       if (rval != 0)
> +       if (rval < 0)
>                tst_brk(TBROK | TERRNO,
> -                       "%s:%d clock_adjtime() failed", file, lineno);
> +                       "%s:%d clock_adjtime() failed %i", file, lineno, rval);
> +
> +       return rval;
> }
> 
> 
> Also we should restore the adjtimex only if we actually managed to save it,
> with something as:
> 
> diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> index 48cfbe6c5..6eb823387 100644
> --- a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
> @@ -58,6 +58,7 @@
> 
> static long hz;
> static struct timex saved, ttxc;
> +static int clock_saved;
> 
> struct test_case {
>        unsigned int modes;
> @@ -165,10 +166,13 @@ static void verify_clock_adjtime(unsigned int i)
> static void setup(void)
> {
>        size_t i;
> +       int rval;
> 
>        /* save original clock flags */
> 
> -       SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +       rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +       clock_saved = 1;
> +       tst_res(TINFO, "clock_adjtime() = %i", rval);
> 
>        hz = SAFE_SYSCONF(_SC_CLK_TCK);
> 
> @@ -203,7 +207,8 @@ static void cleanup(void)
> 
>        /* restore original clock flags */
> 
> -       SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +       if (clock_saved)
> +               SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> }
> 
> static struct tst_test test = {

Alright, will send a v3, sorry about that.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 13:57                       ` Rafael David Tinoco
@ 2019-03-21 14:05                         ` Cyril Hrubis
  2019-03-21 14:10                           ` Cyril Hrubis
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-21 14:05 UTC (permalink / raw)
  To: ltp

Hi!
> > Hmm that's strange, memseting the structure does not make much sense.
> 
> checking lib/usercopy.c -> _copy_from_user(), memset() is only done in
> kernel buffer if there was an error in raw_copy_from_user(), so.. you???re
> right. Since mmap???ed buffer has PROT_NONE, I guess the SIGSEGV is thrown
> during ???raw_copy_from_user()??? when referencing the user page with no
> permissions. This might not happen when a NULL is passed, making adjtime
> to ret EFAULT. Anyway, can???t use tst_get_bad_addr() as it seems...

Looking at strace of the test we manage to get -1 and EFAULT followed by
the signal, which is strange. I do wonder why this is the only syscall
that behaves that way.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 14:00                     ` Rafael David Tinoco
@ 2019-03-21 14:06                       ` Cyril Hrubis
  0 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-21 14:06 UTC (permalink / raw)
  To: ltp

Hi!
> Alright, will send a v3, sorry about that.

No problem :-) I'm happy to help.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 14:05                         ` Cyril Hrubis
@ 2019-03-21 14:10                           ` Cyril Hrubis
  2019-03-21 14:17                             ` Rafael David Tinoco
  2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-21 14:10 UTC (permalink / raw)
  To: ltp

Hi!
> > checking lib/usercopy.c -> _copy_from_user(), memset() is only done in
> > kernel buffer if there was an error in raw_copy_from_user(), so.. you???re
> > right. Since mmap???ed buffer has PROT_NONE, I guess the SIGSEGV is thrown
> > during ???raw_copy_from_user()??? when referencing the user page with no
> > permissions. This might not happen when a NULL is passed, making adjtime
> > to ret EFAULT. Anyway, can???t use tst_get_bad_addr() as it seems...
> 
> Looking at strace of the test we manage to get -1 and EFAULT followed by
> the signal, which is strange. I do wonder why this is the only syscall
> that behaves that way.

Found the bug :-), the kernel is not the problem but rather the lines:

	if (txcptr)
		timex_show("TEST", *txcptr);


You have to change these to something as:

	if (tcxptr != bad_addr)
		timex_show("TEST", *txcptr);

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 14:10                           ` Cyril Hrubis
@ 2019-03-21 14:17                             ` Rafael David Tinoco
  2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 14:17 UTC (permalink / raw)
  To: ltp

> On 21 Mar 2019, at 11:10, Cyril Hrubis <chrubis@suse.cz> wrote:
> 
> Hi!
>>> checking lib/usercopy.c -> _copy_from_user(), memset() is only done in
>>> kernel buffer if there was an error in raw_copy_from_user(), so.. you???re
>>> right. Since mmap???ed buffer has PROT_NONE, I guess the SIGSEGV is thrown
>>> during ???raw_copy_from_user()??? when referencing the user page with no
>>> permissions. This might not happen when a NULL is passed, making adjtime
>>> to ret EFAULT. Anyway, can???t use tst_get_bad_addr() as it seems...
>> 
>> Looking at strace of the test we manage to get -1 and EFAULT followed by
>> the signal, which is strange. I do wonder why this is the only syscall
>> that behaves that way.
> 
> Found the bug :-), the kernel is not the problem but rather the lines:
> 
> 	if (txcptr)
> 		timex_show("TEST", *txcptr);
> 
> 
> You have to change these to something as:
> 
> 	if (tcxptr != bad_addr)
> 		timex_show("TEST", *txcptr);

/me blushes for not having opened it in gdb :o)

tks

> 
> -- 
> Cyril Hrubis
> chrubis@suse.cz



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-03-21 14:10                           ` Cyril Hrubis
  2019-03-21 14:17                             ` Rafael David Tinoco
@ 2019-03-21 20:27                             ` Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
                                                 ` (2 more replies)
  1 sibling, 3 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 20:27 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index d5cd83394..596db4099 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,7 +6,9 @@
  */
 
 #include <time.h>
+#include <sys/timex.h>
 #include "tst_test.h"
+#include "lapi/syscalls.h"
 #include "lapi/posix_clocks.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
@@ -44,6 +46,19 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline int safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+	if (rval < 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed %i", file, lineno, rval);
+
+	return rval;
+}
+
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -52,3 +67,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 2/4] lib: Add include guard to tst_safe_clocks.h
  2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-03-21 20:27                               ` Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 20:27 UTC (permalink / raw)
  To: ltp

When adding a common header to my tests I missed this include guard when
accidentally including tst_safe_clocks.h from .c and .h files. Since
other tst_safe_*.h files have guards I thought it would be good to add
to this one as well.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index 596db4099..34ed953b4 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -5,6 +5,9 @@
  * Email : code@zilogic.com
  */
 
+#ifndef TST_SAFE_CLOCKS_H__
+#define TST_SAFE_CLOCKS_H__
+
 #include <time.h>
 #include <sys/timex.h>
 #include "tst_test.h"
@@ -70,3 +73,5 @@ static inline int safe_clock_adjtime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_ADJTIME(clk_id, txc)\
 	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
+
+#endif /* SAFE_CLOCKS_H__ */
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition
  2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
@ 2019-03-21 20:27                               ` Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 20:27 UTC (permalink / raw)
  To: ltp

Used by clock_XXXtime() tests, defining MAX_CLOCKS in common header.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                               | 2 ++
 testcases/kernel/syscalls/clock_gettime/clock_gettime02.c | 2 --
 testcases/kernel/syscalls/clock_settime/clock_settime02.c | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 0d1f0e99c..4914479ac 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -9,6 +9,8 @@
 #ifndef POSIX_CLOCKS_H__
 #define POSIX_CLOCKS_H__
 
+#define MAX_CLOCKS 16
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
index 2a29a71e6..b4bc6e2d5 100644
--- a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
+++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
@@ -24,8 +24,6 @@
 #include "tst_timer.h"
 #include "tst_safe_clocks.h"
 
-#define MAX_CLOCKS 16
-
 struct test_case {
 	clockid_t clktype;
 	int exp_err;
diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime02.c b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
index 8db417b6b..e16e9061a 100644
--- a/testcases/kernel/syscalls/clock_settime/clock_settime02.c
+++ b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
@@ -16,7 +16,6 @@
 
 #define DELTA_SEC 10
 #define NSEC_PER_SEC (1000000000L)
-#define MAX_CLOCKS 16
 
 struct test_case {
 	clockid_t type;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
  2019-03-21 20:27                               ` [LTP] [PATCH v3 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
@ 2019-03-21 20:27                               ` Rafael David Tinoco
  2019-03-21 20:31                                 ` Rafael David Tinoco
  2 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 20:27 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

 1) a regular POSIX clock (only REALTIME clock implements adjtime())
    - will behave exactly like adjtimex() system call.
    - only one being tested here.

 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
    - will trigger the PTP clock driver function "adjtime()"
    - different implementations from one PTP clock to another
    - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
    - no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                   |   4 +
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime.h    |  57 +++++
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 220 ++++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 220 ++++++++++++++++++
 7 files changed, 516 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 4914479ac..b1f7a7c55 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -11,6 +11,10 @@
 
 #define MAX_CLOCKS 16
 
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR |  \
+		 ADJ_ESTERROR | ADJ_STATUS | ADJ_TIMECONST |  \
+		 ADJ_TICK)
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/runtest/syscalls b/runtest/syscalls
index a13d51918..817f3576b 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
new file mode 100644
index 000000000..34b97fdfa
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include <time.h>
+#include <pwd.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+
+static int sys_clock_adjtime(clockid_t, struct timex *);
+static void timex_show(char *, struct timex);
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..c5381c383
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 500000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr = NULL;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr = tc[i].highlimit;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+	int rval;
+
+	/* check if clock is TIME_OK and save original clock flags */
+
+	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+
+	if (rval != TIME_OK)
+		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap");
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+
+		/* fix high and low limits by dividing it per HZ value */
+
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+
+		/* fix usec as being test default resolution */
+
+		if (saved.modes & ADJ_NANO) {
+			if (tc[i].modes == ADJ_OFFSET) {
+				tc[i].highlimit *= 1000;
+				tc[i].delta *= 1000;
+			}
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..ae590848c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+static void cleanup(void);
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami = 0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	static const char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/* special case: EFAULT for bad addresses */
+	if (tc[i].exp_err == EFAULT)
+		txcptr = tst_get_bad_addr(cleanup);
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr && tc[i].exp_err != EFAULT)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	if (tc[i].exp_err != TST_ERR) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+		return;
+	}
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+	int rval;
+
+	/* check if clock is TIME_OK and save original clock flags */
+
+	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+
+	if (rval != TIME_OK)
+		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap");
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 20:27                               ` [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-03-21 20:31                                 ` Rafael David Tinoco
  2019-03-22 13:34                                   ` Cyril Hrubis
  0 siblings, 1 reply; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-21 20:31 UTC (permalink / raw)
  To: ltp


> +static void setup(void)
> +{
> +	size_t i;
> +	int rval;
> +
> +	/* check if clock is TIME_OK and save original clock flags */
> +
> +	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +
> +	if (rval != TIME_OK)
> +		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap”);

I choose to break test if rval > 0 mainly because it could still have
on-going leap operations, since clock_adjtime() is async, and also
because doing the test with an unsynced clock seems weird.

Ran both or 10 seconds w/out any issue.

Same for clock_adtime02:

> +static void setup(void)
> +{
> +	size_t i;
> +	int rval;
> +
> +	/* check if clock is TIME_OK and save original clock flags */
> +
> +	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
> +
> +	if (rval != TIME_OK)
> +		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap");
> +

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-21 20:31                                 ` Rafael David Tinoco
@ 2019-03-22 13:34                                   ` Cyril Hrubis
  2019-03-22 13:36                                     ` Rafael David Tinoco
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-22 13:34 UTC (permalink / raw)
  To: ltp

Hi!
> > +	if (rval != TIME_OK)
> > +		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap???);
> 
> I choose to break test if rval > 0 mainly because it could still have
> on-going leap operations, since clock_adjtime() is async, and also
> because doing the test with an unsynced clock seems weird.

We should print the saved with timex_show() here and the rval at least.

It however it looks like kernel boots with STA_UNSYNC until NTP manges
to sync the time and clears the flag but only if it manages to sync the
clock.

See:

http://linuxelf.com/blog/2017/03/27/clock-status-unsync/

Which itself is an argument to run the test with unsynced clock, since
not all environments have access to internet or ntp daemon running.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-22 13:34                                   ` Cyril Hrubis
@ 2019-03-22 13:36                                     ` Rafael David Tinoco
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  1 sibling, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-22 13:36 UTC (permalink / raw)
  To: ltp

> On 22 Mar 2019, at 10:34, Cyril Hrubis <chrubis@suse.cz> wrote:
> 
> Hi!
>>> +	if (rval != TIME_OK)
>>> +		tst_brk(TBROK | TTERRNO, "unsynced clock or on-going leap???);
>> 
>> I choose to break test if rval > 0 mainly because it could still have
>> on-going leap operations, since clock_adjtime() is async, and also
>> because doing the test with an unsynced clock seems weird.
> 
> We should print the saved with timex_show() here and the rval at least.

Alright. v4 on its way.

> 
> It however it looks like kernel boots with STA_UNSYNC until NTP manges
> to sync the time and clears the flag but only if it manages to sync the
> clock.
> 
> See:
> 
> http://linuxelf.com/blog/2017/03/27/clock-status-unsync/
> 
> Which itself is an argument to run the test with unsynced clock, since
> not all environments have access to internet or ntp daemon running.

Valid point. I’ll allow rval being 5 then.

> 
> -- 
> Cyril Hrubis
> chrubis@suse.cz



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-03-22 13:34                                   ` Cyril Hrubis
  2019-03-22 13:36                                     ` Rafael David Tinoco
@ 2019-03-22 18:25                                     ` Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
                                                         ` (3 more replies)
  1 sibling, 4 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-22 18:25 UTC (permalink / raw)
  To: ltp

Adds SAFE_CLOCK_ADJTIME() macro to tst_safe_clocks.h.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index d5cd83394..596db4099 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -6,7 +6,9 @@
  */
 
 #include <time.h>
+#include <sys/timex.h>
 #include "tst_test.h"
+#include "lapi/syscalls.h"
 #include "lapi/posix_clocks.h"
 
 static inline void safe_clock_getres(const char *file, const int lineno,
@@ -44,6 +46,19 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 			"%s:%d clock_gettime() failed", file, lineno);
 }
 
+static inline int safe_clock_adjtime(const char *file, const int lineno,
+	clockid_t clk_id, struct timex *txc)
+{
+	int rval;
+
+	rval = tst_syscall(__NR_clock_adjtime, clk_id, txc);
+	if (rval < 0)
+		tst_brk(TBROK | TERRNO,
+			"%s:%d clock_adjtime() failed %i", file, lineno, rval);
+
+	return rval;
+}
+
 #define SAFE_CLOCK_GETRES(clk_id, res)\
 	safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
 
@@ -52,3 +67,6 @@ static inline void safe_clock_settime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_SETTIME(clk_id, tp)\
 	safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_ADJTIME(clk_id, txc)\
+	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v4 2/4] lib: Add include guard to tst_safe_clocks.h
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
@ 2019-03-22 18:25                                       ` Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
                                                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-22 18:25 UTC (permalink / raw)
  To: ltp

When adding a common header to my tests I missed this include guard when
accidentally including tst_safe_clocks.h from .c and .h files. Since
other tst_safe_*.h files have guards I thought it would be good to add
to this one as well.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/tst_safe_clocks.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/tst_safe_clocks.h b/include/tst_safe_clocks.h
index 596db4099..34ed953b4 100644
--- a/include/tst_safe_clocks.h
+++ b/include/tst_safe_clocks.h
@@ -5,6 +5,9 @@
  * Email : code@zilogic.com
  */
 
+#ifndef TST_SAFE_CLOCKS_H__
+#define TST_SAFE_CLOCKS_H__
+
 #include <time.h>
 #include <sys/timex.h>
 #include "tst_test.h"
@@ -70,3 +73,5 @@ static inline int safe_clock_adjtime(const char *file, const int lineno,
 
 #define SAFE_CLOCK_ADJTIME(clk_id, txc)\
 	safe_clock_adjtime(__FILE__, __LINE__, (clk_id), (txc))
+
+#endif /* SAFE_CLOCKS_H__ */
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v4 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
@ 2019-03-22 18:25                                       ` Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
  2019-03-25 16:24                                       ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
  3 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-22 18:25 UTC (permalink / raw)
  To: ltp

Used by clock_XXXtime() tests, defining MAX_CLOCKS in common header.

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                               | 2 ++
 testcases/kernel/syscalls/clock_gettime/clock_gettime02.c | 2 --
 testcases/kernel/syscalls/clock_settime/clock_settime02.c | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 0d1f0e99c..4914479ac 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -9,6 +9,8 @@
 #ifndef POSIX_CLOCKS_H__
 #define POSIX_CLOCKS_H__
 
+#define MAX_CLOCKS 16
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
index 2a29a71e6..b4bc6e2d5 100644
--- a/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
+++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime02.c
@@ -24,8 +24,6 @@
 #include "tst_timer.h"
 #include "tst_safe_clocks.h"
 
-#define MAX_CLOCKS 16
-
 struct test_case {
 	clockid_t clktype;
 	int exp_err;
diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime02.c b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
index 8db417b6b..e16e9061a 100644
--- a/testcases/kernel/syscalls/clock_settime/clock_settime02.c
+++ b/testcases/kernel/syscalls/clock_settime/clock_settime02.c
@@ -16,7 +16,6 @@
 
 #define DELTA_SEC 10
 #define NSEC_PER_SEC (1000000000L)
-#define MAX_CLOCKS 16
 
 struct test_case {
 	clockid_t type;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v4 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
@ 2019-03-22 18:25                                       ` Rafael David Tinoco
  2019-03-25 16:24                                       ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
  3 siblings, 0 replies; 37+ messages in thread
From: Rafael David Tinoco @ 2019-03-22 18:25 UTC (permalink / raw)
  To: ltp

Fixes: 270

clock_adjtime{01,02} are created using the new API, based on existing
adjtimex(2) tests. clock_adjtime() syscall might have as execution
path:

 1) a regular POSIX clock (only REALTIME clock implements adjtime())
    - will behave exactly like adjtimex() system call.
    - only one being tested here.

 2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
    - will trigger the PTP clock driver function "adjtime()"
    - different implementations from one PTP clock to another
    - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
    - no observed execution entry point for clock_adjtime()

Signed-off-by: Rafael David Tinoco <rafael.tinoco@linaro.org>
---
 include/lapi/posix_clocks.h                   |   4 +
 runtest/syscalls                              |   3 +
 .../kernel/syscalls/clock_adjtime/.gitignore  |   2 +
 .../kernel/syscalls/clock_adjtime/Makefile    |  10 +
 .../syscalls/clock_adjtime/clock_adjtime.h    |  57 +++++
 .../syscalls/clock_adjtime/clock_adjtime01.c  | 221 ++++++++++++++++++
 .../syscalls/clock_adjtime/clock_adjtime02.c  | 221 ++++++++++++++++++
 7 files changed, 518 insertions(+)
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/.gitignore
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/Makefile
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
 create mode 100644 testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c

diff --git a/include/lapi/posix_clocks.h b/include/lapi/posix_clocks.h
index 4914479ac..b1f7a7c55 100644
--- a/include/lapi/posix_clocks.h
+++ b/include/lapi/posix_clocks.h
@@ -11,6 +11,10 @@
 
 #define MAX_CLOCKS 16
 
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR |  \
+		 ADJ_ESTERROR | ADJ_STATUS | ADJ_TIMECONST |  \
+		 ADJ_TICK)
+
 #ifndef CLOCK_MONOTONIC_RAW
 # define CLOCK_MONOTONIC_RAW 4
 #endif
diff --git a/runtest/syscalls b/runtest/syscalls
index a13d51918..817f3576b 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -74,6 +74,9 @@ chroot02 chroot02
 chroot03 chroot03
 chroot04 chroot04
 
+clock_adjtime01 clock_adjtime01
+clock_adjtime02 clock_adjtime02
+
 clock_getres01 clock_getres01
 clock_nanosleep01 clock_nanosleep01
 clock_nanosleep02 clock_nanosleep02
diff --git a/testcases/kernel/syscalls/clock_adjtime/.gitignore b/testcases/kernel/syscalls/clock_adjtime/.gitignore
new file mode 100644
index 000000000..28d5a1d45
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/.gitignore
@@ -0,0 +1,2 @@
+clock_adjtime01
+clock_adjtime02
diff --git a/testcases/kernel/syscalls/clock_adjtime/Makefile b/testcases/kernel/syscalls/clock_adjtime/Makefile
new file mode 100644
index 000000000..79f671f1c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/Makefile
@@ -0,0 +1,10 @@
+# Copyright (c) 2019 - Linaro Limited. All rights reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+LDLIBS+=-lrt
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
\ No newline at end of file
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
new file mode 100644
index 000000000..34b97fdfa
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#include "config.h"
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_safe_clocks.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+#include <time.h>
+#include <pwd.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+
+static int sys_clock_adjtime(clockid_t, struct timex *);
+static void timex_show(char *, struct timex);
+
+/*
+ * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
+ */
+static int sys_clock_adjtime(clockid_t clk_id, struct timex *txc)
+{
+	return tst_syscall(__NR_clock_adjtime, clk_id, txc);
+}
+
+static void timex_show(char *given, struct timex txc)
+{
+	tst_res(TINFO,  "%s\n"
+			"             mode: %d\n"
+			"           offset: %ld\n"
+			"        frequency: %ld\n"
+			"         maxerror: %ld\n"
+			"         esterror: %ld\n"
+			"           status: %d (0x%x)\n"
+			"    time_constant: %ld\n"
+			"        precision: %ld\n"
+			"        tolerance: %ld\n"
+			"             tick: %ld\n"
+			"         raw time: %d(s) %d(us)",
+			given,
+			txc.modes,
+			txc.offset,
+			txc.freq,
+			txc.maxerror,
+			txc.esterror,
+			txc.status,
+			txc.status,
+			txc.constant,
+			txc.precision,
+			txc.tolerance,
+			txc.tick,
+			(int)txc.time.tv_sec,
+			(int)txc.time.tv_usec);
+}
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
new file mode 100644
index 000000000..6eac1f25c
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime01.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check possible adjustments:
+ *
+ *    - ADJ_OFFSET     - usec or nsec, kernel adjusts time gradually by offset
+ *                       (-512000 < offset < 512000)
+ *    - ADJ_FREQUENCY  - system clock frequency offset
+ *    - ADJ_MAXERROR   - maximum error (usec)
+ *    - ADJ_ESTERROR   - estimated time error in us
+ *    - ADJ_STATUS     - clock command/status of ntp implementation
+ *    - ADJ_TIMECONST  - PLL stiffness (jitter dependent) + poll int for PLL
+ *    - ADJ_TICK       - us between clock ticks
+ *                       (>= 900000/HZ, <= 1100000/HZ)
+ *
+ * and also the standalone ones (using .offset variable):
+ *
+ *    - ADJ_OFFSET_SINGLESHOT - behave like adjtime()
+ *    - ADJ_OFFSET_SS_READ - ret remaining time for completion after SINGLESHOT
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+struct test_case {
+	unsigned int modes;
+	long highlimit;
+	long *ptr;
+	long delta;
+};
+
+struct test_case tc[] = {
+	{
+	 .modes = ADJ_OFFSET_SINGLESHOT,
+	},
+	{
+	 .modes = ADJ_OFFSET_SS_READ,
+	},
+	{
+	 .modes = ADJ_ALL,
+	},
+	{
+	 .modes = ADJ_OFFSET,
+	 .highlimit = 500000,
+	 .ptr = &ttxc.offset,
+	 .delta = 10000,
+	},
+	{
+	 .modes = ADJ_FREQUENCY,
+	 .ptr = &ttxc.freq,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_MAXERROR,
+	 .ptr = &ttxc.maxerror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_ESTERROR,
+	 .ptr = &ttxc.esterror,
+	 .delta = 100,
+	},
+	{
+	 .modes = ADJ_TIMECONST,
+	 .ptr = &ttxc.constant,
+	 .delta = 1,
+	},
+	{
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1000,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	long ptroff, *ptr = NULL;
+	struct timex verify;
+
+	memset(&ttxc, 0, sizeof(struct timex));
+	memset(&verify, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("GET", ttxc);
+
+	ttxc.modes = tc[i].modes;
+
+	if (tc[i].ptr && tc[i].delta) {
+
+		*tc[i].ptr += tc[i].delta;
+
+		/* fix limits, if existent, so no errors occur */
+
+		if (tc[i].highlimit) {
+			if (*tc[i].ptr >= tc[i].highlimit)
+				*tc[i].ptr = tc[i].highlimit;
+		}
+	}
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &ttxc);
+	timex_show("SET", ttxc);
+
+	if (tc[i].ptr) {
+
+		/* adjtimex field being tested so we can verify later */
+
+		ptroff = (long) tc[i].ptr - (long) &ttxc;
+		ptr = (void *) &verify + ptroff;
+	}
+
+	TEST(sys_clock_adjtime(CLOCK_REALTIME, &verify));
+	timex_show("VERIFY", verify);
+
+	if (tc[i].ptr && *tc[i].ptr != *ptr) {
+		tst_res(TFAIL, "clock_adjtime(): could not set value (mode=%x)",
+				tc[i].modes);
+	}
+
+	if (TST_RET < 0) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): mode=%x, returned "
+				"error", tc[i].modes);
+	}
+
+	tst_res(TPASS, "clock_adjtime(): success (mode=%x)", tc[i].modes);
+}
+
+static void setup(void)
+{
+	size_t i;
+	int rval;
+
+	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+
+	if (rval != TIME_OK && rval != TIME_ERROR) {
+		timex_show("SAVE_STATUS", saved);
+		tst_brk(TBROK | TTERRNO, "clock has on-going leap changes, "
+				"returned: %i", rval);
+	}
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+
+		/* fix high and low limits by dividing it per HZ value */
+
+		if (tc[i].modes == ADJ_TICK)
+			tc[i].highlimit /= hz;
+
+		/* fix usec as being test default resolution */
+
+		if (saved.modes & ADJ_NANO) {
+			if (tc[i].modes == ADJ_OFFSET) {
+				tc[i].highlimit *= 1000;
+				tc[i].delta *= 1000;
+			}
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
new file mode 100644
index 000000000..1ce936f96
--- /dev/null
+++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime02.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+/*
+ * clock_adjtime() syscall might have as execution path:
+ *
+ *   1) a regular POSIX clock (only REALTIME clock implements adjtime())
+ *      - will behave exactly like adjtimex() system call.
+ *      - only one being tested here.
+ *
+ *   2) a dynamic POSIX clock (which ops are implemented by PTP clocks)
+ *      - will trigger the PTP clock driver function "adjtime()"
+ *      - different implementations from one PTP clock to another
+ *      - might return EOPNOTSUPP (like ptp_kvm_caps, for example)
+ *      - no entry point for clock_adjtime(), missing "CLOCK_PTP" model
+ *
+ * so it is sane to check for the following errors:
+ *
+ *   EINVAL -  clock id being used does not exist
+ *
+ *   EFAULT - (struct timex *) does not point to valid memory
+ *
+ *   EINVAL - ADJ_OFFSET + .offset outside range -512000 < x < 512000
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - ADJ_FREQUENCY + .freq outside range -32768000 < x < 3276800
+ *            (after 2.6.26, kernels normalize to the limit if outside range)
+ *
+ *   EINVAL - .tick outside permitted range (900000/HZ < .tick < 1100000/HZ)
+ *
+ *   EPERM  - .modes is neither 0 nor ADJ_OFFSET_SS_READ (CAP_SYS_TIME required)
+ *
+ *   EINVAL - .status other than those listed bellow
+ *
+ * For ADJ_STATUS, consider the following flags:
+ *
+ *      rw  STA_PLL - enable phase-locked loop updates (ADJ_OFFSET)
+ *      rw  STA_PPSFREQ - enable PPS (pulse-per-second) freq discipline
+ *      rw  STA_PPSTIME - enable PPS time discipline
+ *      rw  STA_FLL - select freq-locked loop mode.
+ *      rw  STA_INS - ins leap sec after the last sec of UTC day (all days)
+ *      rw  STA_DEL - del leap sec@last sec of UTC day (all days)
+ *      rw  STA_UNSYNC - clock unsynced
+ *      rw  STA_FREQHOLD - hold freq. ADJ_OFFSET made w/out auto small adjs
+ *      ro  STA_PPSSIGNAL - valid PPS (pulse-per-second) signal is present
+ *      ro  STA_PPSJITTER - PPS signal jitter exceeded.
+ *      ro  STA_PPSWANDER - PPS signal wander exceeded.
+ *      ro  STA_PPSERROR - PPS signal calibration error.
+ *      ro  STA_CLOKERR - clock HW fault.
+ *      ro  STA_NANO - 0 = us, 1 = ns (set = ADJ_NANO, cl = ADJ_MICRO)
+ *      rw  STA_MODE - mode: 0 = phased locked loop. 1 = freq locked loop
+ *      ro  STA_CLK - clock source. unused.
+ */
+
+#include "clock_adjtime.h"
+
+static long hz;
+static struct timex saved, ttxc;
+
+static void cleanup(void);
+
+struct test_case {
+	clockid_t clktype;
+	unsigned int modes;
+	long lowlimit;
+	long highlimit;
+	long *ptr;
+	long delta;
+	int exp_err;
+	int droproot;
+};
+
+struct test_case tc[] = {
+	{
+	 .clktype = MAX_CLOCKS,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = MAX_CLOCKS + 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EFAULT,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .lowlimit = 900000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_TICK,
+	 .highlimit = 1100000,
+	 .ptr = &ttxc.tick,
+	 .delta = 1,
+	 .exp_err = EINVAL,
+	},
+	{
+	 .clktype = CLOCK_REALTIME,
+	 .modes = ADJ_ALL,
+	 .exp_err = EPERM,
+	 .droproot = 1,
+	},
+};
+
+static void verify_clock_adjtime(unsigned int i)
+{
+	uid_t whoami = 0;
+	struct timex *txcptr;
+	struct passwd *nobody;
+	static const char name[] = "nobody";
+
+	txcptr = &ttxc;
+
+	memset(txcptr, 0, sizeof(struct timex));
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, txcptr);
+	timex_show("GET", *txcptr);
+
+	if (tc[i].droproot) {
+		nobody = SAFE_GETPWNAM(name);
+		whoami = nobody->pw_uid;
+		SAFE_SETEUID(whoami);
+	}
+
+	txcptr->modes = tc[i].modes;
+
+	if (tc[i].ptr) {
+
+		if (tc[i].lowlimit)
+			*tc[i].ptr = tc[i].lowlimit - tc[i].delta;
+
+		if (tc[i].highlimit)
+			*tc[i].ptr = tc[i].highlimit + tc[i].delta;
+	}
+
+	/* special case: EFAULT for bad addresses */
+	if (tc[i].exp_err == EFAULT)
+		txcptr = tst_get_bad_addr(cleanup);
+
+	TEST(sys_clock_adjtime(tc[i].clktype, txcptr));
+	if (txcptr && tc[i].exp_err != EFAULT)
+		timex_show("TEST", *txcptr);
+
+	if (TST_RET >= 0) {
+		tst_res(TFAIL, "clock_adjtime(): passed unexpectedly (mode=%x, "
+				"uid=%d)", tc[i].modes, whoami);
+		return;
+	}
+
+	if (tc[i].exp_err != TST_ERR) {
+		tst_res(TFAIL | TTERRNO, "clock_adjtime(): expected %d but "
+				"failed with %d (mode=%x, uid=%d)",
+				tc[i].exp_err, TST_ERR, tc[i].modes, whoami);
+		return;
+	}
+
+	tst_res(TPASS, "clock_adjtime(): failed as expected (mode=0x%x, "
+			"uid=%d)", tc[i].modes, whoami);
+
+	if (tc[i].droproot)
+		SAFE_SETEUID(0);
+}
+
+static void setup(void)
+{
+	size_t i;
+	int rval;
+
+	rval = SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+
+	if (rval != TIME_OK && rval != TIME_ERROR) {
+		timex_show("SAVE_STATUS", saved);
+		tst_brk(TBROK | TTERRNO, "clock has on-going leap changes, "
+				"returned: %i", rval);
+	}
+
+	hz = SAFE_SYSCONF(_SC_CLK_TCK);
+
+	/* fix high and low limits by dividing it per HZ value */
+
+	for (i = 0; i < ARRAY_SIZE(tc); i++) {
+		if (tc[i].modes == ADJ_TICK) {
+			tc[i].highlimit /= hz;
+			tc[i].lowlimit /= hz;
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	saved.modes = ADJ_ALL;
+
+	/* restore clock resolution based on original status flag */
+
+	if (saved.status & STA_NANO)
+		saved.modes |= ADJ_NANO;
+	else
+		saved.modes |= ADJ_MICRO;
+
+	/* restore original clock flags */
+
+	SAFE_CLOCK_ADJTIME(CLOCK_REALTIME, &saved);
+}
+
+static struct tst_test test = {
+	.test = verify_clock_adjtime,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tcnt = ARRAY_SIZE(tc),
+	.needs_root = 1,
+	.restore_wallclock = 1,
+};
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro
  2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
                                                         ` (2 preceding siblings ...)
  2019-03-22 18:25                                       ` [LTP] [PATCH v4 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
@ 2019-03-25 16:24                                       ` Cyril Hrubis
  3 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-03-25 16:24 UTC (permalink / raw)
  To: ltp

Hi!
Pushed, thanks.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2019-03-25 16:24 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-21 20:05 [LTP] [PATCH 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-02-21 20:05 ` [LTP] [PATCH 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-02-21 20:19   ` Rafael David Tinoco
2019-02-21 20:30   ` [LTP] [PATCH v2 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-02-21 20:30     ` [LTP] [PATCH v2 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-02-26  0:17       ` Petr Vorel
2019-02-26  0:24         ` Enji Cooper
2019-02-26 16:08         ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-02-26 16:08           ` [LTP] [PATCH v3 2/2] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-03-13 16:32             ` Cyril Hrubis
2019-03-15 11:07               ` Rafael David Tinoco
2019-03-20 21:41               ` [LTP] [PATCH v2 1/3] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-03-20 21:41                 ` [LTP] [PATCH v2 2/3] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
2019-03-20 21:41                 ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-03-20 21:48                   ` Rafael David Tinoco
2019-03-21 13:42                     ` Cyril Hrubis
2019-03-21 13:57                       ` Rafael David Tinoco
2019-03-21 14:05                         ` Cyril Hrubis
2019-03-21 14:10                           ` Cyril Hrubis
2019-03-21 14:17                             ` Rafael David Tinoco
2019-03-21 20:27                             ` [LTP] [PATCH v3 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-03-21 20:27                               ` [LTP] [PATCH v3 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
2019-03-21 20:27                               ` [LTP] [PATCH v3 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
2019-03-21 20:27                               ` [LTP] [PATCH v3 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-03-21 20:31                                 ` Rafael David Tinoco
2019-03-22 13:34                                   ` Cyril Hrubis
2019-03-22 13:36                                     ` Rafael David Tinoco
2019-03-22 18:25                                     ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Rafael David Tinoco
2019-03-22 18:25                                       ` [LTP] [PATCH v4 2/4] lib: Add include guard to tst_safe_clocks.h Rafael David Tinoco
2019-03-22 18:25                                       ` [LTP] [PATCH v4 3/4] lapi/posix_clocks.h: add MAX_CLOCKS definition Rafael David Tinoco
2019-03-22 18:25                                       ` [LTP] [PATCH v4 4/4] syscalls/clock_adjtime: create clock_adjtime syscall tests Rafael David Tinoco
2019-03-25 16:24                                       ` [LTP] [PATCH v4 1/4] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
2019-03-21 13:54                   ` [LTP] [PATCH v2 3/3] syscalls/clock_adjtime: create clock_adjtime syscall tests Cyril Hrubis
2019-03-21 14:00                     ` Rafael David Tinoco
2019-03-21 14:06                       ` Cyril Hrubis
2019-03-13 16:09           ` [LTP] [PATCH v3 1/2] lib: include SAFE_CLOCK_ADJTIME() macro Cyril Hrubis
2019-03-13 16:26             ` Rafael David Tinoco

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.