As noted by John Hubbard the original test relied on side effects of the implementation of migrate_vma_setup() to detect if pages had been swapped to disk or not. This is subject to change in future so explicitly check for swap entries via pagemap instead. Fix a spelling mistake while we're at it. Signed-off-by: Alistair Popple <apopple@xxxxxxxxxx> Fixes: 5cc88e844e87 ("selftests/hmm-tests: add test for dirty bits") Reviewed-by: Mika Penttilä <mpenttil@xxxxxxxxxx> --- Changes for v2: - Added Mika's Reviewed-by (Thanks!) - Moved pagemap checks into vm_util.c as suggested by David H. --- tools/testing/selftests/vm/Makefile | 1 + tools/testing/selftests/vm/hmm-tests.c | 28 ++++++++++++++++++++++---- tools/testing/selftests/vm/vm_util.c | 22 ++++++++++++++++++++ tools/testing/selftests/vm/vm_util.h | 2 ++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index d9fa6a9ea584..17e36129efd2 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -100,6 +100,7 @@ include ../lib.mk $(OUTPUT)/madv_populate: vm_util.c $(OUTPUT)/soft-dirty: vm_util.c $(OUTPUT)/split_huge_page_test: vm_util.c +$(OUTPUT)/hmm-tests: vm_util.c ifeq ($(MACHINE),x86_64) BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32)) diff --git a/tools/testing/selftests/vm/hmm-tests.c b/tools/testing/selftests/vm/hmm-tests.c index 70fdb49b59ed..509fe8c5158e 100644 --- a/tools/testing/selftests/vm/hmm-tests.c +++ b/tools/testing/selftests/vm/hmm-tests.c @@ -37,6 +37,7 @@ */ #include "../../../../lib/test_hmm_uapi.h" #include "../../../../mm/gup_test.h" +#include "vm_util.h" struct hmm_buffer { void *ptr; @@ -1261,9 +1262,24 @@ static int destroy_cgroup(void) return 0; } +/* Returns true if at least one page in the range is on swap */ +static bool pages_swapped(void *ptr, size_t size) +{ + int fd = open("/proc/self/pagemap", O_RDONLY); + bool ret; + + if (fd < 0) + return false; + + ret = pagemap_range_some_swapped(fd, ptr, size); + close(fd); + + return ret; +} + /* * Try and migrate a dirty page that has previously been swapped to disk. This - * checks that we don't loose dirty bits. + * checks that we don't lose dirty bits. */ TEST_F(hmm, migrate_dirty_page) { @@ -1300,6 +1316,10 @@ TEST_F(hmm, migrate_dirty_page) ASSERT_FALSE(write_cgroup_param(cgroup, "memory.reclaim", 1UL<<30)); + /* Make sure at least some pages got paged to disk. */ + if (!pages_swapped(buffer->ptr, size)) + SKIP(return, "Pages weren't swapped when they should have been"); + /* Fault pages back in from swap as clean pages */ for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) tmp += ptr[i]; @@ -1309,10 +1329,10 @@ TEST_F(hmm, migrate_dirty_page) ptr[i] = i; /* - * Attempt to migrate memory to device, which should fail because - * hopefully some pages are backed by swap storage. + * Attempt to migrate memory to device. This might fail if some pages + * are/were backed by swap but that's ok. */ - ASSERT_TRUE(hmm_migrate_sys_to_dev(self->fd, buffer, npages)); + hmm_migrate_sys_to_dev(self->fd, buffer, npages); ASSERT_FALSE(write_cgroup_param(cgroup, "memory.reclaim", 1UL<<30)); diff --git a/tools/testing/selftests/vm/vm_util.c b/tools/testing/selftests/vm/vm_util.c index b58ab11a7a30..2768d4f3de4c 100644 --- a/tools/testing/selftests/vm/vm_util.c +++ b/tools/testing/selftests/vm/vm_util.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include <unistd.h> #include <string.h> #include <fcntl.h> #include "../kselftest.h" @@ -20,6 +21,14 @@ uint64_t pagemap_get_entry(int fd, char *start) return entry; } +bool pagemap_is_swapped(int fd, char *start) +{ + uint64_t entry = pagemap_get_entry(fd, start); + + // Check if swap entry bit (62nd bit) is set + return entry & 0x4000000000000000ull; +} + bool pagemap_is_softdirty(int fd, char *start) { uint64_t entry = pagemap_get_entry(fd, start); @@ -28,6 +37,19 @@ bool pagemap_is_softdirty(int fd, char *start) return entry & 0x0080000000000000ull; } +/* Returns true if at least one page in the range is in swap */ +bool pagemap_range_some_swapped(int fd, char *start, size_t len) +{ + unsigned long i; + unsigned long npages = len / getpagesize(); + + for (i = 0; i < npages; i++) + if (pagemap_is_swapped(fd, start + i * getpagesize())) + return true; + + return false; +} + void clear_softdirty(void) { int ret; diff --git a/tools/testing/selftests/vm/vm_util.h b/tools/testing/selftests/vm/vm_util.h index 2e512bd57ae1..307e11f72341 100644 --- a/tools/testing/selftests/vm/vm_util.h +++ b/tools/testing/selftests/vm/vm_util.h @@ -4,6 +4,8 @@ uint64_t pagemap_get_entry(int fd, char *start); bool pagemap_is_softdirty(int fd, char *start); +bool pagemap_is_swapped(int fd, char *start); +bool pagemap_range_some_swapped(int fd, char *start, size_t len); void clear_softdirty(void); uint64_t read_pmd_pagesize(void); uint64_t check_huge(void *addr); -- 2.35.1