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
inodes(void)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
df(void)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
swap(void)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
usermem(void)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
cleanupdf(void)152 cleanupdf(void)
153 {
154 unlink(dfpath);
155 }
156
157 void
getdf(int64_t * block,int64_t * inode)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
reservedf(int64_t blks,int64_t inos)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