Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Miaohe Lin and committed by
Andrew Morton
d51b5076 12e8a2fa

+58 -4
+58 -4
tools/testing/selftests/mm/memory-failure.c
··· 29 29 enum result_type { 30 30 MADV_HARD_ANON, 31 31 MADV_HARD_CLEAN_PAGECACHE, 32 + MADV_HARD_DIRTY_PAGECACHE, 32 33 MADV_SOFT_ANON, 33 34 MADV_SOFT_CLEAN_PAGECACHE, 35 + MADV_SOFT_DIRTY_PAGECACHE, 34 36 }; 35 37 36 38 static jmp_buf signal_jmp_buf; ··· 164 162 case MADV_SOFT_ANON: 165 163 case MADV_HARD_CLEAN_PAGECACHE: 166 164 case MADV_SOFT_CLEAN_PAGECACHE: 165 + case MADV_SOFT_DIRTY_PAGECACHE: 167 166 /* It is not expected to receive a SIGBUS signal. */ 168 167 ASSERT_EQ(setjmp, 0); 169 168 ··· 175 172 ASSERT_NE(pagemap_get_pfn(self->pagemap_fd, vaddr), self->pfn); 176 173 break; 177 174 case MADV_HARD_ANON: 175 + case MADV_HARD_DIRTY_PAGECACHE: 178 176 /* The SIGBUS signal should have been received. */ 179 177 ASSERT_EQ(setjmp, 1); 180 178 ··· 248 244 ASSERT_EQ(munmap(addr, self->page_size), 0); 249 245 } 250 246 247 + static int prepare_file(const char *fname, unsigned long size) 248 + { 249 + int fd; 250 + 251 + fd = open(fname, O_RDWR | O_CREAT, 0664); 252 + if (fd >= 0) { 253 + unlink(fname); 254 + ftruncate(fd, size); 255 + } 256 + return fd; 257 + } 258 + 251 259 /* Borrowed from mm/gup_longterm.c. */ 252 260 static int get_fs_type(int fd) 253 261 { ··· 275 259 276 260 TEST_F(memory_failure, clean_pagecache) 277 261 { 278 - const char *fname = "./clean-page-cache-test-file"; 279 262 int fd; 280 263 char *addr; 281 264 int ret; 282 265 int fs_type; 283 266 284 - fd = open(fname, O_RDWR | O_CREAT, 0664); 267 + fd = prepare_file("./clean-page-cache-test-file", self->page_size); 285 268 if (fd < 0) 286 269 SKIP(return, "failed to open test file.\n"); 287 - unlink(fname); 288 - ftruncate(fd, self->page_size); 289 270 fs_type = get_fs_type(fd); 290 271 if (!fs_type || fs_type == TMPFS_MAGIC) 291 272 SKIP(return, "unsupported filesystem :%x\n", fs_type); ··· 307 294 check(_metadata, self, addr, MADV_HARD_CLEAN_PAGECACHE, ret); 308 295 else 309 296 check(_metadata, self, addr, MADV_SOFT_CLEAN_PAGECACHE, ret); 297 + 298 + cleanup(_metadata, self, addr); 299 + 300 + ASSERT_EQ(munmap(addr, self->page_size), 0); 301 + 302 + ASSERT_EQ(close(fd), 0); 303 + } 304 + 305 + TEST_F(memory_failure, dirty_pagecache) 306 + { 307 + int fd; 308 + char *addr; 309 + int ret; 310 + int fs_type; 311 + 312 + fd = prepare_file("./dirty-page-cache-test-file", self->page_size); 313 + if (fd < 0) 314 + SKIP(return, "failed to open test file.\n"); 315 + fs_type = get_fs_type(fd); 316 + if (!fs_type || fs_type == TMPFS_MAGIC) 317 + SKIP(return, "unsupported filesystem :%x\n", fs_type); 318 + 319 + addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE, 320 + MAP_SHARED, fd, 0); 321 + if (addr == MAP_FAILED) 322 + SKIP(return, "mmap failed, not enough memory.\n"); 323 + memset(addr, 0xce, self->page_size); 324 + 325 + prepare(_metadata, self, addr); 326 + 327 + ret = sigsetjmp(signal_jmp_buf, 1); 328 + if (!self->triggered) { 329 + self->triggered = true; 330 + ASSERT_EQ(variant->inject(self, addr), 0); 331 + FORCE_READ(*addr); 332 + } 333 + 334 + if (variant->type == MADV_HARD) 335 + check(_metadata, self, addr, MADV_HARD_DIRTY_PAGECACHE, ret); 336 + else 337 + check(_metadata, self, addr, MADV_SOFT_DIRTY_PAGECACHE, ret); 310 338 311 339 cleanup(_metadata, self, addr); 312 340