Skip to content

Commit eea274d

Browse files
Michal Hockotorvalds
authored andcommitted
selftests: vm: drop dependencies on page flags from mlock2 tests
It was noticed that mlock2 tests are failing after 9c4e6b1 ("mm, mlock, vmscan: no more skipping pagevecs") because the patch has changed the timing on when the page is added to the unevictable LRU list and thus gains the unevictable page flag. The test was just too dependent on the implementation details which were true at the time when it was introduced. Page flags and the timing when they are set is something no userspace should ever depend on. The test should be testing only for the user observable contract of the tested syscalls. Those are defined pretty well for the mlock and there are other means for testing them. In fact this is already done and testing for page flags can be safely dropped to achieve the aimed purpose. Present bits can be checked by /proc/<pid>/smaps RSS field and the locking state by VmFlags although I would argue that Locked: field would be more appropriate. Drop all the page flag machinery and considerably simplify the test. This should be more robust for future kernel changes while checking the promised contract is still valid. Fixes: 9c4e6b1 ("mm, mlock, vmscan: no more skipping pagevecs") Reported-by: Rafael Aquini <[email protected]> Signed-off-by: Michal Hocko <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Acked-by: Rafael Aquini <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Eric B Munson <[email protected]> Cc: Shuah Khan <[email protected]> Cc: <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent c4ecddf commit eea274d

File tree

1 file changed

+37
-196
lines changed

1 file changed

+37
-196
lines changed

tools/testing/selftests/vm/mlock2-tests.c

Lines changed: 37 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -67,59 +67,6 @@ static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
6767
return ret;
6868
}
6969

70-
static uint64_t get_pageflags(unsigned long addr)
71-
{
72-
FILE *file;
73-
uint64_t pfn;
74-
unsigned long offset;
75-
76-
file = fopen("/proc/self/pagemap", "r");
77-
if (!file) {
78-
perror("fopen pagemap");
79-
_exit(1);
80-
}
81-
82-
offset = addr / getpagesize() * sizeof(pfn);
83-
84-
if (fseek(file, offset, SEEK_SET)) {
85-
perror("fseek pagemap");
86-
_exit(1);
87-
}
88-
89-
if (fread(&pfn, sizeof(pfn), 1, file) != 1) {
90-
perror("fread pagemap");
91-
_exit(1);
92-
}
93-
94-
fclose(file);
95-
return pfn;
96-
}
97-
98-
static uint64_t get_kpageflags(unsigned long pfn)
99-
{
100-
uint64_t flags;
101-
FILE *file;
102-
103-
file = fopen("/proc/kpageflags", "r");
104-
if (!file) {
105-
perror("fopen kpageflags");
106-
_exit(1);
107-
}
108-
109-
if (fseek(file, pfn * sizeof(flags), SEEK_SET)) {
110-
perror("fseek kpageflags");
111-
_exit(1);
112-
}
113-
114-
if (fread(&flags, sizeof(flags), 1, file) != 1) {
115-
perror("fread kpageflags");
116-
_exit(1);
117-
}
118-
119-
fclose(file);
120-
return flags;
121-
}
122-
12370
#define VMFLAGS "VmFlags:"
12471

12572
static bool is_vmflag_set(unsigned long addr, const char *vmflag)
@@ -159,19 +106,13 @@ static bool is_vmflag_set(unsigned long addr, const char *vmflag)
159106
#define RSS "Rss:"
160107
#define LOCKED "lo"
161108

