Merge branch 'akpm' (patches from Andrew)

Merge misc updates from Andrew Morton:

 - a few misc things

 - ocfs2 updates

 - most of MM

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (159 commits)
  tools/testing/selftests/proc/proc-self-syscall.c: remove duplicate include
  proc: more robust bulk read test
  proc: test /proc/*/maps, smaps, smaps_rollup, statm
  proc: use seq_puts() everywhere
  proc: read kernel cpu stat pointer once
  proc: remove unused argument in proc_pid_lookup()
  fs/proc/thread_self.c: code cleanup for proc_setup_thread_self()
  fs/proc/self.c: code cleanup for proc_setup_self()
  proc: return exit code 4 for skipped tests
  mm,mremap: bail out earlier in mremap_to under map pressure
  mm/sparse: fix a bad comparison
  mm/memory.c: do_fault: avoid usage of stale vm_area_struct
  writeback: fix inode cgroup switching comment
  mm/huge_memory.c: fix "orig_pud" set but not used
  mm/hotplug: fix an imbalance with DEBUG_PAGEALLOC
  mm/memcontrol.c: fix bad line in comment
  mm/cma.c: cma_declare_contiguous: correct err handling
  mm/page_ext.c: fix an imbalance with kmemleak
  mm/compaction: pass pgdat to too_many_isolated() instead of zone
  mm: remove zone_lru_lock() function, access ->lru_lock directly
  ...
This commit is contained in:
Linus Torvalds
2019-03-06 10:31:36 -08:00
213 changed files with 4924 additions and 2321 deletions

View File

@@ -48,6 +48,7 @@ TARGETS += sysctl
ifneq (1, $(quicktest))
TARGETS += timers
endif
TARGETS += tmpfs
TARGETS += user
TARGETS += vm
TARGETS += x86

View File

@@ -54,6 +54,22 @@ static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
return fd;
}
static int mfd_assert_reopen_fd(int fd_in)
{
int r, fd;
char path[100];
sprintf(path, "/proc/self/fd/%d", fd_in);
fd = open(path, O_RDWR);
if (fd < 0) {
printf("re-open of existing fd %d failed\n", fd_in);
abort();
}
return fd;
}
static void mfd_fail_new(const char *name, unsigned int flags)
{
int r;
@@ -255,6 +271,25 @@ static void mfd_assert_read(int fd)
munmap(p, mfd_def_size);
}
/* Test that PROT_READ + MAP_SHARED mappings work. */
static void mfd_assert_read_shared(int fd)
{
void *p;
/* verify PROT_READ and MAP_SHARED *is* allowed */
p = mmap(NULL,
mfd_def_size,
PROT_READ,
MAP_SHARED,
fd,
0);
if (p == MAP_FAILED) {
printf("mmap() failed: %m\n");
abort();
}
munmap(p, mfd_def_size);
}
static void mfd_assert_write(int fd)
{
ssize_t l;
@@ -692,6 +727,44 @@ static void test_seal_write(void)
close(fd);
}
/*
* Test SEAL_FUTURE_WRITE
* Test whether SEAL_FUTURE_WRITE actually prevents modifications.
*/
static void test_seal_future_write(void)
{
int fd, fd2;
void *p;
printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
fd = mfd_assert_new("kern_memfd_seal_future_write",
mfd_def_size,
MFD_CLOEXEC | MFD_ALLOW_SEALING);
p = mfd_assert_mmap_shared(fd);
mfd_assert_has_seals(fd, 0);
mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
/* read should pass, writes should fail */
mfd_assert_read(fd);
mfd_assert_read_shared(fd);
mfd_fail_write(fd);
fd2 = mfd_assert_reopen_fd(fd);
/* read should pass, writes should still fail */
mfd_assert_read(fd2);
mfd_assert_read_shared(fd2);
mfd_fail_write(fd2);
munmap(p, mfd_def_size);
close(fd2);
close(fd);
}
/*
* Test SEAL_SHRINK
* Test whether SEAL_SHRINK actually prevents shrinking
@@ -945,6 +1018,7 @@ int main(int argc, char **argv)
test_basic();
test_seal_write();
test_seal_future_write();
test_seal_shrink();
test_seal_grow();
test_seal_resize();

View File

@@ -2,6 +2,7 @@
/fd-002-posix-eq
/fd-003-kthread
/proc-loadavg-001
/proc-pid-vm
/proc-self-map-files-001
/proc-self-map-files-002
/proc-self-syscall

View File

@@ -6,6 +6,7 @@ TEST_GEN_PROGS += fd-001-lookup
TEST_GEN_PROGS += fd-002-posix-eq
TEST_GEN_PROGS += fd-003-kthread
TEST_GEN_PROGS += proc-loadavg-001
TEST_GEN_PROGS += proc-pid-vm
TEST_GEN_PROGS += proc-self-map-files-001
TEST_GEN_PROGS += proc-self-map-files-002
TEST_GEN_PROGS += proc-self-syscall

View File

@@ -30,7 +30,7 @@ int main(void)
if (unshare(CLONE_NEWPID) == -1) {
if (errno == ENOSYS || errno == EPERM)
return 2;
return 4;
return 1;
}

View File

@@ -0,0 +1,406 @@
/*
* Copyright (c) 2019 Alexey Dobriyan <adobriyan@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Fork and exec tiny 1 page executable which precisely controls its VM.
* Test /proc/$PID/maps
* Test /proc/$PID/smaps
* Test /proc/$PID/smaps_rollup
* Test /proc/$PID/statm
*
* FIXME require CONFIG_TMPFS which can be disabled
* FIXME test other values from "smaps"
* FIXME support other archs
*/
#undef NDEBUG
#include <assert.h>
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <linux/kdev_t.h>
static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags)
{
return syscall(SYS_execveat, dirfd, pathname, argv, envp, flags);
}
static void make_private_tmp(void)
{
if (unshare(CLONE_NEWNS) == -1) {
if (errno == ENOSYS || errno == EPERM) {
exit(4);
}
exit(1);
}
if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) == -1) {
exit(1);
}
if (mount(NULL, "/tmp", "tmpfs", 0, NULL) == -1) {
exit(1);
}
}
static pid_t pid = -1;
static void ate(void)
{
if (pid > 0) {
kill(pid, SIGTERM);
}
}
struct elf64_hdr {
uint8_t e_ident[16];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint64_t e_entry;
uint64_t e_phoff;
uint64_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
struct elf64_phdr {
uint32_t p_type;
uint32_t p_flags;
uint64_t p_offset;
uint64_t p_vaddr;
uint64_t p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align;
};
#ifdef __x86_64__
#define PAGE_SIZE 4096
#define VADDR (1UL << 32)
#define MAPS_OFFSET 73
#define syscall 0x0f, 0x05
#define mov_rdi(x) \
0x48, 0xbf, \
(x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \
((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, ((x)>>56)&0xff
#define mov_rsi(x) \
0x48, 0xbe, \
(x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \
((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, ((x)>>56)&0xff
#define mov_eax(x) \
0xb8, (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff
static const uint8_t payload[] = {
/* Casually unmap stack, vDSO and everything else. */
/* munmap */
mov_rdi(VADDR + 4096),
mov_rsi((1ULL << 47) - 4096 - VADDR - 4096),
mov_eax(11),
syscall,
/* Ping parent. */
/* write(0, &c, 1); */
0x31, 0xff, /* xor edi, edi */
0x48, 0x8d, 0x35, 0x00, 0x00, 0x00, 0x00, /* lea rsi, [rip] */
0xba, 0x01, 0x00, 0x00, 0x00, /* mov edx, 1 */
mov_eax(1),
syscall,
/* 1: pause(); */
mov_eax(34),
syscall,
0xeb, 0xf7, /* jmp 1b */
};
static int make_exe(const uint8_t *payload, size_t len)
{
struct elf64_hdr h;
struct elf64_phdr ph;
struct iovec iov[3] = {
{&h, sizeof(struct elf64_hdr)},
{&ph, sizeof(struct elf64_phdr)},
{(void *)payload, len},
};
int fd, fd1;
char buf[64];
memset(&h, 0, sizeof(h));
h.e_ident[0] = 0x7f;
h.e_ident[1] = 'E';
h.e_ident[2] = 'L';
h.e_ident[3] = 'F';
h.e_ident[4] = 2;
h.e_ident[5] = 1;
h.e_ident[6] = 1;
h.e_ident[7] = 0;
h.e_type = 2;
h.e_machine = 0x3e;
h.e_version = 1;
h.e_entry = VADDR + sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr);
h.e_phoff = sizeof(struct elf64_hdr);
h.e_shoff = 0;
h.e_flags = 0;
h.e_ehsize = sizeof(struct elf64_hdr);
h.e_phentsize = sizeof(struct elf64_phdr);
h.e_phnum = 1;
h.e_shentsize = 0;
h.e_shnum = 0;
h.e_shstrndx = 0;
memset(&ph, 0, sizeof(ph));
ph.p_type = 1;
ph.p_flags = (1<<2)|1;
ph.p_offset = 0;
ph.p_vaddr = VADDR;
ph.p_paddr = 0;
ph.p_filesz = sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + sizeof(payload);
ph.p_memsz = sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + sizeof(payload);
ph.p_align = 4096;
fd = openat(AT_FDCWD, "/tmp", O_WRONLY|O_EXCL|O_TMPFILE, 0700);
if (fd == -1) {
exit(1);
}
if (writev(fd, iov, 3) != sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + len) {
exit(1);
}
/* Avoid ETXTBSY on exec. */
snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd);
fd1 = open(buf, O_RDONLY|O_CLOEXEC);
close(fd);
return fd1;
}
#endif
#ifdef __x86_64__
int main(void)
{
int pipefd[2];
int exec_fd;
atexit(ate);
make_private_tmp();
/* Reserve fd 0 for 1-byte pipe ping from child. */
close(0);
if (open("/", O_RDONLY|O_DIRECTORY|O_PATH) != 0) {
return 1;
}
exec_fd = make_exe(payload, sizeof(payload));
if (pipe(pipefd) == -1) {
return 1;
}
if (dup2(pipefd[1], 0) != 0) {
return 1;
}
pid = fork();
if (pid == -1) {
return 1;
}
if (pid == 0) {
sys_execveat(exec_fd, "", NULL, NULL, AT_EMPTY_PATH);
return 1;
}
char _;
if (read(pipefd[0], &_, 1) != 1) {
return 1;
}
struct stat st;
if (fstat(exec_fd, &st) == -1) {
return 1;
}
/* Generate "head -n1 /proc/$PID/maps" */
char buf0[256];
memset(buf0, ' ', sizeof(buf0));
int len = snprintf(buf0, sizeof(buf0),
"%08lx-%08lx r-xp 00000000 %02lx:%02lx %llu",
VADDR, VADDR + PAGE_SIZE,
MAJOR(st.st_dev), MINOR(st.st_dev),
(unsigned long long)st.st_ino);
buf0[len] = ' ';
snprintf(buf0 + MAPS_OFFSET, sizeof(buf0) - MAPS_OFFSET,
"/tmp/#%llu (deleted)\n", (unsigned long long)st.st_ino);
/* Test /proc/$PID/maps */
{
char buf[256];
ssize_t rv;
int fd;
snprintf(buf, sizeof(buf), "/proc/%u/maps", pid);
fd = open(buf, O_RDONLY);
if (fd == -1) {
return 1;
}
rv = read(fd, buf, sizeof(buf));
assert(rv == strlen(buf0));
assert(memcmp(buf, buf0, strlen(buf0)) == 0);
}
/* Test /proc/$PID/smaps */
{
char buf[1024];
ssize_t rv;
int fd;
snprintf(buf, sizeof(buf), "/proc/%u/smaps", pid);
fd = open(buf, O_RDONLY);
if (fd == -1) {
return 1;
}
rv = read(fd, buf, sizeof(buf));
assert(0 <= rv && rv <= sizeof(buf));
assert(rv >= strlen(buf0));
assert(memcmp(buf, buf0, strlen(buf0)) == 0);
#define RSS1 "Rss: 4 kB\n"
#define RSS2 "Rss: 0 kB\n"
#define PSS1 "Pss: 4 kB\n"
#define PSS2 "Pss: 0 kB\n"
assert(memmem(buf, rv, RSS1, strlen(RSS1)) ||
memmem(buf, rv, RSS2, strlen(RSS2)));
assert(memmem(buf, rv, PSS1, strlen(PSS1)) ||
memmem(buf, rv, PSS2, strlen(PSS2)));
static const char *S[] = {
"Size: 4 kB\n",
"KernelPageSize: 4 kB\n",
"MMUPageSize: 4 kB\n",
"Anonymous: 0 kB\n",
"AnonHugePages: 0 kB\n",
"Shared_Hugetlb: 0 kB\n",
"Private_Hugetlb: 0 kB\n",
"Locked: 0 kB\n",
};
int i;
for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
assert(memmem(buf, rv, S[i], strlen(S[i])));
}
}
/* Test /proc/$PID/smaps_rollup */
{
char bufr[256];
memset(bufr, ' ', sizeof(bufr));
len = snprintf(bufr, sizeof(bufr),
"%08lx-%08lx ---p 00000000 00:00 0",
VADDR, VADDR + PAGE_SIZE);
bufr[len] = ' ';
snprintf(bufr + MAPS_OFFSET, sizeof(bufr) - MAPS_OFFSET,
"[rollup]\n");
char buf[1024];
ssize_t rv;
int fd;
snprintf(buf, sizeof(buf), "/proc/%u/smaps_rollup", pid);
fd = open(buf, O_RDONLY);
if (fd == -1) {
return 1;
}
rv = read(fd, buf, sizeof(buf));
assert(0 <= rv && rv <= sizeof(buf));
assert(rv >= strlen(bufr));
assert(memcmp(buf, bufr, strlen(bufr)) == 0);
assert(memmem(buf, rv, RSS1, strlen(RSS1)) ||
memmem(buf, rv, RSS2, strlen(RSS2)));
assert(memmem(buf, rv, PSS1, strlen(PSS1)) ||
memmem(buf, rv, PSS2, strlen(PSS2)));
static const char *S[] = {
"Anonymous: 0 kB\n",
"AnonHugePages: 0 kB\n",
"Shared_Hugetlb: 0 kB\n",
"Private_Hugetlb: 0 kB\n",
"Locked: 0 kB\n",
};
int i;
for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
assert(memmem(buf, rv, S[i], strlen(S[i])));
}
}
/* Test /proc/$PID/statm */
{
char buf[64];
ssize_t rv;
int fd;
snprintf(buf, sizeof(buf), "/proc/%u/statm", pid);
fd = open(buf, O_RDONLY);
if (fd == -1) {
return 1;
}
rv = read(fd, buf, sizeof(buf));
assert(rv == 7 * 2);
assert(buf[0] == '1'); /* ->total_vm */
assert(buf[1] == ' ');
assert(buf[2] == '0' || buf[2] == '1'); /* rss */
assert(buf[3] == ' ');
assert(buf[4] == '0' || buf[2] == '1'); /* file rss */
assert(buf[5] == ' ');
assert(buf[6] == '1'); /* ELF executable segments */
assert(buf[7] == ' ');
assert(buf[8] == '0');
assert(buf[9] == ' ');
assert(buf[10] == '0'); /* ->data_vm + ->stack_vm */
assert(buf[11] == ' ');
assert(buf[12] == '0');
assert(buf[13] == '\n');
}
return 0;
}
#else
int main(void)
{
return 4;
}
#endif

View File

@@ -63,7 +63,7 @@ int main(void)
p = mmap((void *)va, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_FILE|MAP_FIXED, fd, 0);
if (p == MAP_FAILED) {
if (errno == EPERM)
return 2;
return 4;
return 1;
}

View File

@@ -20,7 +20,6 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
@@ -39,7 +38,7 @@ int main(void)
fd = open("/proc/self/syscall", O_RDONLY);
if (fd == -1) {
if (errno == ENOENT)
return 2;
return 4;
return 1;
}

View File

@@ -27,7 +27,7 @@ int main(void)
fd = open("/proc/self/wchan", O_RDONLY);
if (fd == -1) {
if (errno == ENOENT)
return 2;
return 4;
return 1;
}

View File

@@ -26,8 +26,10 @@
#include <dirent.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <fcntl.h>
#include <unistd.h>
@@ -123,10 +125,22 @@ static void f(DIR *d, unsigned int level)
int main(void)
{
DIR *d;
struct statfs sfs;
d = opendir("/proc");
if (!d)
return 4;
/* Ensure /proc is proc. */
if (fstatfs(dirfd(d), &sfs) == -1) {
return 1;
}
if (sfs.f_type != 0x9fa0) {
fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type);
return 2;
}
f(d, 0);
return 0;
}

View File

@@ -0,0 +1 @@
/bug-link-o-tmpfile

View File

@@ -0,0 +1,7 @@
CFLAGS += -Wall -O2
CFLAGS += -D_GNU_SOURCE
TEST_GEN_PROGS :=
TEST_GEN_PROGS += bug-link-o-tmpfile
include ../lib.mk

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2019 Alexey Dobriyan <adobriyan@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Test that open(O_TMPFILE), linkat() doesn't screw accounting. */
#include <errno.h>
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mount.h>
#include <unistd.h>
int main(void)
{
int fd;
if (unshare(CLONE_NEWNS) == -1) {
if (errno == ENOSYS || errno == EPERM) {
fprintf(stderr, "error: unshare, errno %d\n", errno);
return 4;
}
fprintf(stderr, "error: unshare, errno %d\n", errno);
return 1;
}
if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) == -1) {
fprintf(stderr, "error: mount '/', errno %d\n", errno);
return 1;
}
/* Our heroes: 1 root inode, 1 O_TMPFILE inode, 1 permanent inode. */
if (mount(NULL, "/tmp", "tmpfs", 0, "nr_inodes=3") == -1) {
fprintf(stderr, "error: mount tmpfs, errno %d\n", errno);
return 1;
}
fd = openat(AT_FDCWD, "/tmp", O_WRONLY|O_TMPFILE, 0600);
if (fd == -1) {
fprintf(stderr, "error: open 1, errno %d\n", errno);
return 1;
}
if (linkat(fd, "", AT_FDCWD, "/tmp/1", AT_EMPTY_PATH) == -1) {
fprintf(stderr, "error: linkat, errno %d\n", errno);
return 1;
}
close(fd);
fd = openat(AT_FDCWD, "/tmp", O_WRONLY|O_TMPFILE, 0600);
if (fd == -1) {
fprintf(stderr, "error: open 2, errno %d\n", errno);
return 1;
}
return 0;
}

View File

@@ -211,4 +211,20 @@ else
echo "[PASS]"
fi
echo "------------------------------------"
echo "running vmalloc stability smoke test"
echo "------------------------------------"
./test_vmalloc.sh smoke
ret_val=$?
if [ $ret_val -eq 0 ]; then
echo "[PASS]"
elif [ $ret_val -eq $ksft_skip ]; then
echo "[SKIP]"
exitcode=$ksft_skip
else
echo "[FAIL]"
exitcode=1
fi
exit $exitcode

View File

@@ -0,0 +1,176 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2018 Uladzislau Rezki (Sony) <urezki@gmail.com>
#
# This is a test script for the kernel test driver to analyse vmalloc
# allocator. Therefore it is just a kernel module loader. You can specify
# and pass different parameters in order to:
# a) analyse performance of vmalloc allocations;
# b) stressing and stability check of vmalloc subsystem.
TEST_NAME="vmalloc"
DRIVER="test_${TEST_NAME}"
# 1 if fails
exitcode=1
# Kselftest framework requirement - SKIP code is 4.
ksft_skip=4
#
# Static templates for performance, stressing and smoke tests.
# Also it is possible to pass any supported parameters manualy.
#
PERF_PARAM="single_cpu_test=1 sequential_test_order=1 test_repeat_count=3"
SMOKE_PARAM="single_cpu_test=1 test_loop_count=10000 test_repeat_count=10"
STRESS_PARAM="test_repeat_count=20"
check_test_requirements()
{
uid=$(id -u)
if [ $uid -ne 0 ]; then
echo "$0: Must be run as root"
exit $ksft_skip
fi
if ! which modprobe > /dev/null 2>&1; then
echo "$0: You need modprobe installed"
exit $ksft_skip
fi
if ! modinfo $DRIVER > /dev/null 2>&1; then
echo "$0: You must have the following enabled in your kernel:"
echo "CONFIG_TEST_VMALLOC=m"
exit $ksft_skip
fi
}
run_perfformance_check()
{
echo "Run performance tests to evaluate how fast vmalloc allocation is."
echo "It runs all test cases on one single CPU with sequential order."
modprobe $DRIVER $PERF_PARAM > /dev/null 2>&1
echo "Done."
echo "Ccheck the kernel message buffer to see the summary."
}
run_stability_check()
{
echo "Run stability tests. In order to stress vmalloc subsystem we run"
echo "all available test cases on all available CPUs simultaneously."
echo "It will take time, so be patient."
modprobe $DRIVER $STRESS_PARAM > /dev/null 2>&1
echo "Done."
echo "Check the kernel ring buffer to see the summary."
}
run_smoke_check()
{
echo "Run smoke test. Note, this test provides basic coverage."
echo "Please check $0 output how it can be used"
echo "for deep performance analysis as well as stress testing."
modprobe $DRIVER $SMOKE_PARAM > /dev/null 2>&1
echo "Done."
echo "Check the kernel ring buffer to see the summary."
}
usage()
{
echo -n "Usage: $0 [ performance ] | [ stress ] | | [ smoke ] | "
echo "manual parameters"
echo
echo "Valid tests and parameters:"
echo
modinfo $DRIVER
echo
echo "Example usage:"
echo
echo "# Shows help message"
echo "./${DRIVER}.sh"
echo
echo "# Runs 1 test(id_1), repeats it 5 times on all online CPUs"
echo "./${DRIVER}.sh run_test_mask=1 test_repeat_count=5"
echo
echo -n "# Runs 4 tests(id_1|id_2|id_4|id_16) on one CPU with "
echo "sequential order"
echo -n "./${DRIVER}.sh single_cpu_test=1 sequential_test_order=1 "
echo "run_test_mask=23"
echo
echo -n "# Runs all tests on all online CPUs, shuffled order, repeats "
echo "20 times"
echo "./${DRIVER}.sh test_repeat_count=20"
echo
echo "# Performance analysis"
echo "./${DRIVER}.sh performance"
echo
echo "# Stress testing"
echo "./${DRIVER}.sh stress"
echo
exit 0
}
function validate_passed_args()
{
VALID_ARGS=`modinfo $DRIVER | awk '/parm:/ {print $2}' | sed 's/:.*//'`
#
# Something has been passed, check it.
#
for passed_arg in $@; do
key=${passed_arg//=*/}
val="${passed_arg:$((${#key}+1))}"
valid=0
for valid_arg in $VALID_ARGS; do
if [[ $key = $valid_arg ]] && [[ $val -gt 0 ]]; then
valid=1
break
fi
done
if [[ $valid -ne 1 ]]; then
echo "Error: key or value is not correct: ${key} $val"
exit $exitcode
fi
done
}
function run_manual_check()
{
#
# Validate passed parameters. If there is wrong one,
# the script exists and does not execute further.
#
validate_passed_args $@
echo "Run the test with following parameters: $@"
modprobe $DRIVER $@ > /dev/null 2>&1
echo "Done."
echo "Check the kernel ring buffer to see the summary."
}
function run_test()
{
if [ $# -eq 0 ]; then
usage
else
if [[ "$1" = "performance" ]]; then
run_perfformance_check
elif [[ "$1" = "stress" ]]; then
run_stability_check
elif [[ "$1" = "smoke" ]]; then
run_smoke_check
else
run_manual_check $@
fi
fi
}
check_test_requirements
run_test $@
exit 0