1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 */
6/*
7 * Description:
8 * If one memory is already locked by mlock2() with MLOCK_ONFAULT and then
9 * it is locked again by mlock()(or mlock2() without MLOCK_ONFAULT), the
10 * VmLck field in /proc/pid/status should increase once instead of twice.
11 *
12 * This issue has been fixed in kernel:
13 * 'b155b4fde5bd("mm: mlock: avoid increase mm->locked_vm on mlock() when already mlock2(,MLOCK_ONFAULT)")'
14 */
15#include <errno.h>
16#include <unistd.h>
17#include <sys/mman.h>
18#include <linux/mman.h>
19
20#include "tst_test.h"
21#include "lapi/syscalls.h"
22#include "lapi/mlock2.h"
23
24static unsigned long pgsz;
25static char *addr;
26
27static void verify_mlock2(void)
28{
29	unsigned long bsize, asize1, asize2;
30
31	SAFE_FILE_LINES_SCANF("/proc/self/status", "VmLck: %lu", &bsize);
32
33	TEST(tst_syscall(__NR_mlock2, addr, pgsz, MLOCK_ONFAULT));
34	if (TST_RET != 0) {
35		if (TST_ERR == EINVAL) {
36			tst_res(TCONF,
37				"mlock2() didn't support MLOCK_ONFAULT");
38		} else {
39			tst_res(TFAIL | TTERRNO,
40				"mlock2(MLOCK_ONFAULT) failed");
41		}
42		return;
43	}
44
45	SAFE_FILE_LINES_SCANF("/proc/self/status", "VmLck: %lu", &asize1);
46
47	if ((asize1 - bsize) * 1024 != pgsz) {
48		tst_res(TFAIL,
49			"mlock2(MLOCK_ONFAULT) locked %lu size, expected %lu",
50			(asize1 - bsize) * 1024, pgsz);
51		goto end;
52	}
53
54	TEST(tst_syscall(__NR_mlock2, addr, pgsz, 0));
55	if (TST_RET != 0) {
56		tst_res(TFAIL | TTERRNO, "mlock2() failed");
57		goto end;
58	}
59
60	SAFE_FILE_LINES_SCANF("/proc/self/status", "VmLck: %lu", &asize2);
61
62	if (asize1 != asize2) {
63		tst_res(TFAIL, "Locking one memory again increased VmLck");
64	} else {
65		tst_res(TPASS,
66			"Locking one memory again didn't increased VmLck");
67	}
68
69end:
70	SAFE_MUNLOCK(addr, pgsz);
71}
72
73static void setup(void)
74{
75	pgsz = getpagesize();
76	addr = SAFE_MMAP(NULL, pgsz, PROT_WRITE,
77			 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
78}
79
80static void cleanup(void)
81{
82	if (addr)
83		SAFE_MUNMAP(addr, pgsz);
84}
85
86static struct tst_test test = {
87	.test_all = verify_mlock2,
88	.setup = setup,
89	.cleanup = cleanup,
90	.needs_root = 1,
91};
92