linux-kselftest-5.9-rc1
This Kselftest update for Linux 5.9-rc1 consists of - TAP output reporting related fixes from Paolo Bonzini and Kees Cook. These fixes make it skip reporting consistent with TAP format. - Cleanup fixes to framework run_tests from Yauheni Kaliuta -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAl8p1akACgkQCwJExA0N QxwqKg/9HzbnpWeb736HAjeA3v0LFuPte8TELSerjKqfas+g9xQxhf+ReHaZXz9i KnhBPYyOb57DjnT7Mi7c5qGYzLKCvBF30OR0M1P5lRWBX3SC0VvkgdHzLpksIsHx 1wIht3gClvdOnHeHWWRG374iCbw86po8Xa5V9KOJOofbEKjctYjiShnd3OXXNLdJ h1/Ro+LffdsqO7VWoJruSuBplCXAVIr8IpUnOhtw/JTGlK7csNHBdHb7KTBm+zKU i0+f6H5uxRM3BA793OHen9D6kHAVLzhtPc7O0O1IhNRKnDgzY/UIS0qSGpxzD6KG +ZZ4FpvyfN2EPqgGegjdTNhQjPrjXpPos46FTNOM/qiQNYvCuvUFjRCAzVuN9cqU QzXdNPUOI7YLpOYpqLNqeefTXhZUxCWPF33oHPhU28W59qYpqQDRRDoOu7l9e7KQ DMwIKCaSw5qCB7S6x5LqOiQcc4/3xIbJVjO/CQU7G4cuREkAHqUvc2rfwCHcn60e rt2h/v2rnHzie4kTEukWKPuyHL64CL0jYTdHtFb/PbavnfbEPe3t6GiGu2DJN680 mem6+9Q12KTtY4VY6enBE4YHVlxQPksbp/o5G91evNuFul1ZsAFgWdR5t+iiMrCU d6u2m5H6dMShZYqTw98MU/PKAh31sQCNZqhruhZMgUOJEV7lP/s= =4uja -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull kselftest updates form Shuah Khan: - TAP output reporting related fixes from Paolo Bonzini and Kees Cook. These fixes make it skip reporting consistent with TAP format. - Cleanup fixes to framework run_tests from Yauheni Kaliuta * tag 'linux-kselftest-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (23 commits) selftests/harness: Limit step counter reporting selftests/seccomp: Check ENOSYS under tracing selftests/seccomp: Refactor to use fixture variants selftests/harness: Clean up kern-doc for fixtures selftests: kmod: Add module address visibility test Replace HTTP links with HTTPS ones: KMOD KERNEL MODULE LOADER - USERMODE HELPER selftests: fix condition in run_tests selftests: do not use .ONESHELL selftests: pidfd: skip test if unshare fails with EPERM selftests: pidfd: do not use ksft_exit_skip after ksft_set_plan selftests/harness: Report skip reason selftests/harness: Display signed values correctly selftests/harness: Refactor XFAIL into SKIP selftests/harness: Switch to TAP output selftests: Add header documentation and helpers selftests/binderfs: Fix harness API usage selftests: Remove unneeded selftest API headers selftests/clone3: Reorder reporting output selftests: sync_test: do not use ksft_exit_skip after ksft_set_plan selftests: sigaltstack: do not use ksft_exit_skip after ksft_set_plan ...
This commit is contained in:
commit
4834ce9d8e
tools/testing/selftests
breakpoints
clone3
filesystems/binderfs
kmod
kselftest.hkselftest
kselftest_harness.hlib.mkpid_namespace
pidfd
sigaltstack
sync
uevent
|
@ -47,7 +47,7 @@ void child(int cpu)
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool run_test(int cpu)
|
int run_test(int cpu)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
@ -55,7 +55,7 @@ bool run_test(int cpu)
|
||||||
|
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
ksft_print_msg("fork() failed: %s\n", strerror(errno));
|
ksft_print_msg("fork() failed: %s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
child(cpu);
|
child(cpu);
|
||||||
|
@ -63,67 +63,68 @@ bool run_test(int cpu)
|
||||||
wpid = waitpid(pid, &status, __WALL);
|
wpid = waitpid(pid, &status, __WALL);
|
||||||
if (wpid != pid) {
|
if (wpid != pid) {
|
||||||
ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
|
ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (!WIFSTOPPED(status)) {
|
if (!WIFSTOPPED(status)) {
|
||||||
ksft_print_msg("child did not stop: %s\n", strerror(errno));
|
ksft_print_msg("child did not stop: %s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (WSTOPSIG(status) != SIGSTOP) {
|
if (WSTOPSIG(status) != SIGSTOP) {
|
||||||
ksft_print_msg("child did not stop with SIGSTOP: %s\n",
|
ksft_print_msg("child did not stop with SIGSTOP: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
|
if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
|
||||||
if (errno == EIO) {
|
if (errno == EIO) {
|
||||||
ksft_exit_skip(
|
ksft_print_msg(
|
||||||
"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
|
"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
return KSFT_SKIP;
|
||||||
}
|
}
|
||||||
ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
|
ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpid = waitpid(pid, &status, __WALL);
|
wpid = waitpid(pid, &status, __WALL);
|
||||||
if (wpid != pid) {
|
if (wpid != pid) {
|
||||||
ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
|
ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
ksft_print_msg("child did not single-step: %s\n",
|
ksft_print_msg("child did not single-step: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (!WIFSTOPPED(status)) {
|
if (!WIFSTOPPED(status)) {
|
||||||
ksft_print_msg("child did not stop: %s\n", strerror(errno));
|
ksft_print_msg("child did not stop: %s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (WSTOPSIG(status) != SIGTRAP) {
|
if (WSTOPSIG(status) != SIGTRAP) {
|
||||||
ksft_print_msg("child did not stop with SIGTRAP: %s\n",
|
ksft_print_msg("child did not stop with SIGTRAP: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
|
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
|
||||||
ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
|
ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpid = waitpid(pid, &status, __WALL);
|
wpid = waitpid(pid, &status, __WALL);
|
||||||
if (wpid != pid) {
|
if (wpid != pid) {
|
||||||
ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
|
ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
if (!WIFEXITED(status)) {
|
if (!WIFEXITED(status)) {
|
||||||
ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
|
ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return KSFT_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void suspend(void)
|
void suspend(void)
|
||||||
|
@ -183,32 +184,38 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
|
|
||||||
if (!CPU_ISSET(cpu, &available_cpus))
|
|
||||||
continue;
|
|
||||||
tests++;
|
|
||||||
}
|
|
||||||
ksft_set_plan(tests);
|
|
||||||
|
|
||||||
if (do_suspend)
|
|
||||||
suspend();
|
|
||||||
|
|
||||||
err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
|
err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
ksft_exit_fail_msg("sched_getaffinity() failed\n");
|
ksft_exit_fail_msg("sched_getaffinity() failed\n");
|
||||||
|
|
||||||
for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
|
for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
|
||||||
bool test_success;
|
if (!CPU_ISSET(cpu, &available_cpus))
|
||||||
|
continue;
|
||||||
|
tests++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_suspend)
|
||||||
|
suspend();
|
||||||
|
|
||||||
|
ksft_set_plan(tests);
|
||||||
|
for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
|
||||||
|
int test_success;
|
||||||
|
|
||||||
if (!CPU_ISSET(cpu, &available_cpus))
|
if (!CPU_ISSET(cpu, &available_cpus))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
test_success = run_test(cpu);
|
test_success = run_test(cpu);
|
||||||
if (test_success) {
|
switch (test_success) {
|
||||||
|
case KSFT_PASS:
|
||||||
ksft_test_result_pass("CPU %d\n", cpu);
|
ksft_test_result_pass("CPU %d\n", cpu);
|
||||||
} else {
|
break;
|
||||||
|
case KSFT_SKIP:
|
||||||
|
ksft_test_result_skip("CPU %d\n", cpu);
|
||||||
|
break;
|
||||||
|
case KSFT_FAIL:
|
||||||
ksft_test_result_fail("CPU %d\n", cpu);
|
ksft_test_result_fail("CPU %d\n", cpu);
|
||||||
succeeded = false;
|
succeeded = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,9 +131,9 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
uid_t uid = getuid();
|
uid_t uid = getuid();
|
||||||
|
|
||||||
test_clone3_supported();
|
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
ksft_set_plan(17);
|
ksft_set_plan(17);
|
||||||
|
test_clone3_supported();
|
||||||
|
|
||||||
/* Just a simple clone3() should return 0.*/
|
/* Just a simple clone3() should return 0.*/
|
||||||
test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
|
test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST);
|
||||||
|
|
|
@ -119,9 +119,8 @@ static void test_clone3_clear_sighand(void)
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
test_clone3_supported();
|
|
||||||
|
|
||||||
ksft_set_plan(1);
|
ksft_set_plan(1);
|
||||||
|
test_clone3_supported();
|
||||||
|
|
||||||
test_clone3_clear_sighand();
|
test_clone3_clear_sighand();
|
||||||
|
|
||||||
|
|
|
@ -157,8 +157,8 @@ int main(int argc, char *argv[])
|
||||||
pid_t set_tid[MAX_PID_NS_LEVEL * 2];
|
pid_t set_tid[MAX_PID_NS_LEVEL * 2];
|
||||||
|
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
test_clone3_supported();
|
|
||||||
ksft_set_plan(29);
|
ksft_set_plan(29);
|
||||||
|
test_clone3_supported();
|
||||||
|
|
||||||
if (pipe(pipe_1) < 0 || pipe(pipe_2) < 0)
|
if (pipe(pipe_1) < 0 || pipe(pipe_2) < 0)
|
||||||
ksft_exit_fail_msg("pipe() failed\n");
|
ksft_exit_fail_msg("pipe() failed\n");
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/android/binder.h>
|
#include <linux/android/binder.h>
|
||||||
#include <linux/android/binderfs.h>
|
#include <linux/android/binderfs.h>
|
||||||
|
|
||||||
#include "../../kselftest.h"
|
|
||||||
#include "../../kselftest_harness.h"
|
#include "../../kselftest_harness.h"
|
||||||
|
|
||||||
#define DEFAULT_THREADS 4
|
#define DEFAULT_THREADS 4
|
||||||
|
@ -37,37 +36,26 @@
|
||||||
fd = -EBADF; \
|
fd = -EBADF; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define log_exit(format, ...) \
|
static void change_mountns(struct __test_metadata *_metadata)
|
||||||
({ \
|
|
||||||
fprintf(stderr, format "\n", ##__VA_ARGS__); \
|
|
||||||
exit(EXIT_FAILURE); \
|
|
||||||
})
|
|
||||||
|
|
||||||
static void change_mountns(void)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = unshare(CLONE_NEWNS);
|
ret = unshare(CLONE_NEWNS);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n",
|
TH_LOG("%s - Failed to unshare mount namespace",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
|
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("%s - Failed to mount / as private\n",
|
TH_LOG("%s - Failed to mount / as private",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rmdir_protect_errno(const char *dir)
|
static int __do_binderfs_test(struct __test_metadata *_metadata)
|
||||||
{
|
{
|
||||||
int saved_errno = errno;
|
int fd, ret, saved_errno, result = 1;
|
||||||
(void)rmdir(dir);
|
|
||||||
errno = saved_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __do_binderfs_test(void)
|
|
||||||
{
|
|
||||||
int fd, ret, saved_errno;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
ssize_t wret;
|
ssize_t wret;
|
||||||
struct binderfs_device device = { 0 };
|
struct binderfs_device device = { 0 };
|
||||||
|
@ -75,113 +63,107 @@ static int __do_binderfs_test(void)
|
||||||
char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
|
char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
|
||||||
device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
|
device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
|
||||||
|
|
||||||
change_mountns();
|
change_mountns(_metadata);
|
||||||
|
|
||||||
if (!mkdtemp(binderfs_mntpt))
|
EXPECT_NE(mkdtemp(binderfs_mntpt), NULL) {
|
||||||
ksft_exit_fail_msg(
|
TH_LOG("%s - Failed to create binderfs mountpoint",
|
||||||
"%s - Failed to create binderfs mountpoint\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
goto out;
|
||||||
ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno != ENODEV)
|
|
||||||
ksft_exit_fail_msg("%s - Failed to mount binderfs\n",
|
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* binderfs mount test passed */
|
ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
|
||||||
ksft_inc_pass_cnt();
|
EXPECT_EQ(ret, 0) {
|
||||||
|
if (errno == ENODEV)
|
||||||
|
XFAIL(goto out, "binderfs missing");
|
||||||
|
TH_LOG("%s - Failed to mount binderfs", strerror(errno));
|
||||||
|
goto rmdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success: binderfs mounted */
|
||||||
|
|
||||||
memcpy(device.name, "my-binder", strlen("my-binder"));
|
memcpy(device.name, "my-binder", strlen("my-binder"));
|
||||||
|
|
||||||
snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
|
snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
|
||||||
fd = open(device_path, O_RDONLY | O_CLOEXEC);
|
fd = open(device_path, O_RDONLY | O_CLOEXEC);
|
||||||
if (fd < 0)
|
EXPECT_GE(fd, 0) {
|
||||||
ksft_exit_fail_msg(
|
TH_LOG("%s - Failed to open binder-control device",
|
||||||
"%s - Failed to open binder-control device\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
goto umount;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ioctl(fd, BINDER_CTL_ADD, &device);
|
ret = ioctl(fd, BINDER_CTL_ADD, &device);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
if (ret < 0) {
|
EXPECT_GE(ret, 0) {
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
TH_LOG("%s - Failed to allocate new binder device",
|
||||||
ksft_exit_fail_msg(
|
|
||||||
"%s - Failed to allocate new binder device\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
goto umount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ksft_print_msg(
|
TH_LOG("Allocated new binder device with major %d, minor %d, and name %s",
|
||||||
"Allocated new binder device with major %d, minor %d, and name %s\n",
|
|
||||||
device.major, device.minor, device.name);
|
device.major, device.minor, device.name);
|
||||||
|
|
||||||
/* binder device allocation test passed */
|
/* success: binder device allocation */
|
||||||
ksft_inc_pass_cnt();
|
|
||||||
|
|
||||||
snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
|
snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
|
||||||
fd = open(device_path, O_CLOEXEC | O_RDONLY);
|
fd = open(device_path, O_CLOEXEC | O_RDONLY);
|
||||||
if (fd < 0) {
|
EXPECT_GE(fd, 0) {
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
TH_LOG("%s - Failed to open my-binder device",
|
||||||
ksft_exit_fail_msg("%s - Failed to open my-binder device\n",
|
strerror(errno));
|
||||||
strerror(errno));
|
goto umount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ioctl(fd, BINDER_VERSION, &version);
|
ret = ioctl(fd, BINDER_VERSION, &version);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
if (ret < 0) {
|
EXPECT_GE(ret, 0) {
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
TH_LOG("%s - Failed to open perform BINDER_VERSION request",
|
||||||
ksft_exit_fail_msg(
|
|
||||||
"%s - Failed to open perform BINDER_VERSION request\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
goto umount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ksft_print_msg("Detected binder version: %d\n",
|
TH_LOG("Detected binder version: %d", version.protocol_version);
|
||||||
version.protocol_version);
|
|
||||||
|
|
||||||
/* binder transaction with binderfs binder device passed */
|
/* success: binder transaction with binderfs binder device */
|
||||||
ksft_inc_pass_cnt();
|
|
||||||
|
|
||||||
ret = unlink(device_path);
|
ret = unlink(device_path);
|
||||||
if (ret < 0) {
|
EXPECT_EQ(ret, 0) {
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
TH_LOG("%s - Failed to delete binder device",
|
||||||
ksft_exit_fail_msg("%s - Failed to delete binder device\n",
|
strerror(errno));
|
||||||
strerror(errno));
|
goto umount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* binder device removal passed */
|
/* success: binder device removal */
|
||||||
ksft_inc_pass_cnt();
|
|
||||||
|
|
||||||
snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
|
snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
|
||||||
ret = unlink(device_path);
|
ret = unlink(device_path);
|
||||||
if (!ret) {
|
EXPECT_NE(ret, 0) {
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
TH_LOG("Managed to delete binder-control device");
|
||||||
ksft_exit_fail_msg("Managed to delete binder-control device\n");
|
goto umount;
|
||||||
} else if (errno != EPERM) {
|
}
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
EXPECT_EQ(errno, EPERM) {
|
||||||
ksft_exit_fail_msg(
|
TH_LOG("%s - Failed to delete binder-control device but exited with unexpected error code",
|
||||||
"%s - Failed to delete binder-control device but exited with unexpected error code\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
goto umount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* binder-control device removal failed as expected */
|
/* success: binder-control device removal failed as expected */
|
||||||
ksft_inc_xfail_cnt();
|
result = 0;
|
||||||
|
|
||||||
on_error:
|
umount:
|
||||||
ret = umount2(binderfs_mntpt, MNT_DETACH);
|
ret = umount2(binderfs_mntpt, MNT_DETACH);
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
EXPECT_EQ(ret, 0) {
|
||||||
if (ret < 0)
|
TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
|
||||||
ksft_exit_fail_msg("%s - Failed to unmount binderfs\n",
|
}
|
||||||
strerror(errno));
|
rmdir:
|
||||||
|
ret = rmdir(binderfs_mntpt);
|
||||||
/* binderfs unmount test passed */
|
EXPECT_EQ(ret, 0) {
|
||||||
ksft_inc_pass_cnt();
|
TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));
|
||||||
return 0;
|
}
|
||||||
|
out:
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_for_pid(pid_t pid)
|
static int wait_for_pid(pid_t pid)
|
||||||
|
@ -291,7 +273,7 @@ static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void change_userns(int syncfds[2])
|
static void change_userns(struct __test_metadata *_metadata, int syncfds[2])
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buf;
|
char buf;
|
||||||
|
@ -299,25 +281,29 @@ static void change_userns(int syncfds[2])
|
||||||
close_prot_errno_disarm(syncfds[1]);
|
close_prot_errno_disarm(syncfds[1]);
|
||||||
|
|
||||||
ret = unshare(CLONE_NEWUSER);
|
ret = unshare(CLONE_NEWUSER);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("%s - Failed to unshare user namespace\n",
|
TH_LOG("%s - Failed to unshare user namespace",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
ret = write_nointr(syncfds[0], "1", 1);
|
ret = write_nointr(syncfds[0], "1", 1);
|
||||||
if (ret != 1)
|
ASSERT_EQ(ret, 1) {
|
||||||
ksft_exit_fail_msg("write_nointr() failed\n");
|
TH_LOG("write_nointr() failed");
|
||||||
|
}
|
||||||
|
|
||||||
ret = read_nointr(syncfds[0], &buf, 1);
|
ret = read_nointr(syncfds[0], &buf, 1);
|
||||||
if (ret != 1)
|
ASSERT_EQ(ret, 1) {
|
||||||
ksft_exit_fail_msg("read_nointr() failed\n");
|
TH_LOG("read_nointr() failed");
|
||||||
|
}
|
||||||
|
|
||||||
close_prot_errno_disarm(syncfds[0]);
|
close_prot_errno_disarm(syncfds[0]);
|
||||||
|
|
||||||
if (setid_userns_root())
|
ASSERT_EQ(setid_userns_root(), 0) {
|
||||||
ksft_exit_fail_msg("setid_userns_root() failed");
|
TH_LOG("setid_userns_root() failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void change_idmaps(int syncfds[2], pid_t pid)
|
static void change_idmaps(struct __test_metadata *_metadata, int syncfds[2], pid_t pid)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buf;
|
char buf;
|
||||||
|
@ -326,35 +312,42 @@ static void change_idmaps(int syncfds[2], pid_t pid)
|
||||||
close_prot_errno_disarm(syncfds[0]);
|
close_prot_errno_disarm(syncfds[0]);
|
||||||
|
|
||||||
ret = read_nointr(syncfds[1], &buf, 1);
|
ret = read_nointr(syncfds[1], &buf, 1);
|
||||||
if (ret != 1)
|
ASSERT_EQ(ret, 1) {
|
||||||
ksft_exit_fail_msg("read_nointr() failed\n");
|
TH_LOG("read_nointr() failed");
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
|
snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
|
||||||
ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
|
ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
|
||||||
if (ret)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("write_id_mapping(UID_MAP) failed");
|
TH_LOG("write_id_mapping(UID_MAP) failed");
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
|
snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
|
||||||
ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
|
ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
|
||||||
if (ret)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("write_id_mapping(GID_MAP) failed");
|
TH_LOG("write_id_mapping(GID_MAP) failed");
|
||||||
|
}
|
||||||
|
|
||||||
ret = write_nointr(syncfds[1], "1", 1);
|
ret = write_nointr(syncfds[1], "1", 1);
|
||||||
if (ret != 1)
|
ASSERT_EQ(ret, 1) {
|
||||||
ksft_exit_fail_msg("write_nointr() failed");
|
TH_LOG("write_nointr() failed");
|
||||||
|
}
|
||||||
|
|
||||||
close_prot_errno_disarm(syncfds[1]);
|
close_prot_errno_disarm(syncfds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct __test_metadata *_thread_metadata;
|
||||||
static void *binder_version_thread(void *data)
|
static void *binder_version_thread(void *data)
|
||||||
{
|
{
|
||||||
|
struct __test_metadata *_metadata = _thread_metadata;
|
||||||
int fd = PTR_TO_INT(data);
|
int fd = PTR_TO_INT(data);
|
||||||
struct binder_version version = { 0 };
|
struct binder_version version = { 0 };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = ioctl(fd, BINDER_VERSION, &version);
|
ret = ioctl(fd, BINDER_VERSION, &version);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ksft_print_msg("%s - Failed to open perform BINDER_VERSION request\n", strerror(errno));
|
TH_LOG("%s - Failed to open perform BINDER_VERSION request\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
pthread_exit(data);
|
pthread_exit(data);
|
||||||
}
|
}
|
||||||
|
@ -377,68 +370,79 @@ TEST(binderfs_stress)
|
||||||
device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
|
device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
|
||||||
|
|
||||||
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
|
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
|
TH_LOG("%s - Failed to create socket pair", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
ASSERT_GE(pid, 0) {
|
||||||
|
TH_LOG("%s - Failed to fork", strerror(errno));
|
||||||
close_prot_errno_disarm(syncfds[0]);
|
close_prot_errno_disarm(syncfds[0]);
|
||||||
close_prot_errno_disarm(syncfds[1]);
|
close_prot_errno_disarm(syncfds[1]);
|
||||||
ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int i, j, k, nthreads;
|
int i, j, k, nthreads;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pthread_t threads[DEFAULT_THREADS];
|
pthread_t threads[DEFAULT_THREADS];
|
||||||
change_userns(syncfds);
|
change_userns(_metadata, syncfds);
|
||||||
change_mountns();
|
change_mountns(_metadata);
|
||||||
|
|
||||||
if (!mkdtemp(binderfs_mntpt))
|
ASSERT_NE(mkdtemp(binderfs_mntpt), NULL) {
|
||||||
log_exit("%s - Failed to create binderfs mountpoint\n",
|
TH_LOG("%s - Failed to create binderfs mountpoint",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
|
ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
log_exit("%s - Failed to mount binderfs\n", strerror(errno));
|
TH_LOG("%s - Failed to mount binderfs", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(fds); i++) {
|
for (int i = 0; i < ARRAY_SIZE(fds); i++) {
|
||||||
|
|
||||||
snprintf(device_path, sizeof(device_path),
|
snprintf(device_path, sizeof(device_path),
|
||||||
"%s/binder-control", binderfs_mntpt);
|
"%s/binder-control", binderfs_mntpt);
|
||||||
fd = open(device_path, O_RDONLY | O_CLOEXEC);
|
fd = open(device_path, O_RDONLY | O_CLOEXEC);
|
||||||
if (fd < 0)
|
ASSERT_GE(fd, 0) {
|
||||||
log_exit("%s - Failed to open binder-control device\n", strerror(errno));
|
TH_LOG("%s - Failed to open binder-control device",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
memset(&device, 0, sizeof(device));
|
memset(&device, 0, sizeof(device));
|
||||||
snprintf(device.name, sizeof(device.name), "%d", i);
|
snprintf(device.name, sizeof(device.name), "%d", i);
|
||||||
ret = ioctl(fd, BINDER_CTL_ADD, &device);
|
ret = ioctl(fd, BINDER_CTL_ADD, &device);
|
||||||
close_prot_errno_disarm(fd);
|
close_prot_errno_disarm(fd);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
log_exit("%s - Failed to allocate new binder device\n", strerror(errno));
|
TH_LOG("%s - Failed to allocate new binder device",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(device_path, sizeof(device_path), "%s/%d",
|
snprintf(device_path, sizeof(device_path), "%s/%d",
|
||||||
binderfs_mntpt, i);
|
binderfs_mntpt, i);
|
||||||
fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
|
fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
|
||||||
if (fds[i] < 0)
|
ASSERT_GE(fds[i], 0) {
|
||||||
log_exit("%s - Failed to open binder device\n", strerror(errno));
|
TH_LOG("%s - Failed to open binder device", strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = umount2(binderfs_mntpt, MNT_DETACH);
|
ret = umount2(binderfs_mntpt, MNT_DETACH);
|
||||||
rmdir_protect_errno(binderfs_mntpt);
|
ASSERT_EQ(ret, 0) {
|
||||||
if (ret < 0)
|
TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
|
||||||
log_exit("%s - Failed to unmount binderfs\n", strerror(errno));
|
rmdir(binderfs_mntpt);
|
||||||
|
}
|
||||||
|
|
||||||
nthreads = get_nprocs_conf();
|
nthreads = get_nprocs_conf();
|
||||||
if (nthreads > DEFAULT_THREADS)
|
if (nthreads > DEFAULT_THREADS)
|
||||||
nthreads = DEFAULT_THREADS;
|
nthreads = DEFAULT_THREADS;
|
||||||
|
|
||||||
|
_thread_metadata = _metadata;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
for (k = 0; k < ARRAY_SIZE(fds); k++) {
|
for (k = 0; k < ARRAY_SIZE(fds); k++) {
|
||||||
for (i = 0; i < nthreads; i++) {
|
for (i = 0; i < nthreads; i++) {
|
||||||
ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
|
ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ksft_print_msg("%s - Failed to create thread %d\n", strerror(errno), i);
|
TH_LOG("%s - Failed to create thread %d",
|
||||||
|
strerror(errno), i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +452,8 @@ TEST(binderfs_stress)
|
||||||
|
|
||||||
ret = pthread_join(threads[j], &fdptr);
|
ret = pthread_join(threads[j], &fdptr);
|
||||||
if (ret)
|
if (ret)
|
||||||
ksft_print_msg("%s - Failed to join thread %d for fd %d\n", strerror(errno), j, PTR_TO_INT(fdptr));
|
TH_LOG("%s - Failed to join thread %d for fd %d",
|
||||||
|
strerror(errno), j, PTR_TO_INT(fdptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
|
@ -459,11 +464,12 @@ TEST(binderfs_stress)
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
change_idmaps(syncfds, pid);
|
change_idmaps(_metadata, syncfds, pid);
|
||||||
|
|
||||||
ret = wait_for_pid(pid);
|
ret = wait_for_pid(pid);
|
||||||
if (ret)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("wait_for_pid() failed");
|
TH_LOG("wait_for_pid() failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(binderfs_test_privileged)
|
TEST(binderfs_test_privileged)
|
||||||
|
@ -471,7 +477,7 @@ TEST(binderfs_test_privileged)
|
||||||
if (geteuid() != 0)
|
if (geteuid() != 0)
|
||||||
XFAIL(return, "Tests are not run as root. Skipping privileged tests");
|
XFAIL(return, "Tests are not run as root. Skipping privileged tests");
|
||||||
|
|
||||||
if (__do_binderfs_test() == 1)
|
if (__do_binderfs_test(_metadata))
|
||||||
XFAIL(return, "The Android binderfs filesystem is not available");
|
XFAIL(return, "The Android binderfs filesystem is not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,31 +488,33 @@ TEST(binderfs_test_unprivileged)
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
|
ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
|
||||||
if (ret < 0)
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
|
TH_LOG("%s - Failed to create socket pair", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
ASSERT_GE(pid, 0) {
|
||||||
close_prot_errno_disarm(syncfds[0]);
|
close_prot_errno_disarm(syncfds[0]);
|
||||||
close_prot_errno_disarm(syncfds[1]);
|
close_prot_errno_disarm(syncfds[1]);
|
||||||
ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
|
TH_LOG("%s - Failed to fork", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
change_userns(syncfds);
|
change_userns(_metadata, syncfds);
|
||||||
if (__do_binderfs_test() == 1)
|
if (__do_binderfs_test(_metadata))
|
||||||
exit(2);
|
exit(2);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
change_idmaps(syncfds, pid);
|
change_idmaps(_metadata, syncfds, pid);
|
||||||
|
|
||||||
ret = wait_for_pid(pid);
|
ret = wait_for_pid(pid);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == 2)
|
if (ret == 2)
|
||||||
XFAIL(return, "The Android binderfs filesystem is not available");
|
XFAIL(return, "The Android binderfs filesystem is not available");
|
||||||
else
|
ASSERT_EQ(ret, 0) {
|
||||||
ksft_exit_fail_msg("wait_for_pid() failed");
|
TH_LOG("wait_for_pid() failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ test_reqs()
|
||||||
if [[ $KMOD_VERSION -le 19 ]]; then
|
if [[ $KMOD_VERSION -le 19 ]]; then
|
||||||
echo "$0: You need at least kmod 20" >&2
|
echo "$0: You need at least kmod 20" >&2
|
||||||
echo "kmod <= 19 is buggy, for details see:" >&2
|
echo "kmod <= 19 is buggy, for details see:" >&2
|
||||||
echo "http://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2
|
echo "https://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2
|
||||||
exit $ksft_skip
|
exit $ksft_skip
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,43 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* kselftest.h: kselftest framework return codes to include from
|
* kselftest.h: low-level kselftest framework to include from
|
||||||
* selftests.
|
* selftest programs. When possible, please use
|
||||||
|
* kselftest_harness.h instead.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 Shuah Khan <shuahkh@osg.samsung.com>
|
* Copyright (c) 2014 Shuah Khan <shuahkh@osg.samsung.com>
|
||||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||||
*
|
*
|
||||||
|
* Using this API consists of first counting how many tests your code
|
||||||
|
* has to run, and then starting up the reporting:
|
||||||
|
*
|
||||||
|
* ksft_print_header();
|
||||||
|
* ksft_set_plan(total_number_of_tests);
|
||||||
|
*
|
||||||
|
* For each test, report any progress, debugging, etc with:
|
||||||
|
*
|
||||||
|
* ksft_print_msg(fmt, ...);
|
||||||
|
*
|
||||||
|
* and finally report the pass/fail/skip/xfail state of the test with one of:
|
||||||
|
*
|
||||||
|
* ksft_test_result(condition, fmt, ...);
|
||||||
|
* ksft_test_result_pass(fmt, ...);
|
||||||
|
* ksft_test_result_fail(fmt, ...);
|
||||||
|
* ksft_test_result_skip(fmt, ...);
|
||||||
|
* ksft_test_result_xfail(fmt, ...);
|
||||||
|
* ksft_test_result_error(fmt, ...);
|
||||||
|
*
|
||||||
|
* When all tests are finished, clean up and exit the program with one of:
|
||||||
|
*
|
||||||
|
* ksft_exit(condition);
|
||||||
|
* ksft_exit_pass();
|
||||||
|
* ksft_exit_fail();
|
||||||
|
*
|
||||||
|
* If the program wants to report details on why the entire program has
|
||||||
|
* failed, it can instead exit with a message (this is usually done when
|
||||||
|
* the program is aborting before finishing all tests):
|
||||||
|
*
|
||||||
|
* ksft_exit_fail_msg(fmt, ...);
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __KSELFTEST_H
|
#ifndef __KSELFTEST_H
|
||||||
#define __KSELFTEST_H
|
#define __KSELFTEST_H
|
||||||
|
@ -74,7 +106,7 @@ static inline void ksft_print_cnts(void)
|
||||||
if (ksft_plan != ksft_test_num())
|
if (ksft_plan != ksft_test_num())
|
||||||
printf("# Planned tests != run tests (%u != %u)\n",
|
printf("# Planned tests != run tests (%u != %u)\n",
|
||||||
ksft_plan, ksft_test_num());
|
ksft_plan, ksft_test_num());
|
||||||
printf("# Pass %d Fail %d Xfail %d Xpass %d Skip %d Error %d\n",
|
printf("# Totals: pass:%d fail:%d xfail:%d xpass:%d skip:%d error:%d\n",
|
||||||
ksft_cnt.ksft_pass, ksft_cnt.ksft_fail,
|
ksft_cnt.ksft_pass, ksft_cnt.ksft_fail,
|
||||||
ksft_cnt.ksft_xfail, ksft_cnt.ksft_xpass,
|
ksft_cnt.ksft_xfail, ksft_cnt.ksft_xpass,
|
||||||
ksft_cnt.ksft_xskip, ksft_cnt.ksft_error);
|
ksft_cnt.ksft_xskip, ksft_cnt.ksft_error);
|
||||||
|
@ -120,6 +152,32 @@ static inline void ksft_test_result_fail(const char *msg, ...)
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ksft_test_result() - Report test success based on truth of condition
|
||||||
|
*
|
||||||
|
* @condition: if true, report test success, otherwise failure.
|
||||||
|
*/
|
||||||
|
#define ksft_test_result(condition, fmt, ...) do { \
|
||||||
|
if (!!(condition)) \
|
||||||
|
ksft_test_result_pass(fmt, ##__VA_ARGS__);\
|
||||||
|
else \
|
||||||
|
ksft_test_result_fail(fmt, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline void ksft_test_result_xfail(const char *msg, ...)
|
||||||
|
{
|
||||||
|
int saved_errno = errno;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
ksft_cnt.ksft_xfail++;
|
||||||
|
|
||||||
|
va_start(args, msg);
|
||||||
|
printf("ok %d # XFAIL ", ksft_test_num());
|
||||||
|
errno = saved_errno;
|
||||||
|
vprintf(msg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void ksft_test_result_skip(const char *msg, ...)
|
static inline void ksft_test_result_skip(const char *msg, ...)
|
||||||
{
|
{
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
|
@ -128,12 +186,13 @@ static inline void ksft_test_result_skip(const char *msg, ...)
|
||||||
ksft_cnt.ksft_xskip++;
|
ksft_cnt.ksft_xskip++;
|
||||||
|
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
printf("not ok %d # SKIP ", ksft_test_num());
|
printf("ok %d # SKIP ", ksft_test_num());
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
vprintf(msg, args);
|
vprintf(msg, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: how does "error" differ from "fail" or "skip"? */
|
||||||
static inline void ksft_test_result_error(const char *msg, ...)
|
static inline void ksft_test_result_error(const char *msg, ...)
|
||||||
{
|
{
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
|
@ -156,11 +215,22 @@ static inline int ksft_exit_pass(void)
|
||||||
|
|
||||||
static inline int ksft_exit_fail(void)
|
static inline int ksft_exit_fail(void)
|
||||||
{
|
{
|
||||||
printf("Bail out!\n");
|
|
||||||
ksft_print_cnts();
|
ksft_print_cnts();
|
||||||
exit(KSFT_FAIL);
|
exit(KSFT_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ksft_exit() - Exit selftest based on truth of condition
|
||||||
|
*
|
||||||
|
* @condition: if true, exit self test with success, otherwise fail.
|
||||||
|
*/
|
||||||
|
#define ksft_exit(condition) do { \
|
||||||
|
if (!!(condition)) \
|
||||||
|
ksft_exit_pass(); \
|
||||||
|
else \
|
||||||
|
ksft_exit_fail(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static inline int ksft_exit_fail_msg(const char *msg, ...)
|
static inline int ksft_exit_fail_msg(const char *msg, ...)
|
||||||
{
|
{
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
|
@ -190,18 +260,30 @@ static inline int ksft_exit_xpass(void)
|
||||||
|
|
||||||
static inline int ksft_exit_skip(const char *msg, ...)
|
static inline int ksft_exit_skip(const char *msg, ...)
|
||||||
{
|
{
|
||||||
if (msg) {
|
int saved_errno = errno;
|
||||||
int saved_errno = errno;
|
va_list args;
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
printf("not ok %d # SKIP ", 1 + ksft_test_num());
|
|
||||||
|
/*
|
||||||
|
* FIXME: several tests misuse ksft_exit_skip so produce
|
||||||
|
* something sensible if some tests have already been run
|
||||||
|
* or a plan has been printed. Those tests should use
|
||||||
|
* ksft_test_result_skip or ksft_exit_fail_msg instead.
|
||||||
|
*/
|
||||||
|
if (ksft_plan || ksft_test_num()) {
|
||||||
|
ksft_cnt.ksft_xskip++;
|
||||||
|
printf("ok %d # SKIP ", 1 + ksft_test_num());
|
||||||
|
} else {
|
||||||
|
printf("1..0 # SKIP ");
|
||||||
|
}
|
||||||
|
if (msg) {
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
vprintf(msg, args);
|
vprintf(msg, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
} else {
|
|
||||||
ksft_print_cnts();
|
|
||||||
}
|
}
|
||||||
|
if (ksft_test_num())
|
||||||
|
ksft_print_cnts();
|
||||||
exit(KSFT_SKIP);
|
exit(KSFT_SKIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ run_one()
|
||||||
echo "ok $test_num $TEST_HDR_MSG") ||
|
echo "ok $test_num $TEST_HDR_MSG") ||
|
||||||
(rc=$?; \
|
(rc=$?; \
|
||||||
if [ $rc -eq $skip_rc ]; then \
|
if [ $rc -eq $skip_rc ]; then \
|
||||||
echo "not ok $test_num $TEST_HDR_MSG # SKIP"
|
echo "ok $test_num $TEST_HDR_MSG # SKIP"
|
||||||
elif [ $rc -eq $timeout_rc ]; then \
|
elif [ $rc -eq $timeout_rc ]; then \
|
||||||
echo "#"
|
echo "#"
|
||||||
echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT"
|
echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT"
|
||||||
|
|
|
@ -50,7 +50,9 @@
|
||||||
#ifndef __KSELFTEST_HARNESS_H
|
#ifndef __KSELFTEST_HARNESS_H
|
||||||
#define __KSELFTEST_HARNESS_H
|
#define __KSELFTEST_HARNESS_H
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -58,10 +60,13 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "kselftest.h"
|
||||||
|
|
||||||
#define TEST_TIMEOUT_DEFAULT 30
|
#define TEST_TIMEOUT_DEFAULT 30
|
||||||
|
|
||||||
/* Utilities exposed to the test definitions */
|
/* Utilities exposed to the test definitions */
|
||||||
|
@ -104,26 +109,28 @@
|
||||||
|
|
||||||
/* Unconditional logger for internal use. */
|
/* Unconditional logger for internal use. */
|
||||||
#define __TH_LOG(fmt, ...) \
|
#define __TH_LOG(fmt, ...) \
|
||||||
fprintf(TH_LOG_STREAM, "%s:%d:%s:" fmt "\n", \
|
fprintf(TH_LOG_STREAM, "# %s:%d:%s:" fmt "\n", \
|
||||||
__FILE__, __LINE__, _metadata->name, ##__VA_ARGS__)
|
__FILE__, __LINE__, _metadata->name, ##__VA_ARGS__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XFAIL(statement, fmt, ...)
|
* SKIP(statement, fmt, ...)
|
||||||
*
|
*
|
||||||
* @statement: statement to run after reporting XFAIL
|
* @statement: statement to run after reporting SKIP
|
||||||
* @fmt: format string
|
* @fmt: format string
|
||||||
* @...: optional arguments
|
* @...: optional arguments
|
||||||
*
|
*
|
||||||
* This forces a "pass" after reporting a failure with an XFAIL prefix,
|
* This forces a "pass" after reporting why something is being skipped
|
||||||
* and runs "statement", which is usually "return" or "goto skip".
|
* and runs "statement", which is usually "return" or "goto skip".
|
||||||
*/
|
*/
|
||||||
#define XFAIL(statement, fmt, ...) do { \
|
#define SKIP(statement, fmt, ...) do { \
|
||||||
|
snprintf(_metadata->results->reason, \
|
||||||
|
sizeof(_metadata->results->reason), fmt, ##__VA_ARGS__); \
|
||||||
if (TH_LOG_ENABLED) { \
|
if (TH_LOG_ENABLED) { \
|
||||||
fprintf(TH_LOG_STREAM, "[ XFAIL! ] " fmt "\n", \
|
fprintf(TH_LOG_STREAM, "# SKIP %s\n", \
|
||||||
##__VA_ARGS__); \
|
_metadata->results->reason); \
|
||||||
} \
|
} \
|
||||||
/* TODO: find a way to pass xfail to test runner process. */ \
|
|
||||||
_metadata->passed = 1; \
|
_metadata->passed = 1; \
|
||||||
|
_metadata->skip = 1; \
|
||||||
_metadata->trigger = 0; \
|
_metadata->trigger = 0; \
|
||||||
statement; \
|
statement; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -673,20 +680,53 @@
|
||||||
__bail(_assert, _metadata->no_print, _metadata->step))
|
__bail(_assert, _metadata->no_print, _metadata->step))
|
||||||
|
|
||||||
#define __INC_STEP(_metadata) \
|
#define __INC_STEP(_metadata) \
|
||||||
if (_metadata->passed && _metadata->step < 255) \
|
/* Keep "step" below 255 (which is used for "SKIP" reporting). */ \
|
||||||
|
if (_metadata->passed && _metadata->step < 253) \
|
||||||
_metadata->step++;
|
_metadata->step++;
|
||||||
|
|
||||||
|
#define is_signed_type(var) (!!(((__typeof__(var))(-1)) < (__typeof__(var))1))
|
||||||
|
|
||||||
#define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
|
#define __EXPECT(_expected, _expected_str, _seen, _seen_str, _t, _assert) do { \
|
||||||
/* Avoid multiple evaluation of the cases */ \
|
/* Avoid multiple evaluation of the cases */ \
|
||||||
__typeof__(_expected) __exp = (_expected); \
|
__typeof__(_expected) __exp = (_expected); \
|
||||||
__typeof__(_seen) __seen = (_seen); \
|
__typeof__(_seen) __seen = (_seen); \
|
||||||
if (_assert) __INC_STEP(_metadata); \
|
if (_assert) __INC_STEP(_metadata); \
|
||||||
if (!(__exp _t __seen)) { \
|
if (!(__exp _t __seen)) { \
|
||||||
unsigned long long __exp_print = (uintptr_t)__exp; \
|
/* Report with actual signedness to avoid weird output. */ \
|
||||||
unsigned long long __seen_print = (uintptr_t)__seen; \
|
switch (is_signed_type(__exp) * 2 + is_signed_type(__seen)) { \
|
||||||
__TH_LOG("Expected %s (%llu) %s %s (%llu)", \
|
case 0: { \
|
||||||
_expected_str, __exp_print, #_t, \
|
unsigned long long __exp_print = (uintptr_t)__exp; \
|
||||||
_seen_str, __seen_print); \
|
unsigned long long __seen_print = (uintptr_t)__seen; \
|
||||||
|
__TH_LOG("Expected %s (%llu) %s %s (%llu)", \
|
||||||
|
_expected_str, __exp_print, #_t, \
|
||||||
|
_seen_str, __seen_print); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case 1: { \
|
||||||
|
unsigned long long __exp_print = (uintptr_t)__exp; \
|
||||||
|
long long __seen_print = (intptr_t)__seen; \
|
||||||
|
__TH_LOG("Expected %s (%llu) %s %s (%lld)", \
|
||||||
|
_expected_str, __exp_print, #_t, \
|
||||||
|
_seen_str, __seen_print); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case 2: { \
|
||||||
|
long long __exp_print = (intptr_t)__exp; \
|
||||||
|
unsigned long long __seen_print = (uintptr_t)__seen; \
|
||||||
|
__TH_LOG("Expected %s (%lld) %s %s (%llu)", \
|
||||||
|
_expected_str, __exp_print, #_t, \
|
||||||
|
_seen_str, __seen_print); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case 3: { \
|
||||||
|
long long __exp_print = (intptr_t)__exp; \
|
||||||
|
long long __seen_print = (intptr_t)__seen; \
|
||||||
|
__TH_LOG("Expected %s (%lld) %s %s (%lld)", \
|
||||||
|
_expected_str, __exp_print, #_t, \
|
||||||
|
_seen_str, __seen_print); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
_metadata->passed = 0; \
|
_metadata->passed = 0; \
|
||||||
/* Ensure the optional handler is triggered */ \
|
/* Ensure the optional handler is triggered */ \
|
||||||
_metadata->trigger = 1; \
|
_metadata->trigger = 1; \
|
||||||
|
@ -727,6 +767,10 @@
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct __test_results {
|
||||||
|
char reason[1024]; /* Reason for test result */
|
||||||
|
};
|
||||||
|
|
||||||
struct __test_metadata;
|
struct __test_metadata;
|
||||||
struct __fixture_variant_metadata;
|
struct __fixture_variant_metadata;
|
||||||
|
|
||||||
|
@ -774,11 +818,13 @@ struct __test_metadata {
|
||||||
struct __fixture_metadata *fixture;
|
struct __fixture_metadata *fixture;
|
||||||
int termsig;
|
int termsig;
|
||||||
int passed;
|
int passed;
|
||||||
|
int skip; /* did SKIP get used? */
|
||||||
int trigger; /* extra handler after the evaluation */
|
int trigger; /* extra handler after the evaluation */
|
||||||
int timeout; /* seconds to wait for test timeout */
|
int timeout; /* seconds to wait for test timeout */
|
||||||
bool timed_out; /* did this test timeout instead of exiting? */
|
bool timed_out; /* did this test timeout instead of exiting? */
|
||||||
__u8 step;
|
__u8 step;
|
||||||
bool no_print; /* manual trigger when TH_LOG_STREAM is not available */
|
bool no_print; /* manual trigger when TH_LOG_STREAM is not available */
|
||||||
|
struct __test_results *results;
|
||||||
struct __test_metadata *prev, *next;
|
struct __test_metadata *prev, *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -814,12 +860,12 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext)
|
||||||
/* Sanity check handler execution environment. */
|
/* Sanity check handler execution environment. */
|
||||||
if (!t) {
|
if (!t) {
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"no active test in SIGALRM handler!?\n");
|
"# no active test in SIGALRM handler!?\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
if (sig != SIGALRM || sig != info->si_signo) {
|
if (sig != SIGALRM || sig != info->si_signo) {
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: SIGALRM handler caught signal %d!?\n",
|
"# %s: SIGALRM handler caught signal %d!?\n",
|
||||||
t->name, sig != SIGALRM ? sig : info->si_signo);
|
t->name, sig != SIGALRM ? sig : info->si_signo);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -840,7 +886,7 @@ void __wait_for_test(struct __test_metadata *t)
|
||||||
if (sigaction(SIGALRM, &action, &saved_action)) {
|
if (sigaction(SIGALRM, &action, &saved_action)) {
|
||||||
t->passed = 0;
|
t->passed = 0;
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: unable to install SIGALRM handler\n",
|
"# %s: unable to install SIGALRM handler\n",
|
||||||
t->name);
|
t->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -852,7 +898,7 @@ void __wait_for_test(struct __test_metadata *t)
|
||||||
if (sigaction(SIGALRM, &saved_action, NULL)) {
|
if (sigaction(SIGALRM, &saved_action, NULL)) {
|
||||||
t->passed = 0;
|
t->passed = 0;
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: unable to uninstall SIGALRM handler\n",
|
"# %s: unable to uninstall SIGALRM handler\n",
|
||||||
t->name);
|
t->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -861,39 +907,51 @@ void __wait_for_test(struct __test_metadata *t)
|
||||||
if (t->timed_out) {
|
if (t->timed_out) {
|
||||||
t->passed = 0;
|
t->passed = 0;
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: Test terminated by timeout\n", t->name);
|
"# %s: Test terminated by timeout\n", t->name);
|
||||||
} else if (WIFEXITED(status)) {
|
} else if (WIFEXITED(status)) {
|
||||||
t->passed = t->termsig == -1 ? !WEXITSTATUS(status) : 0;
|
|
||||||
if (t->termsig != -1) {
|
if (t->termsig != -1) {
|
||||||
|
t->passed = 0;
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: Test exited normally "
|
"# %s: Test exited normally instead of by signal (code: %d)\n",
|
||||||
"instead of by signal (code: %d)\n",
|
|
||||||
t->name,
|
|
||||||
WEXITSTATUS(status));
|
|
||||||
} else if (!t->passed) {
|
|
||||||
fprintf(TH_LOG_STREAM,
|
|
||||||
"%s: Test failed at step #%d\n",
|
|
||||||
t->name,
|
t->name,
|
||||||
WEXITSTATUS(status));
|
WEXITSTATUS(status));
|
||||||
|
} else {
|
||||||
|
switch (WEXITSTATUS(status)) {
|
||||||
|
/* Success */
|
||||||
|
case 0:
|
||||||
|
t->passed = 1;
|
||||||
|
break;
|
||||||
|
/* SKIP */
|
||||||
|
case 255:
|
||||||
|
t->passed = 1;
|
||||||
|
t->skip = 1;
|
||||||
|
break;
|
||||||
|
/* Other failure, assume step report. */
|
||||||
|
default:
|
||||||
|
t->passed = 0;
|
||||||
|
fprintf(TH_LOG_STREAM,
|
||||||
|
"# %s: Test failed at step #%d\n",
|
||||||
|
t->name,
|
||||||
|
WEXITSTATUS(status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
t->passed = 0;
|
t->passed = 0;
|
||||||
if (WTERMSIG(status) == SIGABRT) {
|
if (WTERMSIG(status) == SIGABRT) {
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: Test terminated by assertion\n",
|
"# %s: Test terminated by assertion\n",
|
||||||
t->name);
|
t->name);
|
||||||
} else if (WTERMSIG(status) == t->termsig) {
|
} else if (WTERMSIG(status) == t->termsig) {
|
||||||
t->passed = 1;
|
t->passed = 1;
|
||||||
} else {
|
} else {
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: Test terminated unexpectedly "
|
"# %s: Test terminated unexpectedly by signal %d\n",
|
||||||
"by signal %d\n",
|
|
||||||
t->name,
|
t->name,
|
||||||
WTERMSIG(status));
|
WTERMSIG(status));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(TH_LOG_STREAM,
|
fprintf(TH_LOG_STREAM,
|
||||||
"%s: Test ended in some other way [%u]\n",
|
"# %s: Test ended in some other way [%u]\n",
|
||||||
t->name,
|
t->name,
|
||||||
status);
|
status);
|
||||||
}
|
}
|
||||||
|
@ -905,25 +963,39 @@ void __run_test(struct __fixture_metadata *f,
|
||||||
{
|
{
|
||||||
/* reset test struct */
|
/* reset test struct */
|
||||||
t->passed = 1;
|
t->passed = 1;
|
||||||
|
t->skip = 0;
|
||||||
t->trigger = 0;
|
t->trigger = 0;
|
||||||
t->step = 0;
|
t->step = 0;
|
||||||
t->no_print = 0;
|
t->no_print = 0;
|
||||||
|
memset(t->results->reason, 0, sizeof(t->results->reason));
|
||||||
|
|
||||||
printf("[ RUN ] %s%s%s.%s\n",
|
ksft_print_msg(" RUN %s%s%s.%s ...\n",
|
||||||
f->name, variant->name[0] ? "." : "", variant->name, t->name);
|
f->name, variant->name[0] ? "." : "", variant->name, t->name);
|
||||||
t->pid = fork();
|
t->pid = fork();
|
||||||
if (t->pid < 0) {
|
if (t->pid < 0) {
|
||||||
printf("ERROR SPAWNING TEST CHILD\n");
|
ksft_print_msg("ERROR SPAWNING TEST CHILD\n");
|
||||||
t->passed = 0;
|
t->passed = 0;
|
||||||
} else if (t->pid == 0) {
|
} else if (t->pid == 0) {
|
||||||
t->fn(t, variant);
|
t->fn(t, variant);
|
||||||
/* return the step that failed or 0 */
|
if (t->skip)
|
||||||
_exit(t->passed ? 0 : t->step);
|
_exit(255);
|
||||||
|
/* Pass is exit 0 */
|
||||||
|
if (t->passed)
|
||||||
|
_exit(0);
|
||||||
|
/* Something else happened, report the step. */
|
||||||
|
_exit(t->step);
|
||||||
} else {
|
} else {
|
||||||
__wait_for_test(t);
|
__wait_for_test(t);
|
||||||
}
|
}
|
||||||
printf("[ %4s ] %s%s%s.%s\n", (t->passed ? "OK" : "FAIL"),
|
ksft_print_msg(" %4s %s%s%s.%s\n", t->passed ? "OK" : "FAIL",
|
||||||
f->name, variant->name[0] ? "." : "", variant->name, t->name);
|
f->name, variant->name[0] ? "." : "", variant->name, t->name);
|
||||||
|
|
||||||
|
if (t->skip)
|
||||||
|
ksft_test_result_skip("%s\n", t->results->reason[0] ?
|
||||||
|
t->results->reason : "unknown");
|
||||||
|
else
|
||||||
|
ksft_test_result(t->passed, "%s%s%s.%s\n",
|
||||||
|
f->name, variant->name[0] ? "." : "", variant->name, t->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_harness_run(int __attribute__((unused)) argc,
|
static int test_harness_run(int __attribute__((unused)) argc,
|
||||||
|
@ -932,6 +1004,7 @@ static int test_harness_run(int __attribute__((unused)) argc,
|
||||||
struct __fixture_variant_metadata no_variant = { .name = "", };
|
struct __fixture_variant_metadata no_variant = { .name = "", };
|
||||||
struct __fixture_variant_metadata *v;
|
struct __fixture_variant_metadata *v;
|
||||||
struct __fixture_metadata *f;
|
struct __fixture_metadata *f;
|
||||||
|
struct __test_results *results;
|
||||||
struct __test_metadata *t;
|
struct __test_metadata *t;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int case_count = 0, test_count = 0;
|
unsigned int case_count = 0, test_count = 0;
|
||||||
|
@ -946,14 +1019,20 @@ static int test_harness_run(int __attribute__((unused)) argc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO(wad) add optional arguments similar to gtest. */
|
results = mmap(NULL, sizeof(*results), PROT_READ | PROT_WRITE,
|
||||||
printf("[==========] Running %u tests from %u test cases.\n",
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
|
|
||||||
|
ksft_print_header();
|
||||||
|
ksft_set_plan(test_count);
|
||||||
|
ksft_print_msg("Starting %u tests from %u test cases.\n",
|
||||||
test_count, case_count);
|
test_count, case_count);
|
||||||
for (f = __fixture_list; f; f = f->next) {
|
for (f = __fixture_list; f; f = f->next) {
|
||||||
for (v = f->variant ?: &no_variant; v; v = v->next) {
|
for (v = f->variant ?: &no_variant; v; v = v->next) {
|
||||||
for (t = f->tests; t; t = t->next) {
|
for (t = f->tests; t; t = t->next) {
|
||||||
count++;
|
count++;
|
||||||
|
t->results = results;
|
||||||
__run_test(f, v, t);
|
__run_test(f, v, t);
|
||||||
|
t->results = NULL;
|
||||||
if (t->passed)
|
if (t->passed)
|
||||||
pass_count++;
|
pass_count++;
|
||||||
else
|
else
|
||||||
|
@ -961,9 +1040,14 @@ static int test_harness_run(int __attribute__((unused)) argc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("[==========] %u / %u tests passed.\n", pass_count, count);
|
munmap(results, sizeof(*results));
|
||||||
printf("[ %s ]\n", (ret ? "FAILED" : "PASSED"));
|
|
||||||
return ret;
|
ksft_print_msg("%s: %u / %u tests passed.\n", ret ? "FAILED" : "PASSED",
|
||||||
|
pass_count, count);
|
||||||
|
ksft_exit(ret == 0);
|
||||||
|
|
||||||
|
/* unreachable */
|
||||||
|
return KSFT_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((constructor)) __constructor_order_first(void)
|
static void __attribute__((constructor)) __constructor_order_first(void)
|
||||||
|
|
|
@ -59,9 +59,8 @@ else
|
||||||
all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
|
all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.ONESHELL:
|
|
||||||
define RUN_TESTS
|
define RUN_TESTS
|
||||||
@BASE_DIR="$(selfdir)"; \
|
BASE_DIR="$(selfdir)"; \
|
||||||
. $(selfdir)/kselftest/runner.sh; \
|
. $(selfdir)/kselftest/runner.sh; \
|
||||||
if [ "X$(summary)" != "X" ]; then \
|
if [ "X$(summary)" != "X" ]; then \
|
||||||
per_test_logging=1; \
|
per_test_logging=1; \
|
||||||
|
@ -71,22 +70,21 @@ endef
|
||||||
|
|
||||||
run_tests: all
|
run_tests: all
|
||||||
ifdef building_out_of_srctree
|
ifdef building_out_of_srctree
|
||||||
@if [ "X$(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)" != "X" ]; then
|
@if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \
|
||||||
@rsync -aq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT)
|
rsync -aq $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) $(OUTPUT); \
|
||||||
fi
|
fi
|
||||||
@if [ "X$(TEST_PROGS)" != "X" ]; then
|
@if [ "X$(TEST_PROGS)" != "X" ]; then \
|
||||||
$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(OUTPUT)/$(TEST_PROGS))
|
$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(OUTPUT)/$(TEST_PROGS)) ; \
|
||||||
else
|
else \
|
||||||
$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS))
|
$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS)); \
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
|
@$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
define INSTALL_SINGLE_RULE
|
define INSTALL_SINGLE_RULE
|
||||||
$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
|
$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
|
||||||
$(if $(INSTALL_LIST),@echo rsync -a $(INSTALL_LIST) $(INSTALL_PATH)/)
|
$(if $(INSTALL_LIST),rsync -a $(INSTALL_LIST) $(INSTALL_PATH)/)
|
||||||
$(if $(INSTALL_LIST),@rsync -a $(INSTALL_LIST) $(INSTALL_PATH)/)
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define INSTALL_RULE
|
define INSTALL_RULE
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "../kselftest.h"
|
|
||||||
#include "../kselftest_harness.h"
|
#include "../kselftest_harness.h"
|
||||||
#include "../pidfd/pidfd.h"
|
#include "../pidfd/pidfd.h"
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <linux/kcmp.h>
|
#include <linux/kcmp.h>
|
||||||
|
|
||||||
#include "pidfd.h"
|
#include "pidfd.h"
|
||||||
#include "../kselftest.h"
|
|
||||||
#include "../kselftest_harness.h"
|
#include "../kselftest_harness.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#include "pidfd.h"
|
#include "pidfd.h"
|
||||||
#include "../clone3/clone3_selftests.h"
|
#include "../clone3/clone3_selftests.h"
|
||||||
#include "../kselftest.h"
|
|
||||||
#include "../kselftest_harness.h"
|
#include "../kselftest_harness.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
|
@ -27,6 +28,8 @@
|
||||||
|
|
||||||
#define MAX_EVENTS 5
|
#define MAX_EVENTS 5
|
||||||
|
|
||||||
|
static bool have_pidfd_send_signal;
|
||||||
|
|
||||||
static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
|
static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
|
||||||
{
|
{
|
||||||
size_t stack_size = 1024;
|
size_t stack_size = 1024;
|
||||||
|
@ -56,6 +59,13 @@ static int test_pidfd_send_signal_simple_success(void)
|
||||||
int pidfd, ret;
|
int pidfd, ret;
|
||||||
const char *test_name = "pidfd_send_signal send SIGUSR1";
|
const char *test_name = "pidfd_send_signal send SIGUSR1";
|
||||||
|
|
||||||
|
if (!have_pidfd_send_signal) {
|
||||||
|
ksft_test_result_skip(
|
||||||
|
"%s test: pidfd_send_signal() syscall not supported\n",
|
||||||
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
|
pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
|
||||||
if (pidfd < 0)
|
if (pidfd < 0)
|
||||||
ksft_exit_fail_msg(
|
ksft_exit_fail_msg(
|
||||||
|
@ -86,6 +96,13 @@ static int test_pidfd_send_signal_exited_fail(void)
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
const char *test_name = "pidfd_send_signal signal exited process";
|
const char *test_name = "pidfd_send_signal signal exited process";
|
||||||
|
|
||||||
|
if (!have_pidfd_send_signal) {
|
||||||
|
ksft_test_result_skip(
|
||||||
|
"%s test: pidfd_send_signal() syscall not supported\n",
|
||||||
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
ksft_exit_fail_msg("%s test: Failed to create new process\n",
|
ksft_exit_fail_msg("%s test: Failed to create new process\n",
|
||||||
|
@ -137,16 +154,34 @@ static int test_pidfd_send_signal_recycled_pid_fail(void)
|
||||||
pid_t pid1;
|
pid_t pid1;
|
||||||
const char *test_name = "pidfd_send_signal signal recycled pid";
|
const char *test_name = "pidfd_send_signal signal recycled pid";
|
||||||
|
|
||||||
|
if (!have_pidfd_send_signal) {
|
||||||
|
ksft_test_result_skip(
|
||||||
|
"%s test: pidfd_send_signal() syscall not supported\n",
|
||||||
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ret = unshare(CLONE_NEWPID);
|
ret = unshare(CLONE_NEWPID);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
if (errno == EPERM) {
|
||||||
|
ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n",
|
||||||
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n",
|
ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n",
|
||||||
test_name);
|
test_name);
|
||||||
|
}
|
||||||
|
|
||||||
ret = unshare(CLONE_NEWNS);
|
ret = unshare(CLONE_NEWNS);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
ksft_exit_fail_msg(
|
if (errno == EPERM) {
|
||||||
"%s test: Failed to unshare mount namespace\n",
|
ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n",
|
||||||
test_name);
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n",
|
||||||
|
test_name);
|
||||||
|
}
|
||||||
|
|
||||||
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
|
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -325,15 +360,17 @@ static int test_pidfd_send_signal_syscall_support(void)
|
||||||
|
|
||||||
ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
|
ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == ENOSYS)
|
if (errno == ENOSYS) {
|
||||||
ksft_exit_skip(
|
ksft_test_result_skip(
|
||||||
"%s test: pidfd_send_signal() syscall not supported\n",
|
"%s test: pidfd_send_signal() syscall not supported\n",
|
||||||
test_name);
|
test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
ksft_exit_fail_msg("%s test: Failed to send signal\n",
|
ksft_exit_fail_msg("%s test: Failed to send signal\n",
|
||||||
test_name);
|
test_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_pidfd_send_signal = true;
|
||||||
close(pidfd);
|
close(pidfd);
|
||||||
ksft_test_result_pass(
|
ksft_test_result_pass(
|
||||||
"%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n",
|
"%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n",
|
||||||
|
@ -521,7 +558,7 @@ static void test_pidfd_poll_leader_exit(int use_waitpid)
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
ksft_set_plan(4);
|
ksft_set_plan(8);
|
||||||
|
|
||||||
test_pidfd_poll_exec(0);
|
test_pidfd_poll_exec(0);
|
||||||
test_pidfd_poll_exec(1);
|
test_pidfd_poll_exec(1);
|
||||||
|
|
|
@ -71,7 +71,7 @@ void my_usr1(int sig, siginfo_t *si, void *u)
|
||||||
swapcontext(&sc, &uc);
|
swapcontext(&sc, &uc);
|
||||||
ksft_print_msg("%s\n", p->msg);
|
ksft_print_msg("%s\n", p->msg);
|
||||||
if (!p->flag) {
|
if (!p->flag) {
|
||||||
ksft_exit_skip("[RUN]\tAborting\n");
|
ksft_exit_fail_msg("[RUN]\tAborting\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ int main(void)
|
||||||
err = sigaltstack(&stk, NULL);
|
err = sigaltstack(&stk, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
ksft_exit_skip(
|
ksft_test_result_skip(
|
||||||
"[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
|
"[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
|
||||||
/*
|
/*
|
||||||
* If test cases for the !SS_AUTODISARM variant were
|
* If test cases for the !SS_AUTODISARM variant were
|
||||||
|
|
|
@ -86,9 +86,9 @@ int main(void)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
ksft_set_plan(3 + 7);
|
|
||||||
|
|
||||||
sync_api_supported();
|
sync_api_supported();
|
||||||
|
ksft_set_plan(3 + 7);
|
||||||
|
|
||||||
ksft_print_msg("[RUN]\tTesting sync framework\n");
|
ksft_print_msg("[RUN]\tTesting sync framework\n");
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../kselftest.h"
|
|
||||||
#include "../kselftest_harness.h"
|
#include "../kselftest_harness.h"
|
||||||
|
|
||||||
#define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
|
#define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
|
||||||
|
|
Loading…
Reference in New Issue