Skip to content

Commit d51b507

Browse files
MiaoheLinakpm00
authored andcommitted
selftests/mm: add memory failure dirty pagecache test
This patch adds a new testcase to validate memory failure handling for dirty pagecache. This performs similar operations as clean pagecaches except fsync() is not used to keep pages dirty. This test helps ensure that memory failure handling for dirty pagecache works correctly, including proper SIGBUS delivery, page isolation, and recovery paths. Link: https://lkml.kernel.org/r/20260206031639.2707102-4-linmiaohe@huawei.com Signed-off-by: Miaohe Lin <linmiaohe@huawei.com> Cc: David Hildenbrand <david@kernel.org> Cc: kernel test robot <lkp@intel.com> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Mark Brown <broonie@kernel.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 12e8a2f commit d51b507

1 file changed

Lines changed: 58 additions & 4 deletions

File tree

tools/testing/selftests/mm/memory-failure.c

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ enum inject_type {
2929
enum result_type {
3030
MADV_HARD_ANON,
3131
MADV_HARD_CLEAN_PAGECACHE,
32+
MADV_HARD_DIRTY_PAGECACHE,
3233
MADV_SOFT_ANON,
3334
MADV_SOFT_CLEAN_PAGECACHE,
35+
MADV_SOFT_DIRTY_PAGECACHE,
3436
};
3537

3638
static jmp_buf signal_jmp_buf;
@@ -162,6 +164,7 @@ static void check(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure
162164
case MADV_SOFT_ANON:
163165
case MADV_HARD_CLEAN_PAGECACHE:
164166
case MADV_SOFT_CLEAN_PAGECACHE:
167+
case MADV_SOFT_DIRTY_PAGECACHE:
165168
/* It is not expected to receive a SIGBUS signal. */
166169
ASSERT_EQ(setjmp, 0);
167170

@@ -172,6 +175,7 @@ static void check(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure
172175
ASSERT_NE(pagemap_get_pfn(self->pagemap_fd, vaddr), self->pfn);
173176
break;
174177
case MADV_HARD_ANON:
178+
case MADV_HARD_DIRTY_PAGECACHE:
175179
/* The SIGBUS signal should have been received. */
176180
ASSERT_EQ(setjmp, 1);
177181

@@ -244,6 +248,18 @@ TEST_F(memory_failure, anon)
244248
ASSERT_EQ(munmap(addr, self->page_size), 0);
245249
}
246250

251+
static int prepare_file(const char *fname, unsigned long size)
252+
{
253+
int fd;
254+
255+
fd = open(fname, O_RDWR | O_CREAT, 0664);
256+
if (fd >= 0) {
257+
unlink(fname);
258+
ftruncate(fd, size);
259+
}
260+
return fd;
261+
}
262+
247263
/* Borrowed from mm/gup_longterm.c. */
248264
static int get_fs_type(int fd)
249265
{
@@ -259,17 +275,14 @@ static int get_fs_type(int fd)
259275

260276
TEST_F(memory_failure, clean_pagecache)
261277
{
262-
const char *fname = "./clean-page-cache-test-file";
263278
int fd;
264279
char *addr;
265280
int ret;
266281
int fs_type;
267282

268-
fd = open(fname, O_RDWR | O_CREAT, 0664);
283+
fd = prepare_file("./clean-page-cache-test-file", self->page_size);
269284
if (fd < 0)
270285
SKIP(return, "failed to open test file.\n");
271-
unlink(fname);
272-
ftruncate(fd, self->page_size);
273286
fs_type = get_fs_type(fd);
274287
if (!fs_type || fs_type == TMPFS_MAGIC)
275288
SKIP(return, "unsupported filesystem :%x\n", fs_type);
@@ -302,4 +315,45 @@ TEST_F(memory_failure, clean_pagecache)
302315
ASSERT_EQ(close(fd), 0);
303316
}
304317

318+
TEST_F(memory_failure, dirty_pagecache)
319+
{
320+
int fd;
321+
char *addr;
322+
int ret;
323+
int fs_type;
324+
325+
fd = prepare_file("./dirty-page-cache-test-file", self->page_size);
326+
if (fd < 0)
327+
SKIP(return, "failed to open test file.\n");
328+
fs_type = get_fs_type(fd);
329+
if (!fs_type || fs_type == TMPFS_MAGIC)
330+
SKIP(return, "unsupported filesystem :%x\n", fs_type);
331+
332+
addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
333+
MAP_SHARED, fd, 0);
334+
if (addr == MAP_FAILED)
335+
SKIP(return, "mmap failed, not enough memory.\n");
336+
memset(addr, 0xce, self->page_size);
337+
338+
prepare(_metadata, self, addr);
339+
340+
ret = sigsetjmp(signal_jmp_buf, 1);
341+
if (!self->triggered) {
342+
self->triggered = true;
343+
ASSERT_EQ(variant->inject(self, addr), 0);
344+
FORCE_READ(*addr);
345+
}
346+
347+
if (variant->type == MADV_HARD)
348+
check(_metadata, self, addr, MADV_HARD_DIRTY_PAGECACHE, ret);
349+
else
350+
check(_metadata, self, addr, MADV_SOFT_DIRTY_PAGECACHE, ret);
351+
352+
cleanup(_metadata, self, addr);
353+
354+
ASSERT_EQ(munmap(addr, self->page_size), 0);
355+
356+
ASSERT_EQ(close(fd), 0);
357+
}
358+
305359
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)