Skip to content

Commit 64ff574

Browse files
amlutogregkh
authored andcommitted
selftests/x86: Add clock_gettime() tests to test_vdso
commit 7c03e70 upstream. Now that the vDSO implementation of clock_gettime() is getting reworked, add a selftest for it. This tests that its output is consistent with the syscall version. This is marked for stable to serve as a test for commit 715bd9d ("x86/vdso: Fix asm constraints on vDSO syscall fallbacks") Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/082399674de2619b2befd8c0dde49b260605b126.1538422295.git.luto@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 30500cc commit 64ff574

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

tools/testing/selftests/x86/test_vdso.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <errno.h>
1818
#include <sched.h>
1919
#include <stdbool.h>
20+
#include <limits.h>
2021

2122
#ifndef SYS_getcpu
2223
# ifdef __x86_64__
@@ -31,6 +32,10 @@
3132

3233
int nerrs = 0;
3334

35+
typedef int (*vgettime_t)(clockid_t, struct timespec *);
36+
37+
vgettime_t vdso_clock_gettime;
38+
3439
typedef long (*getcpu_t)(unsigned *, unsigned *, void *);
3540

3641
getcpu_t vgetcpu;
@@ -95,6 +100,10 @@ static void fill_function_pointers()
95100
printf("Warning: failed to find getcpu in vDSO\n");
96101

97102
vgetcpu = (getcpu_t) vsyscall_getcpu();
103+
104+
vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
105+
if (!vdso_clock_gettime)
106+
printf("Warning: failed to find clock_gettime in vDSO\n");
98107
}
99108

100109
static long sys_getcpu(unsigned * cpu, unsigned * node,
@@ -103,6 +112,11 @@ static long sys_getcpu(unsigned * cpu, unsigned * node,
103112
return syscall(__NR_getcpu, cpu, node, cache);
104113
}
105114

115+
static inline int sys_clock_gettime(clockid_t id, struct timespec *ts)
116+
{
117+
return syscall(__NR_clock_gettime, id, ts);
118+
}
119+
106120
static void test_getcpu(void)
107121
{
108122
printf("[RUN]\tTesting getcpu...\n");
@@ -155,10 +169,95 @@ static void test_getcpu(void)
155169
}
156170
}
157171

172+
static bool ts_leq(const struct timespec *a, const struct timespec *b)
173+
{
174+
if (a->tv_sec != b->tv_sec)
175+
return a->tv_sec < b->tv_sec;
176+
else
177+
return a->tv_nsec <= b->tv_nsec;
178+
}
179+
180+
static char const * const clocknames[] = {
181+
[0] = "CLOCK_REALTIME",
182+
[1] = "CLOCK_MONOTONIC",
183+
[2] = "CLOCK_PROCESS_CPUTIME_ID",
184+
[3] = "CLOCK_THREAD_CPUTIME_ID",
185+
[4] = "CLOCK_MONOTONIC_RAW",
186+
[5] = "CLOCK_REALTIME_COARSE",
187+
[6] = "CLOCK_MONOTONIC_COARSE",
188+
[7] = "CLOCK_BOOTTIME",
189+
[8] = "CLOCK_REALTIME_ALARM",
190+
[9] = "CLOCK_BOOTTIME_ALARM",
191+
[10] = "CLOCK_SGI_CYCLE",
192+
[11] = "CLOCK_TAI",
193+
};
194+
195+
static void test_one_clock_gettime(int clock, const char *name)
196+
{
197+
struct timespec start, vdso, end;
198+
int vdso_ret, end_ret;
199+
200+
printf("[RUN]\tTesting clock_gettime for clock %s (%d)...\n", name, clock);
201+
202+
if (sys_clock_gettime(clock, &start) < 0) {
203+
if (errno == EINVAL) {
204+
vdso_ret = vdso_clock_gettime(clock, &vdso);
205+
if (vdso_ret == -EINVAL) {
206+
printf("[OK]\tNo such clock.\n");
207+
} else {
208+
printf("[FAIL]\tNo such clock, but __vdso_clock_gettime returned %d\n", vdso_ret);
209+
nerrs++;
210+
}
211+
} else {
212+
printf("[WARN]\t clock_gettime(%d) syscall returned error %d\n", clock, errno);
213+
}
214+
return;
215+
}
216+
217+
vdso_ret = vdso_clock_gettime(clock, &vdso);
218+
end_ret = sys_clock_gettime(clock, &end);
219+
220+
if (vdso_ret != 0 || end_ret != 0) {
221+
printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n",
222+
vdso_ret, errno);
223+
nerrs++;
224+
return;
225+
}
226+
227+
printf("\t%llu.%09ld %llu.%09ld %llu.%09ld\n",
228+
(unsigned long long)start.tv_sec, start.tv_nsec,
229+
(unsigned long long)vdso.tv_sec, vdso.tv_nsec,
230+
(unsigned long long)end.tv_sec, end.tv_nsec);
231+
232+
if (!ts_leq(&start, &vdso) || !ts_leq(&vdso, &end)) {
233+
printf("[FAIL]\tTimes are out of sequence\n");
234+
nerrs++;
235+
}
236+
}
237+
238+
static void test_clock_gettime(void)
239+
{
240+
for (int clock = 0; clock < sizeof(clocknames) / sizeof(clocknames[0]);
241+
clock++) {
242+
test_one_clock_gettime(clock, clocknames[clock]);
243+
}
244+
245+
/* Also test some invalid clock ids */
246+
test_one_clock_gettime(-1, "invalid");
247+
test_one_clock_gettime(INT_MIN, "invalid");
248+
test_one_clock_gettime(INT_MAX, "invalid");
249+
}
250+
158251
int main(int argc, char **argv)
159252
{
160253
fill_function_pointers();
161254

255+
test_clock_gettime();
256+
257+
/*
258+
* Test getcpu() last so that, if something goes wrong setting affinity,
259+
* we still run the other tests.
260+
*/
162261
test_getcpu();
163262

164263
return nerrs ? 1 : 0;

0 commit comments

Comments
 (0)