Skip to content

Commit

Permalink
syscalls/futex: Add support for time64 tests
Browse files Browse the repository at this point in the history
This adds support for time64 tests to the existing futex() syscall
tests.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
  • Loading branch information
vireshk authored and metan-ucw committed Jul 23, 2020
1 parent daf903e commit 8d2c9c7
Show file tree
Hide file tree
Showing 14 changed files with 542 additions and 587 deletions.
34 changes: 28 additions & 6 deletions testcases/kernel/syscalls/futex/futex_cmp_requeue01.c
Expand Up @@ -42,14 +42,29 @@ static struct tcase {
{1000, 300, 500},
};

static struct test_variants {
enum futex_fn_type fntype;
enum tst_ts_type tstype;
char *desc;
} variants[] = {
#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
#endif

#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
#endif
};

static void do_child(void)
{
struct test_variants *tv = &variants[tst_variant];
struct tst_ts usec = tst_ts_from_ms(tv->tstype, max_sleep_ms);
int slept_for_ms = 0;
struct timespec usec = tst_timespec_from_ms(max_sleep_ms);
int pid = getpid();
int ret = 0;

if (futex_wait(&sd->futexes[0], sd->futexes[0], &usec, 0) == -1) {
if (futex_wait(tv->fntype, &sd->futexes[0], sd->futexes[0], &usec, 0) == -1) {
if (errno == EAGAIN) {
/* spurious wakeup or signal */
tst_atomic_inc(&sd->spurious);
Expand All @@ -72,6 +87,7 @@ static void do_child(void)

static void verify_futex_cmp_requeue(unsigned int n)
{
struct test_variants *tv = &variants[tst_variant];
int num_requeues = 0, num_waits = 0, num_total = 0;
int i, status, spurious, woken_up;
struct tcase *tc = &tcases[n];
Expand Down Expand Up @@ -104,8 +120,8 @@ static void verify_futex_cmp_requeue(unsigned int n)
* specifies an upper limit on the number of waiters that are requeued.
* Returns the total number of waiters that were woken up or requeued.
*/
TEST(futex_cmp_requeue(&sd->futexes[0], sd->futexes[0], &sd->futexes[1],
tc->set_wakes, tc->set_requeues, 0));
TEST(futex_cmp_requeue(tv->fntype, &sd->futexes[0], sd->futexes[0],
&sd->futexes[1], tc->set_wakes, tc->set_requeues, 0));

/* Fail if more than requested wakes + requeues were returned */
if (TST_RET > exp_ret) {
Expand All @@ -115,8 +131,8 @@ static void verify_futex_cmp_requeue(unsigned int n)
tst_res(TINFO, "futex_cmp_requeue() returned %ld", TST_RET);
}

num_requeues = futex_wake(&sd->futexes[1], tc->num_waiters, 0);
num_waits = futex_wake(&sd->futexes[0], tc->num_waiters, 0);
num_requeues = futex_wake(tv->fntype, &sd->futexes[1], tc->num_waiters, 0);
num_waits = futex_wake(tv->fntype, &sd->futexes[0], tc->num_waiters, 0);

tst_atomic_store(1, &sd->test_done);
for (i = 0; i < tc->num_waiters; i++) {
Expand Down Expand Up @@ -178,6 +194,11 @@ static void verify_futex_cmp_requeue(unsigned int n)

static void setup(void)
{
struct test_variants *tv = &variants[tst_variant];

tst_res(TINFO, "Testing variant: %s", tv->desc);
futex_supported_by_kernel(tv->fntype);

max_sleep_ms = tst_multiply_timeout(5000);

sd = SAFE_MMAP(NULL, sizeof(*sd), PROT_READ | PROT_WRITE,
Expand All @@ -198,5 +219,6 @@ static struct tst_test test = {
.cleanup = cleanup,
.tcnt = ARRAY_SIZE(tcases),
.test = verify_futex_cmp_requeue,
.test_variants = ARRAY_SIZE(variants),
.forks_child = 1,
};
24 changes: 22 additions & 2 deletions testcases/kernel/syscalls/futex/futex_cmp_requeue02.c
Expand Up @@ -32,12 +32,26 @@ static struct tcase {
{1, 1, FUTEX_INITIALIZER + 1, EAGAIN},
};

static struct test_variants {
enum futex_fn_type fntype;
char *desc;
} variants[] = {
#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
#endif

#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
#endif
};

static void verify_futex_cmp_requeue(unsigned int n)
{
struct test_variants *tv = &variants[tst_variant];
struct tcase *tc = &tcases[n];

TEST(futex_cmp_requeue(&futexes[0], tc->exp_val, &futexes[1],
tc->set_wakes, tc->set_requeues, 0));
TEST(futex_cmp_requeue(tv->fntype, &futexes[0], tc->exp_val,
&futexes[1], tc->set_wakes, tc->set_requeues, 0));
if (TST_RET != -1) {
tst_res(TFAIL, "futex_cmp_requeue() succeeded unexpectedly");
return;
Expand All @@ -55,6 +69,11 @@ static void verify_futex_cmp_requeue(unsigned int n)

static void setup(void)
{
struct test_variants *tv = &variants[tst_variant];

tst_res(TINFO, "Testing variant: %s", tv->desc);
futex_supported_by_kernel(tv->fntype);

futexes = SAFE_MMAP(NULL, sizeof(futex_t) * 2, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, -1, 0);

Expand All @@ -73,6 +92,7 @@ static struct tst_test test = {
.cleanup = cleanup,
.test = verify_futex_cmp_requeue,
.tcnt = ARRAY_SIZE(tcases),
.test_variants = ARRAY_SIZE(variants),
.tags = (const struct tst_tag[]) {
{"CVE", "2018-6927"},
{"linux-git", "fbe0e839d1e2"},
Expand Down
23 changes: 13 additions & 10 deletions testcases/kernel/syscalls/futex/futex_utils.h
Expand Up @@ -20,10 +20,13 @@
#ifndef FUTEX_UTILS_H__
#define FUTEX_UTILS_H__

#include <stdio.h>
#include <stdlib.h>

/*
* Wait for nr_threads to be sleeping
*/
static int wait_for_threads(unsigned int nr_threads)
static inline int wait_for_threads(unsigned int nr_threads)
{
char thread_state, name[1024];
DIR *dir;
Expand All @@ -32,31 +35,31 @@ static int wait_for_threads(unsigned int nr_threads)

snprintf(name, sizeof(name), "/proc/%i/task/", getpid());

dir = SAFE_OPENDIR(NULL, name);
dir = SAFE_OPENDIR(name);

while ((dent = SAFE_READDIR(NULL, dir))) {
while ((dent = SAFE_READDIR(dir))) {
/* skip ".", ".." and the main thread */
if (atoi(dent->d_name) == getpid() || atoi(dent->d_name) == 0)
continue;

snprintf(name, sizeof(name), "/proc/%i/task/%s/stat",
getpid(), dent->d_name);
getpid(), dent->d_name);

SAFE_FILE_SCANF(NULL, name, "%*i %*s %c", &thread_state);
SAFE_FILE_SCANF(name, "%*i %*s %c", &thread_state);

if (thread_state != 'S') {
tst_resm(TINFO, "Thread %s not sleeping yet", dent->d_name);
SAFE_CLOSEDIR(NULL, dir);
tst_res(TINFO, "Thread %s not sleeping yet", dent->d_name);
SAFE_CLOSEDIR(dir);
return 1;
}
cnt++;
}

SAFE_CLOSEDIR(NULL, dir);
SAFE_CLOSEDIR(dir);

if (cnt != nr_threads) {
tst_resm(TINFO, "%u threads sleeping, expected %u",
cnt, nr_threads);
tst_res(TINFO, "%u threads sleeping, expected %u", cnt,
nr_threads);
}

return 0;
Expand Down
77 changes: 36 additions & 41 deletions testcases/kernel/syscalls/futex/futex_wait01.c
@@ -1,38 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
*
* Based on futextest (futext_wait_timeout.c and futex_wait_ewouldblock.c)
* written by Darren Hart <dvhltc@us.ibm.com>
* Gowrishankar <gowrishankar.m@in.ibm.com>
*
* Licensed under the GNU GPLv2 or later.
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* 1. Block on a futex and wait for timeout.
* 2. Test if FUTEX_WAIT op returns -EWOULDBLOCK if the futex value differs
* from the expected one.
*/
/*
* 1. Block on a futex and wait for timeout.
* 2. Test if FUTEX_WAIT op returns -EWOULDBLOCK if the futex value differs
* from the expected one.
*/

#include <errno.h>

#include "test.h"
#include "futextest.h"

const char *TCID="futex_wait01";

struct testcase {
futex_t *f_addr;
futex_t f_val;
Expand All @@ -41,7 +21,6 @@ struct testcase {
};

static futex_t futex = FUTEX_INITIALIZER;
static struct timespec to = {.tv_sec = 0, .tv_nsec = 10000};

static struct testcase testcases[] = {
{&futex, FUTEX_INITIALIZER, 0, ETIMEDOUT},
Expand All @@ -50,38 +29,54 @@ static struct testcase testcases[] = {
{&futex, FUTEX_INITIALIZER+1, FUTEX_PRIVATE_FLAG, EWOULDBLOCK},
};

const int TST_TOTAL=ARRAY_SIZE(testcases);
static struct test_variants {
enum futex_fn_type fntype;
enum tst_ts_type tstype;
char *desc;
} variants[] = {
#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
#endif

#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
{ .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
#endif
};

static void verify_futex_wait(struct testcase *tc)
static void run(unsigned int n)
{
struct test_variants *tv = &variants[tst_variant];
struct testcase *tc = &testcases[n];
struct tst_ts to = tst_ts_from_ns(tv->tstype, 10000);
int res;

res = futex_wait(tc->f_addr, tc->f_val, &to, tc->opflags);
res = futex_wait(tv->fntype, tc->f_addr, tc->f_val, &to, tc->opflags);

if (res != -1) {
tst_resm(TFAIL, "futex_wait() returned %i, expected -1", res);
tst_res(TFAIL, "futex_wait() succeeded unexpectedly");
return;
}

if (errno != tc->exp_errno) {
tst_resm(TFAIL | TERRNO, "expected errno=%s",
tst_res(TFAIL | TERRNO, "futex_wait() failed with incorrect error, expected errno=%s",
tst_strerrno(tc->exp_errno));
return;
}

tst_resm(TPASS | TERRNO, "futex_wait()");
tst_res(TPASS | TERRNO, "futex_wait() passed");
}

int main(int argc, char *argv[])
static void setup(void)
{
int lc, i;
struct test_variants *tv = &variants[tst_variant];

tst_parse_opts(argc, argv, NULL, NULL);

for (lc = 0; TEST_LOOPING(lc); lc++) {
for (i = 0; i < TST_TOTAL; i++)
verify_futex_wait(testcases + i);
}

tst_exit();
tst_res(TINFO, "Testing variant: %s", tv->desc);
futex_supported_by_kernel(tv->fntype);
}

static struct tst_test test = {
.setup = setup,
.test = run,
.tcnt = ARRAY_SIZE(testcases),
.test_variants = ARRAY_SIZE(variants),
};

0 comments on commit 8d2c9c7

Please sign in to comment.