enum result_type {
MADV_HARD_ANON,
MADV_HARD_CLEAN_PAGECACHE,
+ MADV_HARD_DIRTY_PAGECACHE,
MADV_SOFT_ANON,
MADV_SOFT_CLEAN_PAGECACHE,
+ MADV_SOFT_DIRTY_PAGECACHE,
};
static jmp_buf signal_jmp_buf;
case MADV_SOFT_ANON:
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);
ASSERT_NE(pagemap_get_pfn(self->pagemap_fd, vaddr), self->pfn);
break;
case MADV_HARD_ANON:
+ case MADV_HARD_DIRTY_PAGECACHE:
/* The SIGBUS signal should have been received. */
ASSERT_EQ(setjmp, 1);
ASSERT_EQ(munmap(addr, self->page_size), 0);
}
+static int prepare_file(const char *fname, unsigned long size)
+{
+ int fd;
+
+ fd = open(fname, O_RDWR | O_CREAT, 0664);
+ if (fd >= 0) {
+ unlink(fname);
+ ftruncate(fd, size);
+ }
+ return fd;
+}
+
/* Borrowed from mm/gup_longterm.c. */
static int get_fs_type(int fd)
{
TEST_F(memory_failure, clean_pagecache)
{
- const char *fname = "./clean-page-cache-test-file";
int fd;
char *addr;
int ret;
int fs_type;
- fd = open(fname, O_RDWR | O_CREAT, 0664);
+ fd = prepare_file("./clean-page-cache-test-file", self->page_size);
if (fd < 0)
SKIP(return, "failed to open test file.\n");
- unlink(fname);
- ftruncate(fd, self->page_size);
fs_type = get_fs_type(fd);
if (!fs_type || fs_type == TMPFS_MAGIC)
SKIP(return, "unsupported filesystem :%x\n", fs_type);
ASSERT_EQ(close(fd), 0);
}
+TEST_F(memory_failure, dirty_pagecache)
+{
+ int fd;
+ char *addr;
+ int ret;
+ int fs_type;
+
+ fd = prepare_file("./dirty-page-cache-test-file", self->page_size);
+ if (fd < 0)
+ SKIP(return, "failed to open test file.\n");
+ fs_type = get_fs_type(fd);
+ if (!fs_type || fs_type == TMPFS_MAGIC)
+ SKIP(return, "unsupported filesystem :%x\n", fs_type);
+
+ addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED)
+ 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 (!self->triggered) {
+ self->triggered = true;
+ ASSERT_EQ(variant->inject(self, addr), 0);
+ FORCE_READ(*addr);
+ }
+
+ if (variant->type == MADV_HARD)
+ check(_metadata, self, addr, MADV_HARD_DIRTY_PAGECACHE, ret);
+ else
+ check(_metadata, self, addr, MADV_SOFT_DIRTY_PAGECACHE, ret);
+
+ cleanup(_metadata, self, addr);
+
+ ASSERT_EQ(munmap(addr, self->page_size), 0);
+
+ ASSERT_EQ(close(fd), 0);
+}
+
TEST_HARNESS_MAIN