mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
mm: selftests: Add shmem into memory failure test
Add a shmem memory failure selftest to test the shmem memory failure is correct after modifying shmem return value. Specifically, test the expected behavior under various scenarios combining page dirtiness (dirty vs clean) and failure types (hard vs soft): + Dirty + Hard: Trigger a SIGBUS on injection, and trigger another SIGBUS when reading the page again. + Dirty + Soft: No SIGBUS is triggered, and the original value can be read successfully. + Clean + Hard: No SIGBUS is triggered on injection, but trigger a SIGBUS when trying to read the page again. + Clean + Soft: No SIGBUS is triggered, and the page can be read successfully. [akpm@linux-foundation.org: fix comment typo, per Lisa] Link: https://lore.kernel.org/20260917-memory-failure-mf-delayed-fix-v6-5-4b00856b5364@google.com Signed-off-by: Lisa Wang <wyihan@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Miaohe Lin <linmiaohe@huawei.com> Cc: Ackerley Tng <ackerleytng@google.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David Hildenbrand (Arm) <david@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Fuad Tabba <tabba@google.com> Cc: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com> Cc: Hugh Dickins <hughd@google.com> Cc: Isaku Yamahata <isaku.yamahata@intel.com> Cc: Jiaqi Yan <jiaqiyan@google.com> Cc: Liam R. Howlett <liam@infradead.org> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: Michael Roth <michael.roth@amd.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vishal Annapurve <vannapurve@google.com> Cc: Vlastimil Babka <vbabka@kernel.org> Cc: Xiaoyao Li <xiaoyao.li@intel.com> Cc: Yu Zhang <yu.c.zhang@linux.intel.com>
This commit is contained in:
parent
fd57828da9
commit
69567ac40e
|
|
@ -29,9 +29,14 @@ enum result_type {
|
|||
MADV_HARD_ANON,
|
||||
MADV_HARD_CLEAN_PAGECACHE,
|
||||
MADV_HARD_DIRTY_PAGECACHE,
|
||||
MADV_HARD_CLEAN_SHMEM,
|
||||
MADV_HARD_DIRTY_SHMEM,
|
||||
MADV_SOFT_ANON,
|
||||
MADV_SOFT_CLEAN_PAGECACHE,
|
||||
MADV_SOFT_DIRTY_PAGECACHE,
|
||||
MADV_SOFT_CLEAN_SHMEM,
|
||||
MADV_SOFT_DIRTY_SHMEM,
|
||||
READ_ERROR,
|
||||
};
|
||||
|
||||
static jmp_buf signal_jmp_buf;
|
||||
|
|
@ -157,17 +162,22 @@ static void check(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure
|
|||
case MADV_HARD_CLEAN_PAGECACHE:
|
||||
case MADV_SOFT_CLEAN_PAGECACHE:
|
||||
case MADV_SOFT_DIRTY_PAGECACHE:
|
||||
/* It is not expected to receive a SIGBUS signal. */
|
||||
ASSERT_EQ(setjmp, 0);
|
||||
|
||||
case MADV_SOFT_DIRTY_SHMEM:
|
||||
/* The page content should remain unchanged. */
|
||||
ASSERT_TRUE(check_memory(vaddr, self->page_size));
|
||||
/* FALLTHROUGH */
|
||||
case MADV_HARD_CLEAN_SHMEM:
|
||||
case MADV_SOFT_CLEAN_SHMEM:
|
||||
/* It is not expected to receive a SIGBUS signal. */
|
||||
ASSERT_EQ(setjmp, 0);
|
||||
|
||||
/* The backing pfn of addr should have changed. */
|
||||
ASSERT_NE(pagemap_get_pfn(self->pagemap_fd, vaddr), self->pfn);
|
||||
break;
|
||||
case MADV_HARD_ANON:
|
||||
case MADV_HARD_DIRTY_PAGECACHE:
|
||||
case MADV_HARD_DIRTY_SHMEM:
|
||||
case READ_ERROR:
|
||||
/* The SIGBUS signal should have been received. */
|
||||
ASSERT_EQ(setjmp, 1);
|
||||
|
||||
|
|
@ -263,6 +273,20 @@ static int prepare_file(const char *fname, unsigned long size)
|
|||
return fd;
|
||||
}
|
||||
|
||||
static int prepare_shmem(const char *fname, unsigned long size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = memfd_create(fname, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
if (ftruncate(fd, size) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Borrowed from mm/gup_longterm.c. */
|
||||
static int get_fs_type(int fd)
|
||||
{
|
||||
|
|
@ -365,4 +389,88 @@ TEST_F(memory_failure, dirty_pagecache)
|
|||
ASSERT_EQ(close(fd), 0);
|
||||
}
|
||||
|
||||
TEST_F(memory_failure, dirty_shmem)
|
||||
{
|
||||
int fd;
|
||||
char *addr;
|
||||
int ret;
|
||||
|
||||
fd = prepare_shmem("shmem-file", self->page_size);
|
||||
if (fd < 0)
|
||||
SKIP(return, "failed to open test shmem-file.\n");
|
||||
|
||||
addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
close(fd);
|
||||
SKIP(return, "mmap failed, not enough memory.\n");
|
||||
}
|
||||
memset(addr, 0xce, self->page_size);
|
||||
|
||||
prepare(_metadata, self, addr);
|
||||
|
||||
ret = sigsetjmp(signal_jmp_buf, 1);
|
||||
if (!ret && !self->injection_attempted) {
|
||||
self->injection_attempted = true;
|
||||
ASSERT_EQ(variant->inject(self, addr), 0);
|
||||
}
|
||||
|
||||
if (variant->type == MADV_HARD) {
|
||||
check(_metadata, self, addr, MADV_HARD_DIRTY_SHMEM, ret);
|
||||
ret = sigsetjmp(signal_jmp_buf, 1);
|
||||
if (ret == 0)
|
||||
FORCE_READ(*addr);
|
||||
check(_metadata, self, addr, READ_ERROR, ret);
|
||||
} else {
|
||||
check(_metadata, self, addr, MADV_SOFT_DIRTY_SHMEM, ret);
|
||||
}
|
||||
|
||||
ASSERT_EQ(munmap(addr, self->page_size), 0);
|
||||
|
||||
ASSERT_EQ(close(fd), 0);
|
||||
}
|
||||
|
||||
TEST_F(memory_failure, clean_shmem)
|
||||
{
|
||||
int fd;
|
||||
char *addr;
|
||||
int ret;
|
||||
|
||||
fd = prepare_shmem("shmem-file", self->page_size);
|
||||
if (fd < 0)
|
||||
SKIP(return, "failed to open test shmem-file.\n");
|
||||
|
||||
addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
close(fd);
|
||||
SKIP(return, "mmap failed, not enough memory.\n");
|
||||
}
|
||||
FORCE_READ(*addr);
|
||||
|
||||
prepare(_metadata, self, addr);
|
||||
|
||||
ret = sigsetjmp(signal_jmp_buf, 1);
|
||||
if (!ret && !self->injection_attempted) {
|
||||
self->injection_attempted = true;
|
||||
ASSERT_EQ(variant->inject(self, addr), 0);
|
||||
}
|
||||
|
||||
if (variant->type == MADV_HARD) {
|
||||
check(_metadata, self, addr, MADV_HARD_CLEAN_SHMEM, ret);
|
||||
ret = sigsetjmp(signal_jmp_buf, 1);
|
||||
if (ret == 0)
|
||||
FORCE_READ(*addr);
|
||||
check(_metadata, self, addr, READ_ERROR, ret);
|
||||
} else {
|
||||
/* Test the address accessability without check_memory(). */
|
||||
FORCE_READ(*addr);
|
||||
check(_metadata, self, addr, MADV_SOFT_CLEAN_SHMEM, ret);
|
||||
}
|
||||
|
||||
ASSERT_EQ(munmap(addr, self->page_size), 0);
|
||||
|
||||
ASSERT_EQ(close(fd), 0);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user