xref: /freebsd/tools/test/stress2/lib/resources.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * Copyright (c) 2008 Peter Holm <pho@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 /* Get various resource limits for the tests */
29 
30 #include <sys/types.h>
31 #include <sys/sysctl.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/param.h>
39 #include <sys/mount.h>
40 #include <kvm.h>
41 #include <vm/vm_param.h>
42 #include <errno.h>
43 #include <err.h>
44 #include <stdarg.h>
45 #include <libutil.h>
46 
47 #include "stress.h"
48 
49 static int lockfd;
50 static int dffd;
51 static int flags;
52 static char lockpath[128];
53 static char dfpath[128];
54 
55 static int64_t
56 inodes(void)
57 {
58 	char path[MAXPATHLEN+1];
59 	struct statfs buf;
60 
61 	if (op->inodes != 0)
62 		return (op->inodes);
63 	if (getcwd(path, sizeof(path)) == NULL)
64 		err(1, "getcwd()");
65 
66 	if (statfs(path, &buf) < 0)
67 		err(1, "statfs(%s)", path);
68 	if (!strcmp(buf.f_fstypename, "msdosfs"))
69 			buf.f_ffree = 9999;
70 	flags = buf.f_flags & MNT_VISFLAGMASK;
71 	if (op->verbose > 2)
72 		printf("Free inodes on %s (%s): %jd\n", path,
73 		    buf.f_mntonname, buf.f_ffree);
74 	return (buf.f_ffree);
75 }
76 
77 static int64_t
78 df(void)
79 {
80 	char path[MAXPATHLEN+1];
81 	struct statfs buf;
82 
83 	if (op->kblocks != 0)
84 		return (op->kblocks * (uint64_t)1024);
85 
86 	if (getcwd(path, sizeof(path)) == NULL)
87 		err(1, "getcwd()");
88 
89 	if (statfs(path, &buf) < 0)
90 		err(1, "statfs(%s)", path);
91 	if (buf.f_bavail > (int64_t)buf.f_blocks || buf.f_bavail < 0) {
92 		warnx("Corrupt statfs(%s). f_bavail = %jd!", path,
93 		    buf.f_bavail);
94 		buf.f_bavail = 100;
95 	}
96 	if (op->verbose > 2)
97 		printf("Free space on %s: %jd Mb\n", path, buf.f_bavail *
98 		    buf.f_bsize / 1024 / 1024);
99 	return (buf.f_bavail * buf.f_bsize);
100 }
101 
102 int64_t
103 swap(void)
104 {
105 	struct xswdev xsw;
106 	size_t mibsize, size;
107 	int mib[16], n;
108 	int64_t sz;
109 
110 	mibsize = sizeof mib / sizeof mib[0];
111 	sz = 0;
112 
113 	if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
114 		err(1, "sysctlnametomib()");
115 
116 	for (n = 0; ; ++n) {
117 		mib[mibsize] = n;
118 		size = sizeof xsw;
119 		if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
120 			break;
121 		if (xsw.xsw_version != XSWDEV_VERSION)
122 			errx(1, "xswdev version mismatch");
123 		sz = sz + xsw.xsw_nblks - xsw.xsw_used;
124 	}
125 	if (errno != ENOENT)
126 		err(1, "sysctl()");
127 
128 	if (op->verbose > 2)
129 		printf("Total free swap space %jd Mb\n",
130 			sz * getpagesize() / 1024 / 1024);
131 
132 	return (sz * getpagesize());
133 }
134 
135 unsigned long
136 usermem(void)
137 {
138 	unsigned long mem;
139 	size_t nlen = sizeof(mem);
140 
141 	if (sysctlbyname("hw.usermem", &mem, &nlen, NULL, 0) == -1)
142 		err(1, "sysctlbyname() %s:%d", __FILE__, __LINE__);
143 
144 	if (op->verbose > 2)
145 		printf("Total free user memory %lu Mb\n",
146 			mem / 1024 / 1024);
147 
148 	return (mem);
149 }
150 
151 static void
152 cleanupdf(void)
153 {
154 	unlink(dfpath);
155 }
156 
157 void
158 getdf(int64_t *block, int64_t *inode)
159 {
160 	int i, j;
161 	char buf[128];
162 
163 	snprintf(lockpath, sizeof(lockpath), "%s/lock", op->cd);
164 	for (j = 0; j < 2; j++) {
165 		for (i = 0; i < 10000; i++) {
166 			if ((lockfd = open(lockpath,
167 			    O_CREAT | O_TRUNC | O_WRONLY |
168 			    O_EXCL, 0644)) != -1)
169 				break;
170 			usleep(10000); /* sleep 1/100 sec */
171 			if (i > 0 && i % 1000 == 0)
172 				fprintf(stderr, "%s is waiting for lock file"
173 				    " %s\n",
174 				    getprogname(), lockpath);
175 		}
176 		if (lockfd != -1)
177 			break;
178 		fprintf(stderr, "%s. Removing stale %s\n", getprogname(),
179 		    lockpath);
180 		unlink(lockpath);
181 	}
182 	if (lockfd == -1)
183 		errx(1, "%s. Can not create %s\n", getprogname(), lockpath);
184 	snprintf(dfpath, sizeof(dfpath), "%s/df", op->cd);
185 	if ((dffd = open(dfpath, O_RDWR, 0644)) == -1) {
186 		if ((dffd = open(dfpath,
187 				O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
188 			unlink(lockpath);
189 			err(1, "creat(%s) %s:%d", dfpath, __FILE__,
190 			    __LINE__);
191 		}
192 		atexit(cleanupdf);
193 		*block = df();
194 		*inode = inodes();
195 		snprintf(buf, sizeof(buf), "%jd %jd", *block, *inode);
196 
197 		if (write(dffd, buf, strlen(buf) + 1) !=
198 		    (ssize_t)strlen(buf) +1)
199 			err(1, "write df. %s:%d", __FILE__, __LINE__);
200 	} else {
201 		if (read(dffd, buf, sizeof(buf)) < 1) {
202 			system("ls -l /tmp/stressX.control");
203 			unlink(lockpath);
204 			err(1, "read df. %s:%d", __FILE__, __LINE__);
205 		}
206 		sscanf(buf, "%jd %jd", block, inode);
207 	}
208 	close(dffd);
209 }
210 
211 void
212 reservedf(int64_t blks, int64_t inos)
213 {
214 	char buf[128];
215 	int64_t blocks, inodes;
216 
217 	if ((dffd = open(dfpath, O_RDWR, 0644)) == -1) {
218 		warn("open(%s) %s:%d. %s", dfpath, __FILE__, __LINE__,
219 		    getprogname());
220 		goto err;
221 	}
222 	if (read(dffd, buf, sizeof(buf)) < 1) {
223 		warn("read df. %s:%d", __FILE__, __LINE__);
224 		goto err;
225 	}
226 	sscanf(buf, "%jd %jd", &blocks, &inodes);
227 
228 	if (op->verbose > 2)
229 		printf("%-8s: reservefd(%9jdK, %6jd) out of (%9jdK, %6jd)\n",
230 				getprogname(), blks/1024, inos, blocks/1024,
231 				inodes);
232 	blocks -= blks;
233 	inodes -= inos;
234 
235 	snprintf(buf, sizeof(buf), "%jd %jd", blocks, inodes);
236 	if (blocks < 0 || inodes < 0)
237 		printf("******************************** %s: %s\n",
238 		    getprogname(), buf);
239 	if (lseek(dffd, 0, 0) == -1)
240 		err(1, "lseek. %s:%d", __FILE__, __LINE__);
241 	if (write(dffd, buf, strlen(buf) + 1) != (ssize_t)strlen(buf) +1)
242 		warn("write df. %s:%d", __FILE__, __LINE__);
243 err:
244 	close(dffd);
245 	close(lockfd);
246 	if (unlink(lockpath) == -1)
247 		err(1, "unlink(%s)", lockpath);
248 }
249