xref: /freebsd/tools/test/stress2/misc/mlockall7.sh (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1#!/bin/sh
2
3#
4# Copyright (c) 2014 EMC Corp.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Variation of mmap18.sh.
30# "panic: vm_page_unwire: page 0xfffff81038d721f0's wire count is zero" seen:
31# https://people.freebsd.org/~pho/stress/log/mlockall7.txt
32# Fixed by r328880
33
34[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
35
36. ../default.cfg
37
38here=`pwd`
39cd /tmp
40sed '1,/^EOF/d' < $here/$0 > mlockall7.c
41mycc -o mlockall7 -Wall -Wextra -O2 mlockall7.c -lpthread || exit 1
42rm -f mlockall7.c
43
44/tmp/mlockall7 `[ $# -eq 0 ] && echo 1 || echo $1` || s=1
45
46sleep 2
47rm -f /tmp/mlockall7 /tmp/mlockall7.core
48exit $s
49EOF
50#include <sys/types.h>
51#include <sys/mman.h>
52#include <sys/resource.h>
53#include <sys/stat.h>
54#include <sys/sysctl.h>
55#include <sys/time.h>
56#include <sys/wait.h>
57
58#include <err.h>
59#include <fcntl.h>
60#include <pwd.h>
61#include <pthread.h>
62#include <pthread_np.h>
63#include <sched.h>
64#include <signal.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <time.h>
69#include <unistd.h>
70
71#define N 4096
72#define PARALLEL 50
73#define RUNTIME 180
74
75static u_int32_t r[N];
76static void *p;
77
78static unsigned long
79makearg(void)
80{
81	unsigned long val;
82	unsigned int i;
83
84	val = arc4random();
85	i   = arc4random() % 100;
86	if (i < 20)
87		val = val & 0xff;
88	if (i >= 20 && i < 40)
89		val = val & 0xffff;
90	if (i >= 40 && i < 60)
91		val = (unsigned long)(r) | (val & 0xffff);
92#if defined(__LP64__)
93	if (i >= 60) {
94		val = (val << 32) | arc4random();
95		if (i > 80)
96			val = val & 0x00007fffffffffffUL;
97	}
98#endif
99
100	return (val);
101}
102
103static void *
104tmmap(void *arg __unused)
105{
106	size_t len;
107	time_t start;
108
109	pthread_set_name_np(pthread_self(), __func__);
110	len = 128LL * 1024 * 1024;
111
112	start = time(NULL);
113	while (time(NULL) - start < 60) {
114		if ((p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON,
115		    -1, 0)) != MAP_FAILED) {
116			usleep(100);
117			munmap(p, len);
118		}
119	}
120
121	return (NULL);
122}
123
124static void *
125tmlockall(void *arg __unused)
126{
127	time_t start;
128	int flags;
129
130	pthread_set_name_np(pthread_self(), __func__);
131	start = time(NULL);
132	while (time(NULL) - start < 60) {
133		flags = makearg() & 0xff;
134		mlockall(flags);
135		usleep(100);
136		munlockall();
137		usleep(1000);
138	}
139
140	return (NULL);
141}
142
143static void
144test(void)
145{
146	pthread_t tid[2];
147	time_t start;
148	int i, rc;
149
150	if ((rc = pthread_create(&tid[0], NULL, tmmap, NULL)) != 0)
151		errc(1, rc, "tmmap()");
152	if ((rc = pthread_create(&tid[1], NULL, tmlockall, NULL)) != 0)
153		errc(1, rc, "tmlock()");
154
155	start = time(NULL);
156	while (time(NULL) - start < 60) {
157		if (fork() == 0) {
158			usleep(10000);
159			_exit(0);
160		}
161		wait(NULL);
162	}
163
164	for (i = 0; i < 2; i++)
165		if ((rc = pthread_join(tid[i], NULL)) != 0)
166			errc(1, rc, "pthread_join");
167	_exit(0);
168}
169
170int
171testing(unsigned long maxl)
172{
173	struct passwd *pw;
174	struct rlimit rl;
175	rlim_t maxlock;
176	time_t start;
177	int i;
178
179	maxlock = maxl;
180	if ((pw = getpwnam("nobody")) == NULL)
181		err(1, "failed to resolve nobody");
182	if (setgroups(1, &pw->pw_gid) ||
183	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
184	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
185		err(1, "Can't drop privileges to \"nobody\"");
186	endpwent();
187
188	rl.rlim_max = rl.rlim_cur = 0;
189	if (setrlimit(RLIMIT_CORE, &rl) == -1)
190		warn("setrlimit");
191
192	if (getrlimit(RLIMIT_MEMLOCK, &rl) == -1)
193		warn("getrlimit");
194	if (maxlock <= 0)
195		errx(1, "Argument is %jd", maxlock);
196	maxlock = (maxlock / 10 * 8) / PARALLEL * PAGE_SIZE;
197	if (maxlock < rl.rlim_cur) {
198		rl.rlim_max = rl.rlim_cur = maxlock;
199		if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
200			warn("setrlimit");
201	}
202
203	for (i = 0; i < N; i++)
204		r[i] = arc4random();
205
206	start = time(NULL);
207	while (time(NULL) - start < RUNTIME) {
208		for (i = 0; i < PARALLEL; i++) {
209			if (fork() == 0)
210				test();
211		}
212
213		for (i = 0; i < PARALLEL; i++)
214			wait(NULL);
215	}
216
217	_exit(0);
218}
219
220int
221main(int argc, char *argv[])
222{
223	pid_t pid;
224	size_t len;
225	int i, loops, s, status;
226	unsigned long max_wired;
227	unsigned int wire_count, wire_count_old;
228
229	s = 0;
230	if (argc != 2)
231		errx(1, "Usage: %s <loops>", argv[0]);
232	loops = atoi(argv[1]);
233
234	len = sizeof(max_wired);
235	if (sysctlbyname("vm.max_user_wired", &max_wired, &len, NULL, 0) != 0)
236		err(1, "vm.max_user_wired");
237
238	len = sizeof(wire_count);
239	if (sysctlbyname("vm.stats.vm.v_user_wire_count", &wire_count, &len,
240	    NULL, 0) != 0)
241		err(1, "vm.stats.vm.v_user_wire_count");
242
243	for (i = 0; i < loops; i++) {
244		wire_count_old = wire_count;
245
246		if ((pid = fork()) == 0)
247			testing(max_wired);
248		if (waitpid(pid, &status, 0) != pid)
249			err(1, "waitpid(%d)", pid);
250		if (status != 0)
251			errx(1, "Exit status %d from pid %d\n", status, pid);
252
253		len = sizeof(wire_count);
254		if (sysctlbyname("vm.stats.vm.v_user_wire_count", &wire_count, &len,
255		    NULL, 0) != 0)
256			err(1, "vm.stats.vm.v_user_wire_count");
257		fprintf(stderr, "vm.stats.vm.v_user_wire_count was %d, is %d. %d\n",
258		    wire_count_old, wire_count, wire_count - wire_count_old);
259	}
260
261	return (s);
262}
263