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
49static int lockfd;
50static int dffd;
51static int flags;
52static char lockpath[128];
53static char dfpath[128];
54
55static int64_t
56inodes(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
77static int64_t
78df(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
102int64_t
103swap(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
135unsigned long
136usermem(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
151static void
152cleanupdf(void)
153{
154	unlink(dfpath);
155}
156
157void
158getdf(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
211void
212reservedf(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__);
243err:
244	close(dffd);
245	close(lockfd);
246	if (unlink(lockpath) == -1)
247		err(1, "unlink(%s)", lockpath);
248}
249