diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/testing/selftests/liveupdate/liveupdate.c | 41 | ||||
| -rwxr-xr-x | tools/testing/selftests/mm/charge_reserved_hugetlb.sh | 5 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/guard-regions.c | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/hmm-tests.c | 83 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/hugetlb_dio.c | 91 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/merge.c | 88 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/soft-dirty.c | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/split_huge_page_test.c | 19 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/thp_settings.c | 35 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/thp_settings.h | 1 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/transhuge-stress.c | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/vm_util.c | 24 | ||||
| -rw-r--r-- | tools/testing/selftests/mm/vm_util.h | 2 |
13 files changed, 263 insertions, 138 deletions
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c index c2878e3d5ef9..37c808fbe1e9 100644 --- a/tools/testing/selftests/liveupdate/liveupdate.c +++ b/tools/testing/selftests/liveupdate/liveupdate.c @@ -345,4 +345,45 @@ TEST_F(liveupdate_device, preserve_unsupported_fd) ASSERT_EQ(close(session_fd), 0); } +/* + * Test Case: Prevent Double Preservation + * + * Verifies that a file (memfd) can only be preserved once across all active + * sessions. Attempting to preserve it a second time, whether in the same or + * a different session, should fail with EBUSY. + */ +TEST_F(liveupdate_device, prevent_double_preservation) +{ + int session_fd1, session_fd2, mem_fd; + int ret; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd1 = create_session(self->fd1, "double-preserve-session-1"); + ASSERT_GE(session_fd1, 0); + session_fd2 = create_session(self->fd1, "double-preserve-session-2"); + ASSERT_GE(session_fd2, 0); + + mem_fd = memfd_create("test-memfd", 0); + ASSERT_GE(mem_fd, 0); + + /* First preservation should succeed */ + ASSERT_EQ(preserve_fd(session_fd1, mem_fd, 0x1111), 0); + + /* Second preservation in a different session should fail with EBUSY */ + ret = preserve_fd(session_fd2, mem_fd, 0x2222); + EXPECT_EQ(ret, -EBUSY); + + /* Second preservation in the same session (different token) should fail with EBUSY */ + ret = preserve_fd(session_fd1, mem_fd, 0x3333); + EXPECT_EQ(ret, -EBUSY); + + ASSERT_EQ(close(mem_fd), 0); + ASSERT_EQ(close(session_fd1), 0); + ASSERT_EQ(close(session_fd2), 0); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh index 447769657634..44f4e703deb9 100755 --- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh +++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh @@ -11,6 +11,11 @@ if [[ $(id -u) -ne 0 ]]; then exit $ksft_skip fi +if ! command -v killall >/dev/null 2>&1; then + echo "killall not available. Skipping..." + exit $ksft_skip +fi + nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages) fault_limit_file=limit_in_bytes diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c index dbd21d66d383..48e8b1539be3 100644 --- a/tools/testing/selftests/mm/guard-regions.c +++ b/tools/testing/selftests/mm/guard-regions.c @@ -21,6 +21,7 @@ #include <sys/uio.h> #include <unistd.h> #include "vm_util.h" +#include "thp_settings.h" #include "../pidfd/pidfd.h" @@ -2195,6 +2196,9 @@ TEST_F(guard_regions, collapse) char *ptr; int i; + if (!thp_available()) + SKIP(return, "Transparent Hugepages not available\n"); + /* Need file to be correct size for tests for non-anon. */ if (variant->backing != ANON_BACKED) ASSERT_EQ(ftruncate(self->fd, size), 0); diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c index e8328c89d855..788689497e92 100644 --- a/tools/testing/selftests/mm/hmm-tests.c +++ b/tools/testing/selftests/mm/hmm-tests.c @@ -34,6 +34,7 @@ */ #include <lib/test_hmm_uapi.h> #include <mm/gup_test.h> +#include <mm/vm_util.h> struct hmm_buffer { void *ptr; @@ -548,7 +549,7 @@ TEST_F(hmm, anon_write_child) for (migrate = 0; migrate < 2; ++migrate) { for (use_thp = 0; use_thp < 2; ++use_thp) { - npages = ALIGN(use_thp ? TWOMEG : HMM_BUFFER_SIZE, + npages = ALIGN(use_thp ? read_pmd_pagesize() : HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; ASSERT_NE(npages, 0); size = npages << self->page_shift; @@ -728,7 +729,7 @@ TEST_F(hmm, anon_write_huge) int *ptr; int ret; - size = 2 * TWOMEG; + size = 2 * read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -744,7 +745,7 @@ TEST_F(hmm, anon_write_huge) buffer->fd, 0); ASSERT_NE(buffer->ptr, MAP_FAILED); - size = TWOMEG; + size /= 2; npages = size >> self->page_shift; map = (void *)ALIGN((uintptr_t)buffer->ptr, size); ret = madvise(map, size, MADV_HUGEPAGE); @@ -771,54 +772,6 @@ TEST_F(hmm, anon_write_huge) } /* - * Read numeric data from raw and tagged kernel status files. Used to read - * /proc and /sys data (without a tag) and from /proc/meminfo (with a tag). - */ -static long file_read_ulong(char *file, const char *tag) -{ - int fd; - char buf[2048]; - int len; - char *p, *q; - long val; - - fd = open(file, O_RDONLY); - if (fd < 0) { - /* Error opening the file */ - return -1; - } - - len = read(fd, buf, sizeof(buf)); - close(fd); - if (len < 0) { - /* Error in reading the file */ - return -1; - } - if (len == sizeof(buf)) { - /* Error file is too large */ - return -1; - } - buf[len] = '\0'; - - /* Search for a tag if provided */ - if (tag) { - p = strstr(buf, tag); - if (!p) - return -1; /* looks like the line we want isn't there */ - p += strlen(tag); - } else - p = buf; - - val = strtol(p, &q, 0); - if (*q != ' ') { - /* Error parsing the file */ - return -1; - } - - return val; -} - -/* * Write huge TLBFS page. */ TEST_F(hmm, anon_write_hugetlbfs) @@ -826,15 +779,13 @@ TEST_F(hmm, anon_write_hugetlbfs) struct hmm_buffer *buffer; unsigned long npages; unsigned long size; - unsigned long default_hsize; + unsigned long default_hsize = default_huge_page_size(); unsigned long i; int *ptr; int ret; - default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:"); - if (default_hsize < 0 || default_hsize*1024 < default_hsize) + if (!default_hsize) SKIP(return, "Huge page size could not be determined"); - default_hsize = default_hsize*1024; /* KB to B */ size = ALIGN(TWOMEG, default_hsize); npages = size >> self->page_shift; @@ -1606,7 +1557,7 @@ TEST_F(hmm, compound) struct hmm_buffer *buffer; unsigned long npages; unsigned long size; - unsigned long default_hsize; + unsigned long default_hsize = default_huge_page_size(); int *ptr; unsigned char *m; int ret; @@ -1614,10 +1565,8 @@ TEST_F(hmm, compound) /* Skip test if we can't allocate a hugetlbfs page. */ - default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:"); - if (default_hsize < 0 || default_hsize*1024 < default_hsize) + if (!default_hsize) SKIP(return, "Huge page size could not be determined"); - default_hsize = default_hsize*1024; /* KB to B */ size = ALIGN(TWOMEG, default_hsize); npages = size >> self->page_shift; @@ -2106,7 +2055,7 @@ TEST_F(hmm, migrate_anon_huge_empty) int *ptr; int ret; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -2158,7 +2107,7 @@ TEST_F(hmm, migrate_anon_huge_zero) int ret; int val; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -2221,7 +2170,7 @@ TEST_F(hmm, migrate_anon_huge_free) int *ptr; int ret; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -2280,7 +2229,7 @@ TEST_F(hmm, migrate_anon_huge_fault) int *ptr; int ret; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -2332,7 +2281,7 @@ TEST_F(hmm, migrate_partial_unmap_fault) { struct hmm_buffer *buffer; unsigned long npages; - unsigned long size = TWOMEG; + unsigned long size = read_pmd_pagesize(); unsigned long i; void *old_ptr; void *map; @@ -2398,7 +2347,7 @@ TEST_F(hmm, migrate_remap_fault) { struct hmm_buffer *buffer; unsigned long npages; - unsigned long size = TWOMEG; + unsigned long size = read_pmd_pagesize(); unsigned long i; void *old_ptr, *new_ptr = NULL; void *map; @@ -2498,7 +2447,7 @@ TEST_F(hmm, migrate_anon_huge_err) int *ptr; int ret; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); @@ -2593,7 +2542,7 @@ TEST_F(hmm, migrate_anon_huge_zero_err) int *ptr; int ret; - size = TWOMEG; + size = read_pmd_pagesize(); buffer = malloc(sizeof(*buffer)); ASSERT_NE(buffer, NULL); diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c index 9ac62eb4c97d..31a054fa8134 100644 --- a/tools/testing/selftests/mm/hugetlb_dio.c +++ b/tools/testing/selftests/mm/hugetlb_dio.c @@ -17,12 +17,57 @@ #include <unistd.h> #include <string.h> #include <sys/mman.h> +#include <sys/syscall.h> #include "vm_util.h" #include "kselftest.h" -void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) +#ifndef STATX_DIOALIGN +#define STATX_DIOALIGN 0x00002000U +#endif + +static int get_dio_alignment(int fd) +{ + struct statx stx; + int ret; + + ret = syscall(__NR_statx, fd, "", AT_EMPTY_PATH, STATX_DIOALIGN, &stx); + if (ret < 0) + return -1; + + /* + * If STATX_DIOALIGN is unsupported, assume no alignment + * constraint and let the test proceed. + */ + if (!(stx.stx_mask & STATX_DIOALIGN) || !stx.stx_dio_offset_align) + return 1; + + return stx.stx_dio_offset_align; +} + +static bool check_dio_alignment(unsigned int start_off, + unsigned int end_off, unsigned int align) +{ + unsigned int writesize = end_off - start_off; + + /* + * The kernel's DIO path checks that file offset, length, and + * buffer address are all multiples of dio_offset_align. When + * this test case's parameters don't satisfy that, the write + * would fail with -EINVAL before exercising the hugetlb unpin + * path, so skip. + */ + if (start_off % align != 0 || writesize % align != 0) { + ksft_test_result_skip("DIO align=%u incompatible with offset %u writesize %u\n", + align, start_off, writesize); + return false; + } + + return true; +} + +static void run_dio_using_hugetlb(int fd, unsigned int start_off, + unsigned int end_off, unsigned int align) { - int fd; char *buffer = NULL; char *orig_buffer = NULL; size_t h_pagesize = 0; @@ -32,6 +77,9 @@ void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB; const int mmap_prot = PROT_READ | PROT_WRITE; + if (!check_dio_alignment(start_off, end_off, align)) + return; + writesize = end_off - start_off; /* Get the default huge page size */ @@ -39,10 +87,9 @@ void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) if (!h_pagesize) ksft_exit_fail_msg("Unable to determine huge page size\n"); - /* Open the file to DIO */ - fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664); - if (fd < 0) - ksft_exit_fail_perror("Error opening file\n"); + /* Reset file position since fd is shared across tests */ + if (lseek(fd, 0, SEEK_SET) < 0) + ksft_exit_fail_perror("lseek failed\n"); /* Get the free huge pages before allocation */ free_hpage_b = get_free_hugepages(); @@ -71,7 +118,6 @@ void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) /* unmap the huge page */ munmap(orig_buffer, h_pagesize); - close(fd); /* Get the free huge pages after unmap*/ free_hpage_a = get_free_hugepages(); @@ -89,37 +135,38 @@ void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) int main(void) { - size_t pagesize = 0; - int fd; + int fd, align; + const size_t pagesize = psize(); ksft_print_header(); - /* Open the file to DIO */ - fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664); - if (fd < 0) - ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno)); - close(fd); - /* Check if huge pages are free */ if (!get_free_hugepages()) ksft_exit_skip("No free hugepage, exiting\n"); - ksft_set_plan(4); + fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664); + if (fd < 0) + ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno)); - /* Get base page size */ - pagesize = psize(); + align = get_dio_alignment(fd); + if (align < 0) + ksft_exit_skip("Unable to obtain DIO alignment: %s\n", + strerror(errno)); + ksft_set_plan(4); /* start and end is aligned to pagesize */ - run_dio_using_hugetlb(0, (pagesize * 3)); + run_dio_using_hugetlb(fd, 0, (pagesize * 3), align); /* start is aligned but end is not aligned */ - run_dio_using_hugetlb(0, (pagesize * 3) - (pagesize / 2)); + run_dio_using_hugetlb(fd, 0, (pagesize * 3) - (pagesize / 2), align); /* start is unaligned and end is aligned */ - run_dio_using_hugetlb(pagesize / 2, (pagesize * 3)); + run_dio_using_hugetlb(fd, pagesize / 2, (pagesize * 3), align); /* both start and end are unaligned */ - run_dio_using_hugetlb(pagesize / 2, (pagesize * 3) + (pagesize / 2)); + run_dio_using_hugetlb(fd, pagesize / 2, (pagesize * 3) + (pagesize / 2), align); + + close(fd); ksft_finished(); } diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index 10b686102b79..519e5ac02db7 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -48,6 +48,19 @@ static pid_t do_fork(struct procmap_fd *procmap) return 0; } +#ifdef __NR_mseal +static int sys_mseal(void *ptr, size_t len, unsigned long flags) +{ + return syscall(__NR_mseal, (unsigned long)ptr, len, flags); +} +#else +static int sys_mseal(void *ptr, size_t len, unsigned long flags) +{ + errno = ENOSYS; + return -1; +} +#endif + FIXTURE_SETUP(merge) { self->page_size = psize(); @@ -1217,6 +1230,81 @@ TEST_F(merge, mremap_correct_placed_faulted) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size); } +TEST_F(merge, merge_vmas_with_mseal) +{ + unsigned int page_size = self->page_size; + struct procmap_fd *procmap = &self->procmap; + char *ptr, *ptr2, *ptr3; + /* We need our own as cannot munmap() once sealed. */ + char *carveout; + + /* Invalid mseal() call to see if implemented. */ + ASSERT_EQ(sys_mseal(NULL, 0, ~0UL), -1); + if (errno == ENOSYS) + SKIP(return, "mseal not supported, skipping."); + + /* Map carveout. */ + carveout = mmap(NULL, 5 * page_size, PROT_NONE, + MAP_PRIVATE | MAP_ANON, -1, 0); + ASSERT_NE(carveout, MAP_FAILED); + + /* + * Map 3 separate VMAs: + * + * |-----------|-----------|-----------| + * | RW | RWE | RO | + * |-----------|-----------|-----------| + * ptr ptr2 ptr3 + */ + ptr = mmap(&carveout[page_size], page_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); + ASSERT_NE(ptr, MAP_FAILED); + ptr2 = mmap(&carveout[2 * page_size], page_size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); + ASSERT_NE(ptr2, MAP_FAILED); + ptr3 = mmap(&carveout[3 * page_size], page_size, PROT_READ, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); + ASSERT_NE(ptr3, MAP_FAILED); + + /* + * mseal the second VMA: + * + * |-----------|-----------|-----------| + * | RW | RWES | RO | + * |-----------|-----------|-----------| + * ptr ptr2 ptr3 + */ + ASSERT_EQ(sys_mseal(ptr2, page_size, 0), 0); + + /* Make first VMA mergeable upon mseal. */ + ASSERT_EQ(mprotect(ptr, page_size, + PROT_READ | PROT_WRITE | PROT_EXEC), 0); + /* + * At this point we have: + * + * |-----------|-----------|-----------| + * | RWE | RWES | RO | + * |-----------|-----------|-----------| + * ptr ptr2 ptr3 + * + * Now mseal all of the VMAs. + */ + ASSERT_EQ(sys_mseal(ptr, 3 * page_size, 0), 0); + + /* + * We should end up with: + * + * |-----------------------|-----------| + * | RWES | ROS | + * |-----------------------|-----------| + * ptr ptr3 + */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 2 * page_size); +} + TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev) { struct procmap_fd *procmap = &self->procmap; diff --git a/tools/testing/selftests/mm/soft-dirty.c b/tools/testing/selftests/mm/soft-dirty.c index 59c0dbe99a9b..bcfcac99b436 100644 --- a/tools/testing/selftests/mm/soft-dirty.c +++ b/tools/testing/selftests/mm/soft-dirty.c @@ -82,7 +82,9 @@ static void test_hugepage(int pagemap_fd, int pagesize) int i, ret; if (!thp_is_enabled()) { - ksft_test_result_skip("Transparent Hugepages not available\n"); + ksft_print_msg("Transparent Hugepages not available\n"); + ksft_test_result_skip("Test %s huge page allocation\n", __func__); + ksft_test_result_skip("Test %s huge page dirty bit\n", __func__); return; } diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index e0167111bdd1..500d07c4938b 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -21,6 +21,7 @@ #include <time.h> #include "vm_util.h" #include "kselftest.h" +#include "thp_settings.h" uint64_t pagesize; unsigned int pageshift; @@ -255,21 +256,6 @@ static int check_after_split_folio_orders(char *vaddr_start, size_t len, return status; } -static void write_file(const char *path, const char *buf, size_t buflen) -{ - int fd; - ssize_t numwritten; - - fd = open(path, O_WRONLY); - if (fd == -1) - ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno)); - - numwritten = write(fd, buf, buflen - 1); - close(fd); - if (numwritten < 1) - ksft_exit_fail_msg("Write failed\n"); -} - static void write_debugfs(const char *fmt, ...) { char input[INPUT_MAX]; @@ -772,6 +758,9 @@ int main(int argc, char **argv) ksft_finished(); } + if (!thp_is_enabled()) + ksft_exit_skip("Transparent Hugepages not available\n"); + if (argc > 1) optional_xfs_path = argv[1]; diff --git a/tools/testing/selftests/mm/thp_settings.c b/tools/testing/selftests/mm/thp_settings.c index 574bd0f8ae48..e748ebfb3d4e 100644 --- a/tools/testing/selftests/mm/thp_settings.c +++ b/tools/testing/selftests/mm/thp_settings.c @@ -6,6 +6,7 @@ #include <string.h> #include <unistd.h> +#include "vm_util.h" #include "thp_settings.h" #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/" @@ -64,29 +65,6 @@ int read_file(const char *path, char *buf, size_t buflen) return (unsigned int) numread; } -int write_file(const char *path, const char *buf, size_t buflen) -{ - int fd; - ssize_t numwritten; - - fd = open(path, O_WRONLY); - if (fd == -1) { - printf("open(%s)\n", path); - exit(EXIT_FAILURE); - return 0; - } - - numwritten = write(fd, buf, buflen - 1); - close(fd); - if (numwritten < 1) { - printf("write(%s)\n", buf); - exit(EXIT_FAILURE); - return 0; - } - - return (unsigned int) numwritten; -} - unsigned long read_num(const char *path) { char buf[21]; @@ -104,10 +82,7 @@ void write_num(const char *path, unsigned long num) char buf[21]; sprintf(buf, "%ld", num); - if (!write_file(path, buf, strlen(buf) + 1)) { - perror(path); - exit(EXIT_FAILURE); - } + write_file(path, buf, strlen(buf) + 1); } int thp_read_string(const char *name, const char * const strings[]) @@ -165,11 +140,7 @@ void thp_write_string(const char *name, const char *val) printf("%s: Pathname is too long\n", __func__); exit(EXIT_FAILURE); } - - if (!write_file(path, val, strlen(val) + 1)) { - perror(path); - exit(EXIT_FAILURE); - } + write_file(path, val, strlen(val) + 1); } unsigned long thp_read_num(const char *name) diff --git a/tools/testing/selftests/mm/thp_settings.h b/tools/testing/selftests/mm/thp_settings.h index 76eeb712e5f1..7748a9009191 100644 --- a/tools/testing/selftests/mm/thp_settings.h +++ b/tools/testing/selftests/mm/thp_settings.h @@ -63,7 +63,6 @@ struct thp_settings { }; int read_file(const char *path, char *buf, size_t buflen); -int write_file(const char *path, const char *buf, size_t buflen); unsigned long read_num(const char *path); void write_num(const char *path, unsigned long num); diff --git a/tools/testing/selftests/mm/transhuge-stress.c b/tools/testing/selftests/mm/transhuge-stress.c index bcad47c09518..7a9f1035099b 100644 --- a/tools/testing/selftests/mm/transhuge-stress.c +++ b/tools/testing/selftests/mm/transhuge-stress.c @@ -17,6 +17,7 @@ #include <sys/mman.h> #include "vm_util.h" #include "kselftest.h" +#include "thp_settings.h" int backing_fd = -1; int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE; @@ -37,6 +38,9 @@ int main(int argc, char **argv) ksft_print_header(); + if (!thp_is_enabled()) + ksft_exit_skip("Transparent Hugepages not available\n"); + ram = sysconf(_SC_PHYS_PAGES); if (ram > SIZE_MAX / psize() / 4) ram = SIZE_MAX / 4; diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index a6d4ff7dfdc0..db94564f4431 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -764,3 +764,27 @@ int unpoison_memory(unsigned long pfn) return ret > 0 ? 0 : -errno; } + +void write_file(const char *path, const char *buf, size_t buflen) +{ + int fd, saved_errno; + ssize_t numwritten; + + if (buflen < 2) + ksft_exit_fail_msg("Incorrect buffer len: %zu\n", buflen); + + fd = open(path, O_WRONLY); + if (fd == -1) + ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno)); + + numwritten = write(fd, buf, buflen - 1); + saved_errno = errno; + close(fd); + errno = saved_errno; + if (numwritten < 0) + ksft_exit_fail_msg("%s write(%.*s) failed: %s\n", path, (int)(buflen - 1), + buf, strerror(errno)); + if (numwritten != buflen - 1) + ksft_exit_fail_msg("%s write(%.*s) is truncated, expected %zu bytes, got %zd bytes\n", + path, (int)(buflen - 1), buf, buflen - 1, numwritten); +} diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index e9c4e24769c1..1a07305ceff4 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -166,3 +166,5 @@ int unpoison_memory(unsigned long pfn); #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0) #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) + +void write_file(const char *path, const char *buf, size_t buflen); |