162-
static bool is_vma_lock_on_fault(unsigned long addr)
109+
static unsigned long get_value_for_name(unsigned long addr, const char *name)
163110
{
164-
bool ret = false;
165-
bool locked;
166-
FILE *smaps = NULL;
167-
unsigned long vma_size, vma_rss;
168111
char *line = NULL;
169-
char *value;
170112
size_t size = 0;
171-
172-
locked = is_vmflag_set(addr, LOCKED);
173-
if (!locked)
174-
goto out;
113+
char *value_ptr;
114+
FILE *smaps = NULL;
115+
unsigned long value = -1UL;
175116

176117
smaps = seek_to_smaps_entry(addr);
177118
if (!smaps) {
@@ -180,112 +121,70 @@ static bool is_vma_lock_on_fault(unsigned long addr)
180121
}
181122

182123
while (getline(&line, &size, smaps) > 0) {
183-
if (!strstr(line, SIZE)) {
124+
if (!strstr(line, name)) {
184125
free(line);
185126
line = NULL;
186127
size = 0;
187128
continue;
188129
}
189130

190-
value = line + strlen(SIZE);
191-
if (sscanf(value, "%lu kB", &vma_size) < 1) {
131+
value_ptr = line + strlen(name);
132+
if (sscanf(value_ptr, "%lu kB", &value) < 1) {
192133
printf("Unable to parse smaps entry for Size\n");
193134
goto out;
194135
}
195136
break;
196137
}
197138

198-
while (getline(&line, &size, smaps) > 0) {
199-
if (!strstr(line, RSS)) {
200-
free(line);
201-
line = NULL;
202-
size = 0;
203-
continue;
204-
}
205-
206-
value = line + strlen(RSS);
207-
if (sscanf(value, "%lu kB", &vma_rss) < 1) {
208-
printf("Unable to parse smaps entry for Rss\n");
209-
goto out;
210-
}
211-
break;
212-
}
213-
214-
ret = locked && (vma_rss < vma_size);
215139
out:
216-
free(line);
217140
if (smaps)
218141
fclose(smaps);
219-
return ret;
142+
free(line);
143+
return value;
220144
}
221145

222-
#define PRESENT_BIT 0x8000000000000000ULL
223-
#define PFN_MASK 0x007FFFFFFFFFFFFFULL
224-
#define UNEVICTABLE_BIT (1UL << 18)
225-
226-
static int lock_check(char *map)
146+
static bool is_vma_lock_on_fault(unsigned long addr)
227147
{
228-
unsigned long page_size = getpagesize();
229-
uint64_t page1_flags, page2_flags;
148+
bool locked;
149+
unsigned long vma_size, vma_rss;
230150

231-
page1_flags = get_pageflags((unsigned long)map);
232-
page2_flags = get_pageflags((unsigned long)map + page_size);
151+
locked = is_vmflag_set(addr, LOCKED);
152+
if (!locked)
153+
return false;
233154

234-
/* Both pages should be present */
235-
if (((page1_flags & PRESENT_BIT) == 0) ||
236-
((page2_flags & PRESENT_BIT) == 0)) {
237-
printf("Failed to make both pages present\n");
238-
return 1;
239-
}
155+
vma_size = get_value_for_name(addr, SIZE);
156+
vma_rss = get_value_for_name(addr, RSS);
240157

241-
page1_flags = get_kpageflags(page1_flags & PFN_MASK);
242-
page2_flags = get_kpageflags(page2_flags & PFN_MASK);
158+
/* only one page is faulted in */
159+
return (vma_rss < vma_size);
160+
}
243161

244-
/* Both pages should be unevictable */
245-
if (((page1_flags & UNEVICTABLE_BIT) == 0) ||
246-
((page2_flags & UNEVICTABLE_BIT) == 0)) {
247-
printf("Failed to make both pages unevictable\n");
248-
return 1;
249-
}
162+
#define PRESENT_BIT 0x8000000000000000ULL
163+
#define PFN_MASK 0x007FFFFFFFFFFFFFULL
164+
#define UNEVICTABLE_BIT (1UL << 18)
250165

251-
if (!is_vmflag_set((unsigned long)map, LOCKED)) {
252-
printf("VMA flag %s is missing on page 1\n", LOCKED);
253-
return 1;
254-
}
166+
static int lock_check(unsigned long addr)
167+
{
168+
bool locked;
169+
unsigned long vma_size, vma_rss;
255170

256-
if (!is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
257-
printf("VMA flag %s is missing on page 2\n", LOCKED);
258-
return 1;
259-
}
171+
locked = is_vmflag_set(addr, LOCKED);
172+
if (!locked)
173+
return false;
260174

261-
return 0;
175+
vma_size = get_value_for_name(addr, SIZE);
176+
vma_rss = get_value_for_name(addr, RSS);
177+
178+
return (vma_rss == vma_size);
262179
}
263180

264181
static int unlock_lock_check(char *map)
265182
{
266-
unsigned long page_size = getpagesize();
267-
uint64_t page1_flags, page2_flags;
268-
269-
page1_flags = get_pageflags((unsigned long)map);
270-
page2_flags = get_pageflags((unsigned long)map + page_size);
271-
page1_flags = get_kpageflags(page1_flags & PFN_MASK);
272-
page2_flags = get_kpageflags(page2_flags & PFN_MASK);
273-
274-
if ((page1_flags & UNEVICTABLE_BIT) || (page2_flags & UNEVICTABLE_BIT)) {
275-
printf("A page is still marked unevictable after unlock\n");
276-
return 1;
277-
}
278-
279183
if (is_vmflag_set((unsigned long)map, LOCKED)) {
280184
printf("VMA flag %s is present on page 1 after unlock\n", LOCKED);
281185
return 1;
282186
}
283187

284-
if (is_vmflag_set((unsigned long)map + page_size, LOCKED)) {
285-
printf("VMA flag %s is present on page 2 after unlock\n", LOCKED);
286-
return 1;
287-
}
288-
289188
return 0;
290189
}
291190

@@ -311,7 +210,7 @@ static int test_mlock_lock()
311210
goto unmap;
312211
}
313212

314-
if (lock_check(map))
213+
if (!lock_check((unsigned long)map))
315214
goto unmap;
316215

317216
/* Now unlock and recheck attributes */
@@ -330,64 +229,18 @@ static int test_mlock_lock()
330229

331230
static int onfault_check(char *map)
332231
{
333-
unsigned long page_size = getpagesize();
334-
uint64_t page1_flags, page2_flags;
335-
336-
page1_flags = get_pageflags((unsigned long)map);
337-
page2_flags = get_pageflags((unsigned long)map + page_size);
338-
339-
/* Neither page should be present */
340-
if ((page1_flags & PRESENT_BIT) || (page2_flags & PRESENT_BIT)) {
341-
printf("Pages were made present by MLOCK_ONFAULT\n");
342-
return 1;
343-
}
344-
345232
*map = 'a';
346-
page1_flags = get_pageflags((unsigned long)map);
347-
page2_flags = get_pageflags((unsigned long)map + page_size);
348-
349-
/* Only page 1 should be present */
350-
if ((page1_flags & PRESENT_BIT) == 0) {
351-
printf("Page 1 is not present after fault\n");
352-
return 1;
353-
} else if (page2_flags & PRESENT_BIT) {
354-
printf("Page 2 was made present\n");
355-
return 1;
356-
}
357-
358-
page1_flags = get_kpageflags(page1_flags & PFN_MASK);
359-
360-
/* Page 1 should be unevictable */
361-
if ((page1_flags & UNEVICTABLE_BIT) == 0) {
362-
printf("Failed to make faulted page unevictable\n");
363-
return 1;
364-
}
365-
366233
if (!is_vma_lock_on_fault((unsigned long)map)) {
367234
printf("VMA is not marked for lock on fault\n");
368235
return 1;
369236
}
370237

371-
if (!is_vma_lock_on_fault((unsigned long)map + page_size)) {
372-
printf("VMA is not marked for lock on fault\n");
373-
return 1;
374-
}
375-
376238
return 0;
377239
}
378240

379241
static int unlock_onfault_check(char *map)
380242
{
381243
unsigned long page_size = getpagesize();
382-
uint64_t page1_flags;
383-
384-
page1_flags = get_pageflags((unsigned long)map);
385-
page1_flags = get_kpageflags(page1_flags & PFN_MASK);
386-
387-
if (page1_flags & UNEVICTABLE_BIT) {
388-
printf("Page 1 is still marked unevictable after unlock\n");
389-
return 1;
390-
}
391244

392245
if (is_vma_lock_on_fault((unsigned long)map) ||
393246
is_vma_lock_on_fault((unsigned long)map + page_size)) {
@@ -445,7 +298,6 @@ static int test_lock_onfault_of_present()
445298
char *map;
446299
int ret = 1;
447300
unsigned long page_size = getpagesize();
448-
uint64_t page1_flags, page2_flags;
449301

450302
map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
451303
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -465,17 +317,6 @@ static int test_lock_onfault_of_present()
465317
goto unmap;
466318
}
467319

468-
page1_flags = get_pageflags((unsigned long)map);
469-
page2_flags = get_pageflags((unsigned long)map + page_size);
470-
page1_flags = get_kpageflags(page1_flags & PFN_MASK);
471-
page2_flags = get_kpageflags(page2_flags & PFN_MASK);
472-
473-
/* Page 1 should be unevictable */
474-
if ((page1_flags & UNEVICTABLE_BIT) == 0) {
475-
printf("Failed to make present page unevictable\n");
476-
goto unmap;
477-
}
478-
479320
if (!is_vma_lock_on_fault((unsigned long)map) ||
480321
!is_vma_lock_on_fault((unsigned long)map + page_size)) {
481322
printf("VMA with present pages is not marked lock on fault\n");
@@ -507,7 +348,7 @@ static int test_munlockall()
507348
goto out;
508349
}
509350

510-
if (lock_check(map))
351+
if (!lock_check((unsigned long)map))
511352
goto unmap;
512353

513354
if (munlockall()) {
@@ -549,7 +390,7 @@ static int test_munlockall()
549390
goto out;
550391
}
551392

552-
if (lock_check(map))
393+
if (!lock_check((unsigned long)map))
553394
goto unmap;
554395

555396
if (munlockall()) {

0 commit comments

Comments
 (0)