1ff4ef2fbSMiaohe Lin // SPDX-License-Identifier: GPL-2.0
2ff4ef2fbSMiaohe Lin /*
3ff4ef2fbSMiaohe Lin * Memory-failure functional tests.
4ff4ef2fbSMiaohe Lin *
5ff4ef2fbSMiaohe Lin * Author(s): Miaohe Lin <linmiaohe@huawei.com>
6ff4ef2fbSMiaohe Lin */
7ff4ef2fbSMiaohe Lin
8ff4ef2fbSMiaohe Lin #include "../kselftest_harness.h"
9ff4ef2fbSMiaohe Lin
10ff4ef2fbSMiaohe Lin #include <sys/mman.h>
11ff4ef2fbSMiaohe Lin #include <linux/mman.h>
12ff4ef2fbSMiaohe Lin #include <linux/string.h>
1312e8a2faSMiaohe Lin #include <unistd.h>
14ff4ef2fbSMiaohe Lin #include <signal.h>
15ff4ef2fbSMiaohe Lin #include <setjmp.h>
16ff4ef2fbSMiaohe Lin #include <unistd.h>
17ff4ef2fbSMiaohe Lin #include <fcntl.h>
1812e8a2faSMiaohe Lin #include <sys/vfs.h>
1912e8a2faSMiaohe Lin #include <linux/magic.h>
2012e8a2faSMiaohe Lin #include <errno.h>
21ff4ef2fbSMiaohe Lin
22ff4ef2fbSMiaohe Lin #include "vm_util.h"
23ff4ef2fbSMiaohe Lin
24ff4ef2fbSMiaohe Lin enum inject_type {
25ff4ef2fbSMiaohe Lin MADV_HARD,
26ff4ef2fbSMiaohe Lin MADV_SOFT,
27ff4ef2fbSMiaohe Lin };
28ff4ef2fbSMiaohe Lin
29ff4ef2fbSMiaohe Lin enum result_type {
30ff4ef2fbSMiaohe Lin MADV_HARD_ANON,
3112e8a2faSMiaohe Lin MADV_HARD_CLEAN_PAGECACHE,
32*d51b5076SMiaohe Lin MADV_HARD_DIRTY_PAGECACHE,
33ff4ef2fbSMiaohe Lin MADV_SOFT_ANON,
3412e8a2faSMiaohe Lin MADV_SOFT_CLEAN_PAGECACHE,
35*d51b5076SMiaohe Lin MADV_SOFT_DIRTY_PAGECACHE,
36ff4ef2fbSMiaohe Lin };
37ff4ef2fbSMiaohe Lin
38ff4ef2fbSMiaohe Lin static jmp_buf signal_jmp_buf;
39ff4ef2fbSMiaohe Lin static siginfo_t siginfo;
40ff4ef2fbSMiaohe Lin const char *pagemap_proc = "/proc/self/pagemap";
41ff4ef2fbSMiaohe Lin const char *kpageflags_proc = "/proc/kpageflags";
42ff4ef2fbSMiaohe Lin
FIXTURE(memory_failure)43ff4ef2fbSMiaohe Lin FIXTURE(memory_failure)
44ff4ef2fbSMiaohe Lin {
45ff4ef2fbSMiaohe Lin unsigned long page_size;
46ff4ef2fbSMiaohe Lin unsigned long corrupted_size;
47ff4ef2fbSMiaohe Lin unsigned long pfn;
48ff4ef2fbSMiaohe Lin int pagemap_fd;
49ff4ef2fbSMiaohe Lin int kpageflags_fd;
50ff4ef2fbSMiaohe Lin bool triggered;
51ff4ef2fbSMiaohe Lin };
52ff4ef2fbSMiaohe Lin
FIXTURE_VARIANT(memory_failure)53ff4ef2fbSMiaohe Lin FIXTURE_VARIANT(memory_failure)
54ff4ef2fbSMiaohe Lin {
55ff4ef2fbSMiaohe Lin enum inject_type type;
56ff4ef2fbSMiaohe Lin int (*inject)(FIXTURE_DATA(memory_failure) * self, void *vaddr);
57ff4ef2fbSMiaohe Lin };
58ff4ef2fbSMiaohe Lin
madv_hard_inject(FIXTURE_DATA (memory_failure)* self,void * vaddr)59ff4ef2fbSMiaohe Lin static int madv_hard_inject(FIXTURE_DATA(memory_failure) * self, void *vaddr)
60ff4ef2fbSMiaohe Lin {
61ff4ef2fbSMiaohe Lin return madvise(vaddr, self->page_size, MADV_HWPOISON);
62ff4ef2fbSMiaohe Lin }
63ff4ef2fbSMiaohe Lin
FIXTURE_VARIANT_ADD(memory_failure,madv_hard)64ff4ef2fbSMiaohe Lin FIXTURE_VARIANT_ADD(memory_failure, madv_hard)
65ff4ef2fbSMiaohe Lin {
66ff4ef2fbSMiaohe Lin .type = MADV_HARD,
67ff4ef2fbSMiaohe Lin .inject = madv_hard_inject,
68ff4ef2fbSMiaohe Lin };
69ff4ef2fbSMiaohe Lin
madv_soft_inject(FIXTURE_DATA (memory_failure)* self,void * vaddr)70ff4ef2fbSMiaohe Lin static int madv_soft_inject(FIXTURE_DATA(memory_failure) * self, void *vaddr)
71ff4ef2fbSMiaohe Lin {
72ff4ef2fbSMiaohe Lin return madvise(vaddr, self->page_size, MADV_SOFT_OFFLINE);
73ff4ef2fbSMiaohe Lin }
74ff4ef2fbSMiaohe Lin
FIXTURE_VARIANT_ADD(memory_failure,madv_soft)75ff4ef2fbSMiaohe Lin FIXTURE_VARIANT_ADD(memory_failure, madv_soft)
76ff4ef2fbSMiaohe Lin {
77ff4ef2fbSMiaohe Lin .type = MADV_SOFT,
78ff4ef2fbSMiaohe Lin .inject = madv_soft_inject,
79ff4ef2fbSMiaohe Lin };
80ff4ef2fbSMiaohe Lin
sigbus_action(int signo,siginfo_t * si,void * args)81ff4ef2fbSMiaohe Lin static void sigbus_action(int signo, siginfo_t *si, void *args)
82ff4ef2fbSMiaohe Lin {
83ff4ef2fbSMiaohe Lin memcpy(&siginfo, si, sizeof(siginfo_t));
84ff4ef2fbSMiaohe Lin siglongjmp(signal_jmp_buf, 1);
85ff4ef2fbSMiaohe Lin }
86ff4ef2fbSMiaohe Lin
setup_sighandler(void)87ff4ef2fbSMiaohe Lin static int setup_sighandler(void)
88ff4ef2fbSMiaohe Lin {
89ff4ef2fbSMiaohe Lin struct sigaction sa = {
90ff4ef2fbSMiaohe Lin .sa_sigaction = sigbus_action,
91ff4ef2fbSMiaohe Lin .sa_flags = SA_SIGINFO,
92ff4ef2fbSMiaohe Lin };
93ff4ef2fbSMiaohe Lin
94ff4ef2fbSMiaohe Lin return sigaction(SIGBUS, &sa, NULL);
95ff4ef2fbSMiaohe Lin }
96ff4ef2fbSMiaohe Lin
FIXTURE_SETUP(memory_failure)97ff4ef2fbSMiaohe Lin FIXTURE_SETUP(memory_failure)
98ff4ef2fbSMiaohe Lin {
99ff4ef2fbSMiaohe Lin memset(self, 0, sizeof(*self));
100ff4ef2fbSMiaohe Lin
101ff4ef2fbSMiaohe Lin self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
102ff4ef2fbSMiaohe Lin
103ff4ef2fbSMiaohe Lin memset(&siginfo, 0, sizeof(siginfo));
104ff4ef2fbSMiaohe Lin if (setup_sighandler())
105ff4ef2fbSMiaohe Lin SKIP(return, "setup sighandler failed.\n");
106ff4ef2fbSMiaohe Lin
107ff4ef2fbSMiaohe Lin self->pagemap_fd = open(pagemap_proc, O_RDONLY);
108ff4ef2fbSMiaohe Lin if (self->pagemap_fd == -1)
109ff4ef2fbSMiaohe Lin SKIP(return, "open %s failed.\n", pagemap_proc);
110ff4ef2fbSMiaohe Lin
111ff4ef2fbSMiaohe Lin self->kpageflags_fd = open(kpageflags_proc, O_RDONLY);
112ff4ef2fbSMiaohe Lin if (self->kpageflags_fd == -1)
113ff4ef2fbSMiaohe Lin SKIP(return, "open %s failed.\n", kpageflags_proc);
114ff4ef2fbSMiaohe Lin }
115ff4ef2fbSMiaohe Lin
teardown_sighandler(void)116ff4ef2fbSMiaohe Lin static void teardown_sighandler(void)
117ff4ef2fbSMiaohe Lin {
118ff4ef2fbSMiaohe Lin struct sigaction sa = {
119ff4ef2fbSMiaohe Lin .sa_handler = SIG_DFL,
120ff4ef2fbSMiaohe Lin .sa_flags = SA_SIGINFO,
121ff4ef2fbSMiaohe Lin };
122ff4ef2fbSMiaohe Lin
123ff4ef2fbSMiaohe Lin sigaction(SIGBUS, &sa, NULL);
124ff4ef2fbSMiaohe Lin }
125ff4ef2fbSMiaohe Lin
FIXTURE_TEARDOWN(memory_failure)126ff4ef2fbSMiaohe Lin FIXTURE_TEARDOWN(memory_failure)
127ff4ef2fbSMiaohe Lin {
128ff4ef2fbSMiaohe Lin close(self->kpageflags_fd);
129ff4ef2fbSMiaohe Lin close(self->pagemap_fd);
130ff4ef2fbSMiaohe Lin teardown_sighandler();
131ff4ef2fbSMiaohe Lin }
132ff4ef2fbSMiaohe Lin
prepare(struct __test_metadata * _metadata,FIXTURE_DATA (memory_failure)* self,void * vaddr)133ff4ef2fbSMiaohe Lin static void prepare(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure) * self,
134ff4ef2fbSMiaohe Lin void *vaddr)
135ff4ef2fbSMiaohe Lin {
136ff4ef2fbSMiaohe Lin self->pfn = pagemap_get_pfn(self->pagemap_fd, vaddr);
137ff4ef2fbSMiaohe Lin ASSERT_NE(self->pfn, -1UL);
138ff4ef2fbSMiaohe Lin
139ff4ef2fbSMiaohe Lin ASSERT_EQ(get_hardware_corrupted_size(&self->corrupted_size), 0);
140ff4ef2fbSMiaohe Lin }
141ff4ef2fbSMiaohe Lin
check_memory(void * vaddr,unsigned long size)142ff4ef2fbSMiaohe Lin static bool check_memory(void *vaddr, unsigned long size)
143ff4ef2fbSMiaohe Lin {
144ff4ef2fbSMiaohe Lin char buf[64];
145ff4ef2fbSMiaohe Lin
146ff4ef2fbSMiaohe Lin memset(buf, 0xce, sizeof(buf));
147ff4ef2fbSMiaohe Lin while (size >= sizeof(buf)) {
148ff4ef2fbSMiaohe Lin if (memcmp(vaddr, buf, sizeof(buf)))
149ff4ef2fbSMiaohe Lin return false;
150ff4ef2fbSMiaohe Lin size -= sizeof(buf);
151ff4ef2fbSMiaohe Lin vaddr += sizeof(buf);
152ff4ef2fbSMiaohe Lin }
153ff4ef2fbSMiaohe Lin
154ff4ef2fbSMiaohe Lin return true;
155ff4ef2fbSMiaohe Lin }
156ff4ef2fbSMiaohe Lin
check(struct __test_metadata * _metadata,FIXTURE_DATA (memory_failure)* self,void * vaddr,enum result_type type,int setjmp)157ff4ef2fbSMiaohe Lin static void check(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure) * self,
158ff4ef2fbSMiaohe Lin void *vaddr, enum result_type type, int setjmp)
159ff4ef2fbSMiaohe Lin {
160ff4ef2fbSMiaohe Lin unsigned long size;
161ff4ef2fbSMiaohe Lin uint64_t pfn_flags;
162ff4ef2fbSMiaohe Lin
163ff4ef2fbSMiaohe Lin switch (type) {
164ff4ef2fbSMiaohe Lin case MADV_SOFT_ANON:
16512e8a2faSMiaohe Lin case MADV_HARD_CLEAN_PAGECACHE:
16612e8a2faSMiaohe Lin case MADV_SOFT_CLEAN_PAGECACHE:
167*d51b5076SMiaohe Lin case MADV_SOFT_DIRTY_PAGECACHE:
168ff4ef2fbSMiaohe Lin /* It is not expected to receive a SIGBUS signal. */
169ff4ef2fbSMiaohe Lin ASSERT_EQ(setjmp, 0);
170ff4ef2fbSMiaohe Lin
171ff4ef2fbSMiaohe Lin /* The page content should remain unchanged. */
172ff4ef2fbSMiaohe Lin ASSERT_TRUE(check_memory(vaddr, self->page_size));
173ff4ef2fbSMiaohe Lin
174ff4ef2fbSMiaohe Lin /* The backing pfn of addr should have changed. */
175ff4ef2fbSMiaohe Lin ASSERT_NE(pagemap_get_pfn(self->pagemap_fd, vaddr), self->pfn);
176ff4ef2fbSMiaohe Lin break;
177ff4ef2fbSMiaohe Lin case MADV_HARD_ANON:
178*d51b5076SMiaohe Lin case MADV_HARD_DIRTY_PAGECACHE:
179ff4ef2fbSMiaohe Lin /* The SIGBUS signal should have been received. */
180ff4ef2fbSMiaohe Lin ASSERT_EQ(setjmp, 1);
181ff4ef2fbSMiaohe Lin
182ff4ef2fbSMiaohe Lin /* Check if siginfo contains correct SIGBUS context. */
183ff4ef2fbSMiaohe Lin ASSERT_EQ(siginfo.si_signo, SIGBUS);
184ff4ef2fbSMiaohe Lin ASSERT_EQ(siginfo.si_code, BUS_MCEERR_AR);
185ff4ef2fbSMiaohe Lin ASSERT_EQ(1UL << siginfo.si_addr_lsb, self->page_size);
186ff4ef2fbSMiaohe Lin ASSERT_EQ(siginfo.si_addr, vaddr);
187ff4ef2fbSMiaohe Lin
188ff4ef2fbSMiaohe Lin /* XXX Check backing pte is hwpoison entry when supported. */
189ff4ef2fbSMiaohe Lin ASSERT_TRUE(pagemap_is_swapped(self->pagemap_fd, vaddr));
190ff4ef2fbSMiaohe Lin break;
191ff4ef2fbSMiaohe Lin default:
192ff4ef2fbSMiaohe Lin SKIP(return, "unexpected inject type %d.\n", type);
193ff4ef2fbSMiaohe Lin }
194ff4ef2fbSMiaohe Lin
195ff4ef2fbSMiaohe Lin /* Check if the value of HardwareCorrupted has increased. */
196ff4ef2fbSMiaohe Lin ASSERT_EQ(get_hardware_corrupted_size(&size), 0);
197ff4ef2fbSMiaohe Lin ASSERT_EQ(size, self->corrupted_size + self->page_size / 1024);
198ff4ef2fbSMiaohe Lin
199ff4ef2fbSMiaohe Lin /* Check if HWPoison flag is set. */
200ff4ef2fbSMiaohe Lin ASSERT_EQ(pageflags_get(self->pfn, self->kpageflags_fd, &pfn_flags), 0);
201ff4ef2fbSMiaohe Lin ASSERT_EQ(pfn_flags & KPF_HWPOISON, KPF_HWPOISON);
202ff4ef2fbSMiaohe Lin }
203ff4ef2fbSMiaohe Lin
cleanup(struct __test_metadata * _metadata,FIXTURE_DATA (memory_failure)* self,void * vaddr)204ff4ef2fbSMiaohe Lin static void cleanup(struct __test_metadata *_metadata, FIXTURE_DATA(memory_failure) * self,
205ff4ef2fbSMiaohe Lin void *vaddr)
206ff4ef2fbSMiaohe Lin {
207ff4ef2fbSMiaohe Lin unsigned long size;
208ff4ef2fbSMiaohe Lin uint64_t pfn_flags;
209ff4ef2fbSMiaohe Lin
210ff4ef2fbSMiaohe Lin ASSERT_EQ(unpoison_memory(self->pfn), 0);
211ff4ef2fbSMiaohe Lin
212ff4ef2fbSMiaohe Lin /* Check if HWPoison flag is cleared. */
213ff4ef2fbSMiaohe Lin ASSERT_EQ(pageflags_get(self->pfn, self->kpageflags_fd, &pfn_flags), 0);
214ff4ef2fbSMiaohe Lin ASSERT_NE(pfn_flags & KPF_HWPOISON, KPF_HWPOISON);
215ff4ef2fbSMiaohe Lin
216ff4ef2fbSMiaohe Lin /* Check if the value of HardwareCorrupted has decreased. */
217ff4ef2fbSMiaohe Lin ASSERT_EQ(get_hardware_corrupted_size(&size), 0);
218ff4ef2fbSMiaohe Lin ASSERT_EQ(size, self->corrupted_size);
219ff4ef2fbSMiaohe Lin }
220ff4ef2fbSMiaohe Lin
TEST_F(memory_failure,anon)221ff4ef2fbSMiaohe Lin TEST_F(memory_failure, anon)
222ff4ef2fbSMiaohe Lin {
223ff4ef2fbSMiaohe Lin char *addr;
224ff4ef2fbSMiaohe Lin int ret;
225ff4ef2fbSMiaohe Lin
226ff4ef2fbSMiaohe Lin addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
227ff4ef2fbSMiaohe Lin MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
228ff4ef2fbSMiaohe Lin if (addr == MAP_FAILED)
229ff4ef2fbSMiaohe Lin SKIP(return, "mmap failed, not enough memory.\n");
230ff4ef2fbSMiaohe Lin memset(addr, 0xce, self->page_size);
231ff4ef2fbSMiaohe Lin
232ff4ef2fbSMiaohe Lin prepare(_metadata, self, addr);
233ff4ef2fbSMiaohe Lin
234ff4ef2fbSMiaohe Lin ret = sigsetjmp(signal_jmp_buf, 1);
235ff4ef2fbSMiaohe Lin if (!self->triggered) {
236ff4ef2fbSMiaohe Lin self->triggered = true;
237ff4ef2fbSMiaohe Lin ASSERT_EQ(variant->inject(self, addr), 0);
238ff4ef2fbSMiaohe Lin FORCE_READ(*addr);
239ff4ef2fbSMiaohe Lin }
240ff4ef2fbSMiaohe Lin
241ff4ef2fbSMiaohe Lin if (variant->type == MADV_HARD)
242ff4ef2fbSMiaohe Lin check(_metadata, self, addr, MADV_HARD_ANON, ret);
243ff4ef2fbSMiaohe Lin else
244ff4ef2fbSMiaohe Lin check(_metadata, self, addr, MADV_SOFT_ANON, ret);
245ff4ef2fbSMiaohe Lin
246ff4ef2fbSMiaohe Lin cleanup(_metadata, self, addr);
247ff4ef2fbSMiaohe Lin
248ff4ef2fbSMiaohe Lin ASSERT_EQ(munmap(addr, self->page_size), 0);
249ff4ef2fbSMiaohe Lin }
250ff4ef2fbSMiaohe Lin
prepare_file(const char * fname,unsigned long size)251*d51b5076SMiaohe Lin static int prepare_file(const char *fname, unsigned long size)
252*d51b5076SMiaohe Lin {
253*d51b5076SMiaohe Lin int fd;
254*d51b5076SMiaohe Lin
255*d51b5076SMiaohe Lin fd = open(fname, O_RDWR | O_CREAT, 0664);
256*d51b5076SMiaohe Lin if (fd >= 0) {
257*d51b5076SMiaohe Lin unlink(fname);
258*d51b5076SMiaohe Lin ftruncate(fd, size);
259*d51b5076SMiaohe Lin }
260*d51b5076SMiaohe Lin return fd;
261*d51b5076SMiaohe Lin }
262*d51b5076SMiaohe Lin
26312e8a2faSMiaohe Lin /* Borrowed from mm/gup_longterm.c. */
get_fs_type(int fd)26412e8a2faSMiaohe Lin static int get_fs_type(int fd)
26512e8a2faSMiaohe Lin {
26612e8a2faSMiaohe Lin struct statfs fs;
26712e8a2faSMiaohe Lin int ret;
26812e8a2faSMiaohe Lin
26912e8a2faSMiaohe Lin do {
27012e8a2faSMiaohe Lin ret = fstatfs(fd, &fs);
27112e8a2faSMiaohe Lin } while (ret && errno == EINTR);
27212e8a2faSMiaohe Lin
27312e8a2faSMiaohe Lin return ret ? 0 : (int)fs.f_type;
27412e8a2faSMiaohe Lin }
27512e8a2faSMiaohe Lin
TEST_F(memory_failure,clean_pagecache)27612e8a2faSMiaohe Lin TEST_F(memory_failure, clean_pagecache)
27712e8a2faSMiaohe Lin {
27812e8a2faSMiaohe Lin int fd;
27912e8a2faSMiaohe Lin char *addr;
28012e8a2faSMiaohe Lin int ret;
28112e8a2faSMiaohe Lin int fs_type;
28212e8a2faSMiaohe Lin
283*d51b5076SMiaohe Lin fd = prepare_file("./clean-page-cache-test-file", self->page_size);
28412e8a2faSMiaohe Lin if (fd < 0)
28512e8a2faSMiaohe Lin SKIP(return, "failed to open test file.\n");
28612e8a2faSMiaohe Lin fs_type = get_fs_type(fd);
28712e8a2faSMiaohe Lin if (!fs_type || fs_type == TMPFS_MAGIC)
28812e8a2faSMiaohe Lin SKIP(return, "unsupported filesystem :%x\n", fs_type);
28912e8a2faSMiaohe Lin
29012e8a2faSMiaohe Lin addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
29112e8a2faSMiaohe Lin MAP_SHARED, fd, 0);
29212e8a2faSMiaohe Lin if (addr == MAP_FAILED)
29312e8a2faSMiaohe Lin SKIP(return, "mmap failed, not enough memory.\n");
29412e8a2faSMiaohe Lin memset(addr, 0xce, self->page_size);
29512e8a2faSMiaohe Lin fsync(fd);
29612e8a2faSMiaohe Lin
29712e8a2faSMiaohe Lin prepare(_metadata, self, addr);
29812e8a2faSMiaohe Lin
29912e8a2faSMiaohe Lin ret = sigsetjmp(signal_jmp_buf, 1);
30012e8a2faSMiaohe Lin if (!self->triggered) {
30112e8a2faSMiaohe Lin self->triggered = true;
30212e8a2faSMiaohe Lin ASSERT_EQ(variant->inject(self, addr), 0);
30312e8a2faSMiaohe Lin FORCE_READ(*addr);
30412e8a2faSMiaohe Lin }
30512e8a2faSMiaohe Lin
30612e8a2faSMiaohe Lin if (variant->type == MADV_HARD)
30712e8a2faSMiaohe Lin check(_metadata, self, addr, MADV_HARD_CLEAN_PAGECACHE, ret);
30812e8a2faSMiaohe Lin else
30912e8a2faSMiaohe Lin check(_metadata, self, addr, MADV_SOFT_CLEAN_PAGECACHE, ret);
31012e8a2faSMiaohe Lin
31112e8a2faSMiaohe Lin cleanup(_metadata, self, addr);
31212e8a2faSMiaohe Lin
31312e8a2faSMiaohe Lin ASSERT_EQ(munmap(addr, self->page_size), 0);
31412e8a2faSMiaohe Lin
31512e8a2faSMiaohe Lin ASSERT_EQ(close(fd), 0);
31612e8a2faSMiaohe Lin }
31712e8a2faSMiaohe Lin
TEST_F(memory_failure,dirty_pagecache)318*d51b5076SMiaohe Lin TEST_F(memory_failure, dirty_pagecache)
319*d51b5076SMiaohe Lin {
320*d51b5076SMiaohe Lin int fd;
321*d51b5076SMiaohe Lin char *addr;
322*d51b5076SMiaohe Lin int ret;
323*d51b5076SMiaohe Lin int fs_type;
324*d51b5076SMiaohe Lin
325*d51b5076SMiaohe Lin fd = prepare_file("./dirty-page-cache-test-file", self->page_size);
326*d51b5076SMiaohe Lin if (fd < 0)
327*d51b5076SMiaohe Lin SKIP(return, "failed to open test file.\n");
328*d51b5076SMiaohe Lin fs_type = get_fs_type(fd);
329*d51b5076SMiaohe Lin if (!fs_type || fs_type == TMPFS_MAGIC)
330*d51b5076SMiaohe Lin SKIP(return, "unsupported filesystem :%x\n", fs_type);
331*d51b5076SMiaohe Lin
332*d51b5076SMiaohe Lin addr = mmap(0, self->page_size, PROT_READ | PROT_WRITE,
333*d51b5076SMiaohe Lin MAP_SHARED, fd, 0);
334*d51b5076SMiaohe Lin if (addr == MAP_FAILED)
335*d51b5076SMiaohe Lin SKIP(return, "mmap failed, not enough memory.\n");
336*d51b5076SMiaohe Lin memset(addr, 0xce, self->page_size);
337*d51b5076SMiaohe Lin
338*d51b5076SMiaohe Lin prepare(_metadata, self, addr);
339*d51b5076SMiaohe Lin
340*d51b5076SMiaohe Lin ret = sigsetjmp(signal_jmp_buf, 1);
341*d51b5076SMiaohe Lin if (!self->triggered) {
342*d51b5076SMiaohe Lin self->triggered = true;
343*d51b5076SMiaohe Lin ASSERT_EQ(variant->inject(self, addr), 0);
344*d51b5076SMiaohe Lin FORCE_READ(*addr);
345*d51b5076SMiaohe Lin }
346*d51b5076SMiaohe Lin
347*d51b5076SMiaohe Lin if (variant->type == MADV_HARD)
348*d51b5076SMiaohe Lin check(_metadata, self, addr, MADV_HARD_DIRTY_PAGECACHE, ret);
349*d51b5076SMiaohe Lin else
350*d51b5076SMiaohe Lin check(_metadata, self, addr, MADV_SOFT_DIRTY_PAGECACHE, ret);
351*d51b5076SMiaohe Lin
352*d51b5076SMiaohe Lin cleanup(_metadata, self, addr);
353*d51b5076SMiaohe Lin
354*d51b5076SMiaohe Lin ASSERT_EQ(munmap(addr, self->page_size), 0);
355*d51b5076SMiaohe Lin
356*d51b5076SMiaohe Lin ASSERT_EQ(close(fd), 0);
357*d51b5076SMiaohe Lin }
358*d51b5076SMiaohe Lin
359ff4ef2fbSMiaohe Lin TEST_HARNESS_MAIN
360