• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017 Red Hat, Inc.
4  *
5  */
6 
7 /*
8  * Test description: Verify msync() after writing into mmap()-ed file works.
9  *
10  * Write to mapped region and sync the memory back with file. Check the page
11  * is no longer dirty after msync() call.
12  */
13 
14 #include <errno.h>
15 #include "tst_test.h"
16 
17 static int test_fd;
18 static char *mmaped_area;
19 static long pagesize;
20 
21 #define STRING_TO_WRITE	"AAAAAAAAAA"
22 
get_dirty_bit(void * data)23 uint64_t get_dirty_bit(void *data)
24 {
25 	int pagemap_fd, pageflags_fd;
26 	unsigned long addr;
27 	uint64_t pagemap_entry, pageflag_entry, pfn, index;
28 
29 	addr = (unsigned long)data;
30 	index = (addr / pagesize) * sizeof(uint64_t);
31 	pagemap_fd = SAFE_OPEN("/proc/self/pagemap", O_RDONLY);
32 	SAFE_LSEEK(pagemap_fd, index, SEEK_SET);
33 	SAFE_READ(1, pagemap_fd, &pagemap_entry, sizeof(pagemap_entry));
34 	SAFE_CLOSE(pagemap_fd);
35 	pfn = pagemap_entry & ((1ULL << 55) - 1);
36 	if (!pfn)
37 		return 0;
38 	pageflags_fd = SAFE_OPEN("/proc/kpageflags", O_RDONLY);
39 	index = pfn * sizeof(uint64_t);
40 	SAFE_LSEEK(pageflags_fd, index, SEEK_SET);
41 	SAFE_READ(1, pageflags_fd, &pageflag_entry, sizeof(pageflag_entry));
42 	SAFE_CLOSE(pageflags_fd);
43 	return pageflag_entry & (1ULL << 4);
44 }
45 
test_msync(void)46 static void test_msync(void)
47 {
48 	uint64_t dirty;
49 
50 	test_fd = SAFE_OPEN("msync04/testfile", O_CREAT | O_TRUNC | O_RDWR);
51 	SAFE_WRITE(0, test_fd, STRING_TO_WRITE, sizeof(STRING_TO_WRITE) - 1);
52 	mmaped_area = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
53 			MAP_SHARED, test_fd, 0);
54 	SAFE_CLOSE(test_fd);
55 	mmaped_area[8] = 'B';
56 	dirty = get_dirty_bit(mmaped_area);
57 	if (!dirty) {
58 		tst_res(TFAIL, "Expected dirty bit to be set after writing to"
59 				" mmap()-ed area");
60 		goto clean;
61 	}
62 	if (msync(mmaped_area, pagesize, MS_SYNC) < 0) {
63 		tst_res(TFAIL | TERRNO, "msync() failed");
64 		goto clean;
65 	}
66 	dirty = get_dirty_bit(mmaped_area);
67 	if (dirty)
68 		tst_res(TFAIL, "msync() failed to write dirty page despite"
69 				" succeeding");
70 	else
71 		tst_res(TPASS, "msync() working correctly");
72 
73 clean:
74 	SAFE_MUNMAP(mmaped_area, pagesize);
75 	mmaped_area = NULL;
76 }
77 
setup(void)78 static void setup(void)
79 {
80 	pagesize = (off_t)SAFE_SYSCONF(_SC_PAGESIZE);
81 }
82 
cleanup(void)83 static void cleanup(void)
84 {
85 	if (mmaped_area)
86 		SAFE_MUNMAP(mmaped_area, pagesize);
87 
88 	if (test_fd > 0)
89 		SAFE_CLOSE(test_fd);
90 }
91 
92 static struct tst_test test = {
93 	.test_all = test_msync,
94 	.setup = setup,
95 	.cleanup = cleanup,
96 	.needs_root = 1,
97 	.mntpoint = "msync04",
98 	.mount_device = 1,
99 	.all_filesystems = 1,
100 	.min_kver = "2.6.25",
101 };
102