diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-kmem.c | 2 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/bpf_endian.h | 14 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/bpf_helpers.h | 198 | ||||
-rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc | 36 | ||||
-rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc | 28 | ||||
-rw-r--r-- | tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc | 4 | ||||
-rw-r--r-- | tools/testing/selftests/sysctl/Makefile | 3 | ||||
-rw-r--r-- | tools/testing/selftests/sysctl/common_tests | 131 | ||||
-rw-r--r-- | tools/testing/selftests/sysctl/config | 1 | ||||
-rwxr-xr-x | tools/testing/selftests/sysctl/run_numerictests | 10 | ||||
-rwxr-xr-x | tools/testing/selftests/sysctl/run_stringtests | 77 | ||||
-rw-r--r-- | tools/testing/selftests/sysctl/sysctl.sh | 774 | ||||
-rw-r--r-- | tools/testing/selftests/timers/Makefile | 2 | ||||
-rw-r--r-- | tools/testing/selftests/timers/rtctest.c | 128 | ||||
-rw-r--r-- | tools/testing/selftests/timers/rtctest_setdate.c | 86 |
16 files changed, 1266 insertions, 229 deletions
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0a8a1c4..a1497c5 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -643,7 +643,7 @@ static const struct { { "__GFP_FS", "F" }, { "__GFP_COLD", "CO" }, { "__GFP_NOWARN", "NWR" }, - { "__GFP_REPEAT", "R" }, + { "__GFP_RETRY_MAYFAIL", "R" }, { "__GFP_NOFAIL", "NF" }, { "__GFP_NORETRY", "NR" }, { "__GFP_COMP", "C" }, diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 2ca51a8..153c3a1 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -37,6 +37,5 @@ CLANG ?= clang %.o: %.c $(CLANG) -I. -I./include/uapi -I../../../include/uapi \ - -I../../../../samples/bpf/ \ -Wno-compare-distinct-pointer-types \ -O2 -target bpf -c $< -o $@ diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h index 487cbfb..74af266 100644 --- a/tools/testing/selftests/bpf/bpf_endian.h +++ b/tools/testing/selftests/bpf/bpf_endian.h @@ -23,11 +23,19 @@ # define __bpf_htons(x) __builtin_bswap16(x) # define __bpf_constant_ntohs(x) ___constant_swab16(x) # define __bpf_constant_htons(x) ___constant_swab16(x) +# define __bpf_ntohl(x) __builtin_bswap32(x) +# define __bpf_htonl(x) __builtin_bswap32(x) +# define __bpf_constant_ntohl(x) ___constant_swab32(x) +# define __bpf_constant_htonl(x) ___constant_swab32(x) #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define __bpf_ntohs(x) (x) # define __bpf_htons(x) (x) # define __bpf_constant_ntohs(x) (x) # define __bpf_constant_htons(x) (x) +# define __bpf_ntohl(x) (x) +# define __bpf_htonl(x) (x) +# define __bpf_constant_ntohl(x) (x) +# define __bpf_constant_htonl(x) (x) #else # error "Fix your compiler's __BYTE_ORDER__?!" #endif @@ -38,5 +46,11 @@ #define bpf_ntohs(x) \ (__builtin_constant_p(x) ? \ __bpf_constant_ntohs(x) : __bpf_ntohs(x)) +#define bpf_htonl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_htonl(x) : __bpf_htonl(x)) +#define bpf_ntohl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_ntohl(x) : __bpf_ntohl(x)) #endif /* __BPF_ENDIAN__ */ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h new file mode 100644 index 0000000..d50ac34 --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -0,0 +1,198 @@ +#ifndef __BPF_HELPERS_H +#define __BPF_HELPERS_H + +/* helper macro to place programs, maps, license in + * different sections in elf_bpf file. Section names + * are interpreted by elf_bpf loader + */ +#define SEC(NAME) __attribute__((section(NAME), used)) + +/* helper functions called from eBPF programs written in C */ +static void *(*bpf_map_lookup_elem)(void *map, void *key) = + (void *) BPF_FUNC_map_lookup_elem; +static int (*bpf_map_update_elem)(void *map, void *key, void *value, + unsigned long long flags) = + (void *) BPF_FUNC_map_update_elem; +static int (*bpf_map_delete_elem)(void *map, void *key) = + (void *) BPF_FUNC_map_delete_elem; +static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = + (void *) BPF_FUNC_probe_read; +static unsigned long long (*bpf_ktime_get_ns)(void) = + (void *) BPF_FUNC_ktime_get_ns; +static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = + (void *) BPF_FUNC_trace_printk; +static void (*bpf_tail_call)(void *ctx, void *map, int index) = + (void *) BPF_FUNC_tail_call; +static unsigned long long (*bpf_get_smp_processor_id)(void) = + (void *) BPF_FUNC_get_smp_processor_id; +static unsigned long long (*bpf_get_current_pid_tgid)(void) = + (void *) BPF_FUNC_get_current_pid_tgid; +static unsigned long long (*bpf_get_current_uid_gid)(void) = + (void *) BPF_FUNC_get_current_uid_gid; +static int (*bpf_get_current_comm)(void *buf, int buf_size) = + (void *) BPF_FUNC_get_current_comm; +static unsigned long long (*bpf_perf_event_read)(void *map, + unsigned long long flags) = + (void *) BPF_FUNC_perf_event_read; +static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = + (void *) BPF_FUNC_clone_redirect; +static int (*bpf_redirect)(int ifindex, int flags) = + (void *) BPF_FUNC_redirect; +static int (*bpf_perf_event_output)(void *ctx, void *map, + unsigned long long flags, void *data, + int size) = + (void *) BPF_FUNC_perf_event_output; +static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = + (void *) BPF_FUNC_get_stackid; +static int (*bpf_probe_write_user)(void *dst, void *src, int size) = + (void *) BPF_FUNC_probe_write_user; +static int (*bpf_current_task_under_cgroup)(void *map, int index) = + (void *) BPF_FUNC_current_task_under_cgroup; +static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = + (void *) BPF_FUNC_skb_get_tunnel_key; +static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = + (void *) BPF_FUNC_skb_set_tunnel_key; +static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) = + (void *) BPF_FUNC_skb_get_tunnel_opt; +static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) = + (void *) BPF_FUNC_skb_set_tunnel_opt; +static unsigned long long (*bpf_get_prandom_u32)(void) = + (void *) BPF_FUNC_get_prandom_u32; +static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = + (void *) BPF_FUNC_xdp_adjust_head; +static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, + int optlen) = + (void *) BPF_FUNC_setsockopt; + +/* llvm builtin functions that eBPF C program may use to + * emit BPF_LD_ABS and BPF_LD_IND instructions + */ +struct sk_buff; +unsigned long long load_byte(void *skb, + unsigned long long off) asm("llvm.bpf.load.byte"); +unsigned long long load_half(void *skb, + unsigned long long off) asm("llvm.bpf.load.half"); +unsigned long long load_word(void *skb, + unsigned long long off) asm("llvm.bpf.load.word"); + +/* a helper structure used by eBPF C program + * to describe map attributes to elf_bpf loader + */ +struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; + unsigned int map_flags; + unsigned int inner_map_idx; +}; + +static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = + (void *) BPF_FUNC_skb_load_bytes; +static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = + (void *) BPF_FUNC_skb_store_bytes; +static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = + (void *) BPF_FUNC_l3_csum_replace; +static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = + (void *) BPF_FUNC_l4_csum_replace; +static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = + (void *) BPF_FUNC_skb_under_cgroup; +static int (*bpf_skb_change_head)(void *, int len, int flags) = + (void *) BPF_FUNC_skb_change_head; + +#if defined(__x86_64__) + +#define PT_REGS_PARM1(x) ((x)->di) +#define PT_REGS_PARM2(x) ((x)->si) +#define PT_REGS_PARM3(x) ((x)->dx) +#define PT_REGS_PARM4(x) ((x)->cx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->sp) +#define PT_REGS_FP(x) ((x)->bp) +#define PT_REGS_RC(x) ((x)->ax) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->ip) + +#elif defined(__s390x__) + +#define PT_REGS_PARM1(x) ((x)->gprs[2]) +#define PT_REGS_PARM2(x) ((x)->gprs[3]) +#define PT_REGS_PARM3(x) ((x)->gprs[4]) +#define PT_REGS_PARM4(x) ((x)->gprs[5]) +#define PT_REGS_PARM5(x) ((x)->gprs[6]) +#define PT_REGS_RET(x) ((x)->gprs[14]) +#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->gprs[2]) +#define PT_REGS_SP(x) ((x)->gprs[15]) +#define PT_REGS_IP(x) ((x)->psw.addr) + +#elif defined(__aarch64__) + +#define PT_REGS_PARM1(x) ((x)->regs[0]) +#define PT_REGS_PARM2(x) ((x)->regs[1]) +#define PT_REGS_PARM3(x) ((x)->regs[2]) +#define PT_REGS_PARM4(x) ((x)->regs[3]) +#define PT_REGS_PARM5(x) ((x)->regs[4]) +#define PT_REGS_RET(x) ((x)->regs[30]) +#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[0]) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->pc) + +#elif defined(__mips__) + +#define PT_REGS_PARM1(x) ((x)->regs[4]) +#define PT_REGS_PARM2(x) ((x)->regs[5]) +#define PT_REGS_PARM3(x) ((x)->regs[6]) +#define PT_REGS_PARM4(x) ((x)->regs[7]) +#define PT_REGS_PARM5(x) ((x)->regs[8]) +#define PT_REGS_RET(x) ((x)->regs[31]) +#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[1]) +#define PT_REGS_SP(x) ((x)->regs[29]) +#define PT_REGS_IP(x) ((x)->cp0_epc) + +#elif defined(__powerpc__) + +#define PT_REGS_PARM1(x) ((x)->gpr[3]) +#define PT_REGS_PARM2(x) ((x)->gpr[4]) +#define PT_REGS_PARM3(x) ((x)->gpr[5]) +#define PT_REGS_PARM4(x) ((x)->gpr[6]) +#define PT_REGS_PARM5(x) ((x)->gpr[7]) +#define PT_REGS_RC(x) ((x)->gpr[3]) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->nip) + +#elif defined(__sparc__) + +#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) +#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) +#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) +#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) +#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) +#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) +#if defined(__arch64__) +#define PT_REGS_IP(x) ((x)->tpc) +#else +#define PT_REGS_IP(x) ((x)->pc) +#endif + +#endif + +#ifdef __powerpc__ +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#elif defined(__sparc__) +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#else +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \ + bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) +#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \ + bpf_probe_read(&(ip), sizeof(ip), \ + (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) +#endif + +#endif diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc new file mode 100644 index 0000000..b9302cc --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc @@ -0,0 +1,36 @@ +#!/bin/sh +# description: Kprobe event auto/manual naming + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +disable_events +echo > kprobe_events + +:;: "Add an event on function without name" ;: + +FUNC=`grep " [tT] .*vfs_read$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "` +[ "x" != "x$FUNC" ] || exit_unresolved +echo "p $FUNC" > kprobe_events +PROBE_NAME=`echo $FUNC | tr ".:" "_"` +test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure + +:;: "Add an event on function with new name" ;: + +echo "p:event1 $FUNC" > kprobe_events +test -d events/kprobes/event1 || exit_failure + +:;: "Add an event on function with new name and group" ;: + +echo "p:kprobes2/event2 $FUNC" > kprobe_events +test -d events/kprobes2/event2 || exit_failure + +:;: "Add an event on dot function without name" ;: + +FUNC=`grep -m 10 " [tT] .*\.isra\..*$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "` +[ "x" != "x$FUNC" ] || exit_unresolved +echo "p $FUNC" > kprobe_events +EVENT=`grep $FUNC kprobe_events | cut -f 1 -d " " | cut -f 2 -d:` +[ "x" != "x$EVENT" ] || exit_failure +test -d events/$EVENT || exit_failure + +echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc new file mode 100644 index 0000000..6d634e4 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_module.tc @@ -0,0 +1,28 @@ +#!/bin/sh +# description: Kprobe dynamic event - probing module + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +disable_events +echo > kprobe_events + +:;: "Add an event on a module function without specifying event name" ;: + +MOD=`lsmod | head -n 2 | tail -n 1 | cut -f1 -d" "` +FUNC=`grep -m 1 ".* t .*\\[$MOD\\]" /proc/kallsyms | xargs | cut -f3 -d" "` +[ "x" != "x$MOD" -a "y" != "y$FUNC" ] || exit_unresolved +echo "p $MOD:$FUNC" > kprobe_events +PROBE_NAME=`echo $MOD:$FUNC | tr ".:" "_"` +test -d events/kprobes/p_${PROBE_NAME}_0 || exit_failure + +:;: "Add an event on a module function with new event name" ;: + +echo "p:event1 $MOD:$FUNC" > kprobe_events +test -d events/kprobes/event1 || exit_failure + +:;: "Add an event on a module function with new event and group name" ;: + +echo "p:kprobes1/event1 $MOD:$FUNC" > kprobe_events +test -d events/kprobes1/event1 || exit_failure + +echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc index f4d1ff7..2a1cb99 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc @@ -2,10 +2,10 @@ # description: Register/unregister many kprobe events # ftrace fentry skip size depends on the machine architecture. -# Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc +# Currently HAVE_KPROBES_ON_FTRACE defined on x86 and powerpc64le case `uname -m` in x86_64|i[3456]86) OFFS=5;; - ppc*) OFFS=4;; + ppc64le) OFFS=8;; *) OFFS=0;; esac diff --git a/tools/testing/selftests/sysctl/Makefile b/tools/testing/selftests/sysctl/Makefile index b3c33e0..95c320b 100644 --- a/tools/testing/selftests/sysctl/Makefile +++ b/tools/testing/selftests/sysctl/Makefile @@ -4,8 +4,7 @@ # No binaries, but make sure arg-less "make" doesn't trigger "run_tests". all: -TEST_PROGS := run_numerictests run_stringtests -TEST_FILES := common_tests +TEST_PROGS := sysctl.sh include ../lib.mk diff --git a/tools/testing/selftests/sysctl/common_tests b/tools/testing/selftests/sysctl/common_tests deleted file mode 100644 index b686232..0000000 --- a/tools/testing/selftests/sysctl/common_tests +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/sh - -TEST_FILE=$(mktemp) - -echo "== Testing sysctl behavior against ${TARGET} ==" - -set_orig() -{ - echo "${ORIG}" > "${TARGET}" -} - -set_test() -{ - echo "${TEST_STR}" > "${TARGET}" -} - -verify() -{ - local seen - seen=$(cat "$1") - if [ "${seen}" != "${TEST_STR}" ]; then - return 1 - fi - return 0 -} - -exit_test() -{ - if [ ! -z ${old_strict} ]; then - echo ${old_strict} > ${WRITES_STRICT} - fi - exit $rc -} - -trap 'set_orig; rm -f "${TEST_FILE}"' EXIT - -rc=0 - -echo -n "Writing test file ... " -echo "${TEST_STR}" > "${TEST_FILE}" -if ! verify "${TEST_FILE}"; then - echo "FAIL" >&2 - exit 1 -else - echo "ok" -fi - -echo -n "Checking sysctl is not set to test value ... " -if verify "${TARGET}"; then - echo "FAIL" >&2 - exit 1 -else - echo "ok" -fi - -echo -n "Writing sysctl from shell ... " -set_test -if ! verify "${TARGET}"; then - echo "FAIL" >&2 - exit 1 -else - echo "ok" -fi - -echo -n "Resetting sysctl to original value ... " -set_orig -if verify "${TARGET}"; then - echo "FAIL" >&2 - exit 1 -else - echo "ok" -fi - -echo -n "Checking write strict setting ... " -WRITES_STRICT="${SYSCTL}/kernel/sysctl_writes_strict" -if [ ! -e ${WRITES_STRICT} ]; then - echo "FAIL, but skip in case of old kernel" >&2 -else - old_strict=$(cat ${WRITES_STRICT}) - if [ "$old_strict" = "1" ]; then - echo "ok" - else - echo "FAIL, strict value is 0 but force to 1 to continue" >&2 - echo "1" > ${WRITES_STRICT} - fi -fi - -# Now that we've validated the sanity of "set_test" and "set_orig", -# we can use those functions to set starting states before running -# specific behavioral tests. - -echo -n "Writing entire sysctl in single write ... " -set_orig -dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null -if ! verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Writing middle of sysctl after synchronized seek ... " -set_test -dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null -if ! verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Writing beyond end of sysctl ... " -set_orig -dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null -if verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Writing sysctl with multiple long writes ... " -set_orig -(perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \ - dd of="${TARGET}" bs=50 2>/dev/null -if verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi diff --git a/tools/testing/selftests/sysctl/config b/tools/testing/selftests/sysctl/config new file mode 100644 index 0000000..6ca1480 --- /dev/null +++ b/tools/testing/selftests/sysctl/config @@ -0,0 +1 @@ +CONFIG_TEST_SYSCTL=y diff --git a/tools/testing/selftests/sysctl/run_numerictests b/tools/testing/selftests/sysctl/run_numerictests deleted file mode 100755 index e6e76c9..0000000 --- a/tools/testing/selftests/sysctl/run_numerictests +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/vm/swappiness" -ORIG=$(cat "${TARGET}") -TEST_STR=$(( $ORIG + 1 )) - -. ./common_tests - -exit_test diff --git a/tools/testing/selftests/sysctl/run_stringtests b/tools/testing/selftests/sysctl/run_stringtests deleted file mode 100755 index 857ec66..0000000 --- a/tools/testing/selftests/sysctl/run_stringtests +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -SYSCTL="/proc/sys" -TARGET="${SYSCTL}/kernel/domainname" -ORIG=$(cat "${TARGET}") -TEST_STR="Testing sysctl" - -. ./common_tests - -# Only string sysctls support seeking/appending. -MAXLEN=65 - -echo -n "Writing entire sysctl in short writes ... " -set_orig -dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null -if ! verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Writing middle of sysctl after unsynchronized seek ... " -set_test -dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null -if verify "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Checking sysctl maxlen is at least $MAXLEN ... " -set_orig -perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \ - dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null -if ! grep -q B "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Checking sysctl keeps original string on overflow append ... " -set_orig -perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ - dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null -if grep -q B "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Checking sysctl stays NULL terminated on write ... " -set_orig -perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ - dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null -if grep -q B "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -echo -n "Checking sysctl stays NULL terminated on overwrite ... " -set_orig -perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \ - dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null -if grep -q B "${TARGET}"; then - echo "FAIL" >&2 - rc=1 -else - echo "ok" -fi - -exit_test diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh new file mode 100644 index 0000000..ec232c3 --- /dev/null +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -0,0 +1,774 @@ +#!/bin/bash +# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or at your option any +# later version; or, when distributed separately from the Linux kernel or +# when incorporated into other software packages, subject to the following +# license: +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of copyleft-next (version 0.3.1 or later) as published +# at http://copyleft-next.org/. + +# This performs a series tests against the proc sysctl interface. + +TEST_NAME="sysctl" +TEST_DRIVER="test_${TEST_NAME}" +TEST_DIR=$(dirname $0) +TEST_FILE=$(mktemp) + +# This represents +# +# TEST_ID:TEST_COUNT:ENABLED +# +# TEST_ID: is the test id number +# TEST_COUNT: number of times we should run the test +# ENABLED: 1 if enabled, 0 otherwise +# +# Once these are enabled please leave them as-is. Write your own test, +# we have tons of space. +ALL_TESTS="0001:1:1" +ALL_TESTS="$ALL_TESTS 0002:1:1" +ALL_TESTS="$ALL_TESTS 0003:1:1" +ALL_TESTS="$ALL_TESTS 0004:1:1" +ALL_TESTS="$ALL_TESTS 0005:3:1" + +test_modprobe() +{ + if [ ! -d $DIR ]; then + echo "$0: $DIR not present" >&2 + echo "You must have the following enabled in your kernel:" >&2 + cat $TEST_DIR/config >&2 + exit 1 + fi +} + +function allow_user_defaults() +{ + if [ -z $DIR ]; then + DIR="/sys/module/test_sysctl/" + fi + if [ -z $DEFAULT_NUM_TESTS ]; then + DEFAULT_NUM_TESTS=50 + fi + if [ -z $SYSCTL ]; then + SYSCTL="/proc/sys/debug/test_sysctl" + fi + if [ -z $PROD_SYSCTL ]; then + PROD_SYSCTL="/proc/sys" + fi + if [ -z $WRITES_STRICT ]; then + WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict" + fi +} + +function check_production_sysctl_writes_strict() +{ + echo -n "Checking production write strict setting ... " + if [ ! -e ${WRITES_STRICT} ]; then + echo "FAIL, but skip in case of old kernel" >&2 + else + old_strict=$(cat ${WRITES_STRICT}) + if [ "$old_strict" = "1" ]; then + echo "ok" + else + echo "FAIL, strict value is 0 but force to 1 to continue" >&2 + echo "1" > ${WRITES_STRICT} + fi + fi + + if [ -z $PAGE_SIZE ]; then + PAGE_SIZE=$(getconf PAGESIZE) + fi + if [ -z $MAX_DIGITS ]; then + MAX_DIGITS=$(($PAGE_SIZE/8)) + fi + if [ -z $INT_MAX ]; then + INT_MAX=$(getconf INT_MAX) + fi + if [ -z $UINT_MAX ]; then + UINT_MAX=$(getconf UINT_MAX) + fi +} + +test_reqs() +{ + uid=$(id -u) + if [ $uid -ne 0 ]; then + echo $msg must be run as root >&2 + exit 0 + fi + + if ! which perl 2> /dev/null > /dev/null; then + echo "$0: You need perl installed" + exit 1 + fi + if ! which getconf 2> /dev/null > /dev/null; then + echo "$0: You need getconf installed" + exit 1 + fi + if ! which diff 2> /dev/null > /dev/null; then + echo "$0: You need diff installed" + exit 1 + fi +} + +function load_req_mod() +{ + trap "test_modprobe" EXIT + + if [ ! -d $DIR ]; then + modprobe $TEST_DRIVER + if [ $? -ne 0 ]; then + exit + fi + fi +} + +reset_vals() +{ + VAL="" + TRIGGER=$(basename ${TARGET}) + case "$TRIGGER" in + int_0001) + VAL="60" + ;; + int_0002) + VAL="1" + ;; + uint_0001) + VAL="314" + ;; + string_0001) + VAL="(none)" + ;; + *) + ;; + esac + echo -n $VAL > $TARGET +} + +set_orig() +{ + if [ ! -z $TARGET ]; then + echo "${ORIG}" > "${TARGET}" + fi +} + +set_test() +{ + echo "${TEST_STR}" > "${TARGET}" +} + +verify() +{ + local seen + seen=$(cat "$1") + if [ "${seen}" != "${TEST_STR}" ]; then + return 1 + fi + return 0 +} + +verify_diff_w() +{ + echo "$TEST_STR" | diff -q -w -u - $1 + return $? +} + +test_rc() +{ + if [[ $rc != 0 ]]; then + echo "Failed test, return value: $rc" >&2 + exit $rc + fi +} + +test_finish() +{ + set_orig + rm -f "${TEST_FILE}" + + if [ ! -z ${old_strict} ]; then + echo ${old_strict} > ${WRITES_STRICT} + fi + exit $rc +} + +run_numerictests() +{ + echo "== Testing sysctl behavior against ${TARGET} ==" + + rc=0 + + echo -n "Writing test file ... " + echo "${TEST_STR}" > "${TEST_FILE}" + if ! verify "${TEST_FILE}"; then + echo "FAIL" >&2 + exit 1 + else + echo "ok" + fi + + echo -n "Checking sysctl is not set to test value ... " + if verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 + else + echo "ok" + fi + + echo -n "Writing sysctl from shell ... " + set_test + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 + else + echo "ok" + fi + + echo -n "Resetting sysctl to original value ... " + set_orig + if verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 + else + echo "ok" + fi + + # Now that we've validated the sanity of "set_test" and "set_orig", + # we can use those functions to set starting states before running + # specific behavioral tests. + + echo -n "Writing entire sysctl in single write ... " + set_orig + dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Writing middle of sysctl after synchronized seek ... " + set_test + dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Writing beyond end of sysctl ... " + set_orig + dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Writing sysctl with multiple long writes ... " + set_orig + (perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \ + dd of="${TARGET}" bs=50 2>/dev/null + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + +# Your test must accept digits 3 and 4 to use this +run_limit_digit() +{ + echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..." + reset_vals + + LIMIT=$((MAX_DIGITS -1)) + TEST_STR="3" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Checking passing PAGE_SIZE of spaces fails on write ..." + reset_vals + + LIMIT=$((MAX_DIGITS)) + TEST_STR="4" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + +# You are using an int +run_limit_digit_int() +{ + echo -n "Testing INT_MAX works ..." + reset_vals + TEST_STR="$INT_MAX" + echo -n $TEST_STR > $TARGET + + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing INT_MAX + 1 will fail as expected..." + reset_vals + let TEST_STR=$INT_MAX+1 + echo -n $TEST_STR > $TARGET 2> /dev/null + + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing negative values will work as expected..." + reset_vals + TEST_STR="-3" + echo -n $TEST_STR > $TARGET 2> /dev/null + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + +# You used an int array +run_limit_digit_int_array() +{ + echo -n "Testing array works as expected ... " + TEST_STR="4 3 2 1" + echo -n $TEST_STR > $TARGET + + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing skipping trailing array elements works ... " + # Do not reset_vals, carry on the values from the last test. + # If we only echo in two digits the last two are left intact + TEST_STR="100 101" + echo -n $TEST_STR > $TARGET + # After we echo in, to help diff we need to set on TEST_STR what + # we expect the result to be. + TEST_STR="100 101 2 1" + + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing PAGE_SIZE limit on array works ... " + # Do not reset_vals, carry on the values from the last test. + # Even if you use an int array, you are still restricted to + # MAX_DIGITS, this is a known limitation. Test limit works. + LIMIT=$((MAX_DIGITS -1)) + TEST_STR="9" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + TEST_STR="9 101 2 1" + if ! verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... " + # Do not reset_vals, carry on the values from the last test. + # Now go over limit. + LIMIT=$((MAX_DIGITS)) + TEST_STR="7" + (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ + dd of="${TARGET}" 2>/dev/null + + TEST_STR="7 101 2 1" + if verify_diff_w "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + +# You are using an unsigned int +run_limit_digit_uint() +{ + echo -n "Testing UINT_MAX works ..." + reset_vals + TEST_STR="$UINT_MAX" + echo -n $TEST_STR > $TARGET + + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing UINT_MAX + 1 will fail as expected..." + reset_vals + TEST_STR=$(($UINT_MAX+1)) + echo -n $TEST_STR > $TARGET 2> /dev/null + + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc + + echo -n "Testing negative values will not work as expected ..." + reset_vals + TEST_STR="-3" + echo -n $TEST_STR > $TARGET 2> /dev/null + + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + test_rc +} + +run_stringtests() +{ + echo -n "Writing entire sysctl in short writes ... " + set_orig + dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null + if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Writing middle of sysctl after unsynchronized seek ... " + set_test + dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null + if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Checking sysctl maxlen is at least $MAXLEN ... " + set_orig + perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \ + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null + if ! grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Checking sysctl keeps original string on overflow append ... " + set_orig + perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ + dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null + if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Checking sysctl stays NULL terminated on write ... " + set_orig + perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null + if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + echo -n "Checking sysctl stays NULL terminated on overwrite ... " + set_orig + perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \ + dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null + if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 + else + echo "ok" + fi + + test_rc +} + +sysctl_test_0001() +{ + TARGET="${SYSCTL}/int_0001" + reset_vals + ORIG=$(cat "${TARGET}") + TEST_STR=$(( $ORIG + 1 )) + + run_numerictests + run_limit_digit +} + +sysctl_test_0002() +{ + TARGET="${SYSCTL}/string_0001" + reset_vals + ORIG=$(cat "${TARGET}") + TEST_STR="Testing sysctl" + # Only string sysctls support seeking/appending. + MAXLEN=65 + + run_numerictests + run_stringtests +} + +sysctl_test_0003() +{ + TARGET="${SYSCTL}/int_0002" + reset_vals + ORIG=$(cat "${TARGET}") + TEST_STR=$(( $ORIG + 1 )) + + run_numerictests + run_limit_digit + run_limit_digit_int +} + +sysctl_test_0004() +{ + TARGET="${SYSCTL}/uint_0001" + reset_vals + ORIG=$(cat "${TARGET}") + TEST_STR=$(( $ORIG + 1 )) + + run_numerictests + run_limit_digit + run_limit_digit_uint +} + +sysctl_test_0005() +{ + TARGET="${SYSCTL}/int_0003" + reset_vals + ORIG=$(cat "${TARGET}") + + run_limit_digit_int_array +} + +list_tests() +{ + echo "Test ID list:" + echo + echo "TEST_ID x NUM_TEST" + echo "TEST_ID: Test ID" + echo "NUM_TESTS: Number of recommended times to run the test" + echo + echo "0001 x $(get_test_count 0001) - tests proc_dointvec_minmax()" + echo "0002 x $(get_test_count 0002) - tests proc_dostring()" + echo "0003 x $(get_test_count 0003) - tests proc_dointvec()" + echo "0004 x $(get_test_count 0004) - tests proc_douintvec()" + echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array" +} + +test_reqs + +usage() +{ + NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .) + let NUM_TESTS=$NUM_TESTS+1 + MAX_TEST=$(printf "%04d\n" $NUM_TESTS) + echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |" + echo " [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>" + echo " [ all ] [ -h | --help ] [ -l ]" + echo "" + echo "Valid tests: 0001-$MAX_TEST" + echo "" + echo " all Runs all tests (default)" + echo " -t Run test ID the number amount of times is recommended" + echo " -w Watch test ID run until it runs into an error" + echo " -c Run test ID once" + echo " -s Run test ID x test-count number of times" + echo " -l List all test ID list" + echo " -h|--help Help" + echo + echo "If an error every occurs execution will immediately terminate." + echo "If you are adding a new test try using -w <test-ID> first to" + echo "make sure the test passes a series of tests." + echo + echo Example uses: + echo + echo "$TEST_NAME.sh -- executes all tests" + echo "$TEST_NAME.sh -t 0002 -- Executes test ID 0002 number of times is recomended" + echo "$TEST_NAME.sh -w 0002 -- Watch test ID 0002 run until an error occurs" + echo "$TEST_NAME.sh -s 0002 -- Run test ID 0002 once" + echo "$TEST_NAME.sh -c 0002 3 -- Run test ID 0002 three times" + echo + list_tests + exit 1 +} + +function test_num() +{ + re='^[0-9]+$' + if ! [[ $1 =~ $re ]]; then + usage + fi +} + +function get_test_count() +{ + test_num $1 + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + LAST_TWO=${TEST_DATA#*:*} + echo ${LAST_TWO%:*} +} + +function get_test_enabled() +{ + test_num $1 + TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') + echo ${TEST_DATA#*:*:} +} + +function run_all_tests() +{ + for i in $ALL_TESTS ; do + TEST_ID=${i%:*:*} + ENABLED=$(get_test_enabled $TEST_ID) + TEST_COUNT=$(get_test_count $TEST_ID) + if [[ $ENABLED -eq "1" ]]; then + test_case $TEST_ID $TEST_COUNT + fi + done +} + +function watch_log() +{ + if [ $# -ne 3 ]; then + clear + fi + date + echo "Running test: $2 - run #$1" +} + +function watch_case() +{ + i=0 + while [ 1 ]; do + + if [ $# -eq 1 ]; then + test_num $1 + watch_log $i ${TEST_NAME}_test_$1 + ${TEST_NAME}_test_$1 + else + watch_log $i all + run_all_tests + fi + let i=$i+1 + done +} + +function test_case() +{ + NUM_TESTS=$DEFAULT_NUM_TESTS + if [ $# -eq 2 ]; then + NUM_TESTS=$2 + fi + + i=0 + while [ $i -lt $NUM_TESTS ]; do + test_num $1 + watch_log $i ${TEST_NAME}_test_$1 noclear + RUN_TEST=${TEST_NAME}_test_$1 + $RUN_TEST + let i=$i+1 + done +} + +function parse_args() +{ + if [ $# -eq 0 ]; then + run_all_tests + else + if [[ "$1" = "all" ]]; then + run_all_tests + elif [[ "$1" = "-w" ]]; then + shift + watch_case $@ + elif [[ "$1" = "-t" ]]; then + shift + test_num $1 + test_case $1 $(get_test_count $1) + elif [[ "$1" = "-c" ]]; then + shift + test_num $1 + test_num $2 + test_case $1 $2 + elif [[ "$1" = "-s" ]]; then + shift + test_case $1 1 + elif [[ "$1" = "-l" ]]; then + list_tests + elif [[ "$1" = "-h" || "$1" = "--help" ]]; then + usage + else + usage + fi + fi +} + +test_reqs +allow_user_defaults +check_production_sysctl_writes_strict +load_req_mod + +trap "test_finish" EXIT + +parse_args $@ + +exit 0 diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile index 5801bbe..a9b8613 100644 --- a/tools/testing/selftests/timers/Makefile +++ b/tools/testing/selftests/timers/Makefile @@ -9,7 +9,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \ skew_consistency clocksource-switch freq-step leap-a-day \ - leapcrash set-tai set-2038 set-tz + leapcrash set-tai set-2038 set-tz rtctest_setdate include ../lib.mk diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c index 4230d30..f61170f 100644 --- a/tools/testing/selftests/timers/rtctest.c +++ b/tools/testing/selftests/timers/rtctest.c @@ -21,6 +21,9 @@ #include <stdlib.h> #include <errno.h> +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif /* * This expects the new RTC class driver framework, working with @@ -29,23 +32,84 @@ */ static const char default_rtc[] = "/dev/rtc0"; +static struct rtc_time cutoff_dates[] = { + { + .tm_year = 70, /* 1970 -1900 */ + .tm_mday = 1, + }, + /* signed time_t 19/01/2038 3:14:08 */ + { + .tm_year = 138, + .tm_mday = 19, + }, + { + .tm_year = 138, + .tm_mday = 20, + }, + { + .tm_year = 199, /* 2099 -1900 */ + .tm_mday = 1, + }, + { + .tm_year = 200, /* 2100 -1900 */ + .tm_mday = 1, + }, + /* unsigned time_t 07/02/2106 7:28:15*/ + { + .tm_year = 205, + .tm_mon = 1, + .tm_mday = 7, + }, + { + .tm_year = 206, + .tm_mon = 1, + .tm_mday = 8, + }, + /* signed time on 64bit in nanoseconds 12/04/2262 01:47:16*/ + { + .tm_year = 362, + .tm_mon = 3, + .tm_mday = 12, + }, + { + .tm_year = 362, /* 2262 -1900 */ + .tm_mon = 3, + .tm_mday = 13, + }, +}; + +static int compare_dates(struct rtc_time *a, struct rtc_time *b) +{ + if (a->tm_year != b->tm_year || + a->tm_mon != b->tm_mon || + a->tm_mday != b->tm_mday || + a->tm_hour != b->tm_hour || + a->tm_min != b->tm_min || + ((b->tm_sec - a->tm_sec) > 1)) + return 1; + + return 0; +} int main(int argc, char **argv) { - int i, fd, retval, irqcount = 0; + int i, fd, retval, irqcount = 0, dangerous = 0; unsigned long tmp, data; struct rtc_time rtc_tm; const char *rtc = default_rtc; struct timeval start, end, diff; switch (argc) { + case 3: + if (*argv[2] == 'd') + dangerous = 1; case 2: rtc = argv[1]; /* FALLTHROUGH */ case 1: break; default: - fprintf(stderr, "usage: rtctest [rtcdev]\n"); + fprintf(stderr, "usage: rtctest [rtcdev] [d]\n"); return 1; } @@ -202,7 +266,7 @@ test_PIE: /* not all RTCs support periodic IRQs */ if (errno == EINVAL) { fprintf(stderr, "\nNo periodic IRQ support\n"); - goto done; + goto test_DATE; } perror("RTC_IRQP_READ ioctl"); exit(errno); @@ -221,7 +285,7 @@ test_PIE: if (errno == EINVAL) { fprintf(stderr, "\n...Periodic IRQ rate is fixed\n"); - goto done; + goto test_DATE; } perror("RTC_IRQP_SET ioctl"); exit(errno); @@ -269,6 +333,62 @@ test_PIE: } } +test_DATE: + if (!dangerous) + goto done; + + fprintf(stderr, "\nTesting problematic dates\n"); + + for (i = 0; i < ARRAY_SIZE(cutoff_dates); i++) { + struct rtc_time current; + + /* Write the new date in RTC */ + retval = ioctl(fd, RTC_SET_TIME, &cutoff_dates[i]); + if (retval == -1) { + perror("RTC_SET_TIME ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_RD_TIME, ¤t); + if (retval == -1) { + perror("RTC_RD_TIME ioctl"); + exit(errno); + } + + if(compare_dates(&cutoff_dates[i], ¤t)) { + fprintf(stderr,"Setting date %d failed\n", + cutoff_dates[i].tm_year + 1900); + goto done; + } + + cutoff_dates[i].tm_sec += 5; + + /* Write the new alarm in RTC */ + retval = ioctl(fd, RTC_ALM_SET, &cutoff_dates[i]); + if (retval == -1) { + perror("RTC_ALM_SET ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_ALM_READ, ¤t); + if (retval == -1) { + perror("RTC_ALM_READ ioctl"); + exit(errno); + } + + if(compare_dates(&cutoff_dates[i], ¤t)) { + fprintf(stderr,"Setting alarm %d failed\n", + cutoff_dates[i].tm_year + 1900); + goto done; + } + + fprintf(stderr, "Setting year %d is OK \n", + cutoff_dates[i].tm_year + 1900); + } done: fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); diff --git a/tools/testing/selftests/timers/rtctest_setdate.c b/tools/testing/selftests/timers/rtctest_setdate.c new file mode 100644 index 0000000..2cb7848 --- /dev/null +++ b/tools/testing/selftests/timers/rtctest_setdate.c @@ -0,0 +1,86 @@ +/* Real Time Clock Driver Test + * by: Benjamin Gaignard (benjamin.gaignard@linaro.org) + * + * To build + * gcc rtctest_setdate.c -o rtctest_setdate + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <linux/rtc.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> + +static const char default_time[] = "00:00:00"; + +int main(int argc, char **argv) +{ + int fd, retval; + struct rtc_time new, current; + const char *rtc, *date; + const char *time = default_time; + + switch (argc) { + case 4: + time = argv[3]; + /* FALLTHROUGH */ + case 3: + date = argv[2]; + rtc = argv[1]; + break; + default: + fprintf(stderr, "usage: rtctest_setdate <rtcdev> <DD-MM-YYYY> [HH:MM:SS]\n"); + return 1; + } + + fd = open(rtc, O_RDONLY); + if (fd == -1) { + perror(rtc); + exit(errno); + } + + sscanf(date, "%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year); + new.tm_mon -= 1; + new.tm_year -= 1900; + sscanf(time, "%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec); + + fprintf(stderr, "Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n", + new.tm_mday, new.tm_mon + 1, new.tm_year + 1900, + new.tm_hour, new.tm_min, new.tm_sec); + + /* Write the new date in RTC */ + retval = ioctl(fd, RTC_SET_TIME, &new); + if (retval == -1) { + perror("RTC_SET_TIME ioctl"); + close(fd); + exit(errno); + } + + /* Read back */ + retval = ioctl(fd, RTC_RD_TIME, ¤t); + if (retval == -1) { + perror("RTC_RD_TIME ioctl"); + exit(errno); + } + + fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", + current.tm_mday, current.tm_mon + 1, current.tm_year + 1900, + current.tm_hour, current.tm_min, current.tm_sec); + + close(fd); + return 0; +} |