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/statvfs.h> 39 #include <sys/param.h> 40 #include <sys/mount.h> 41 #include <kvm.h> 42 #include <vm/vm_param.h> 43 #include <errno.h> 44 #include <err.h> 45 #include <stdarg.h> 46 #include <libutil.h> 47 48 #include "stress.h" 49 50 static int lockfd; 51 static int dffd; 52 static int flags; 53 static char lockpath[128]; 54 static char dfpath[128]; 55 56 static int64_t 57 inodes(void) 58 { 59 char path[MAXPATHLEN+1]; 60 struct statfs sbuf; 61 struct statvfs buf; 62 63 if (op->inodes != 0) 64 return (op->inodes); 65 if (getcwd(path, sizeof(path)) == NULL) 66 err(1, "getcwd()"); 67 68 if (statvfs(path, &buf) < 0) 69 err(1, "statfs(%s)", path); 70 if (!strcmp(sbuf.f_fstypename, "msdosfs")) 71 buf.f_ffree = 9999; 72 flags = sbuf.f_flags & MNT_VISFLAGMASK; 73 if (op->verbose > 2) 74 printf("Free inodes on %s (%s): %jd\n", path, sbuf.f_mntonname, 75 (intmax_t)buf.f_ffree); 76 return (buf.f_ffree); 77 } 78 79 static int64_t 80 df(void) 81 { 82 char path[MAXPATHLEN+1]; 83 struct statvfs buf; 84 85 if (op->kblocks != 0) 86 return (op->kblocks * (uint64_t)1024); 87 88 if (getcwd(path, sizeof(path)) == NULL) 89 err(1, "getcwd()"); 90 91 if (statvfs(path, &buf) < 0) 92 err(1, "statfs(%s)", path); 93 94 if (buf.f_bavail > buf.f_blocks || buf.f_bavail < 0) { 95 warnx("Corrupt statfs(%s). f_bavail = %jd!", path, 96 (intmax_t)buf.f_bavail); 97 buf.f_bavail = 100; 98 } 99 if (op->verbose > 2) 100 printf("Free space on %s: %jd Mb\n", path, 101 (intmax_t)(buf.f_bavail * buf.f_bsize / 1024 / 1024)); 102 return (buf.f_bavail * buf.f_bsize); 103 } 104 105 106 int64_t 107 swap(void) 108 { 109 #error "please put the amount of free swap (in bytes) in sz" /* REMOVE HERE! */ 110 /* 111 * Currently, DragonFly has no way of determining free swap as non-root 112 * 113 * Please remove the #error line above this comment and modify the 114 * line below it with the amount of free swap you have (in bytes). 115 */ 116 int64_t sz = 4294967296LL; /* EDIT HERE! */ 117 118 if (op->verbose > 2) 119 printf("Total free swap space %jd Mb\n", 120 (intmax_t)(sz / 1024 / 1024)); 121 122 return (sz); 123 } 124 125 unsigned long 126 usermem(void) 127 { 128 unsigned long mem; 129 size_t nlen = sizeof(mem); 130 131 if (sysctlbyname("hw.usermem", &mem, &nlen, NULL, 0) == -1) 132 err(1, "sysctlbyname() %s:%d", __FILE__, __LINE__); 133 134 if (op->verbose > 2) 135 printf("Total free user memory %lu Mb\n", 136 mem / 1024 / 1024); 137 138 return (mem); 139 } 140 141 void cleanupdf() 142 { 143 unlink(dfpath); 144 } 145 146 void 147 getdf(int64_t *block, int64_t *inode) 148 { 149 int i, j; 150 char buf[128]; 151 152 snprintf(lockpath, sizeof(lockpath), "%s/lock", op->cd); 153 for (j = 0; j < 10; j++) { 154 for (i = 0; i < 10000; i++) { 155 if ((lockfd = open(lockpath, 156 O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0644)) != -1) 157 break; 158 usleep(10000); /* sleep 1/100 sec */ 159 } 160 if (lockfd != -1) 161 break; 162 fprintf(stderr, "%s. Removing stale %s\n", getprogname(), lockpath); 163 unlink(lockpath); 164 } 165 if (lockfd == -1) 166 errx(1, "%s. Can not create %s\n", getprogname(), lockpath); 167 snprintf(dfpath, sizeof(dfpath), "%s/df", op->cd); 168 if ((dffd = open(dfpath, O_RDWR, 0644)) == -1) { 169 if ((dffd = open(dfpath, 170 O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) { 171 unlink(lockpath); 172 err(1, "creat(%s) %s:%d", dfpath, __FILE__, __LINE__); 173 } 174 atexit(cleanupdf); 175 *block = df(); 176 *inode = inodes(); 177 snprintf(buf, sizeof(buf), "%jd %jd", *block, *inode); 178 179 if (write(dffd, buf, strlen(buf) + 1) != strlen(buf) +1) 180 err(1, "write df. %s:%d", __FILE__, __LINE__); 181 } else { 182 if (read(dffd, buf, sizeof(buf)) < 1) { 183 system("ls -l /tmp/stressX.control"); 184 unlink(lockpath); 185 err(1, "read df. %s:%d", __FILE__, __LINE__); 186 } 187 sscanf(buf, "%jd %jd", block, inode); 188 } 189 close(dffd); 190 } 191 192 193 void 194 reservedf(int64_t blks, int64_t inos) 195 { 196 char buf[128]; 197 int64_t blocks, inodes; 198 199 if ((dffd = open(dfpath, O_RDWR, 0644)) == -1) { 200 warn("open(%s) %s:%d. %s", dfpath, __FILE__, __LINE__, getprogname()); 201 goto err; 202 } 203 if (read(dffd, buf, sizeof(buf)) < 1) { 204 warn("read df. %s:%d", __FILE__, __LINE__); 205 goto err; 206 } 207 sscanf(buf, "%jd %jd", &blocks, &inodes); 208 209 if (op->verbose > 2) 210 printf("%-8s: reservefd(%9jdK, %6jd) out of (%9jdK, %6jd)\n", 211 getprogname(), blks/1024, inos, blocks/1024, inodes); 212 blocks -= blks; 213 inodes -= inos; 214 215 snprintf(buf, sizeof(buf), "%jd %jd", blocks, inodes); 216 if (blocks < 0 || inodes < 0) 217 printf("******************************** %s: %s\n", getprogname(), buf); 218 if (lseek(dffd, 0, 0) == -1) 219 err(1, "lseek. %s:%d", __FILE__, __LINE__); 220 if (write(dffd, buf, strlen(buf) + 1) != strlen(buf) +1) 221 warn("write df. %s:%d", __FILE__, __LINE__); 222 err: 223 close(dffd); 224 close(lockfd); 225 if (unlink(lockpath) == -1) 226 err(1, "unlink(%s)", lockpath); 227 } 228 229 /* The UFS2 soft update lag problem causes a lot of confusion, so for now add the err() function here */ 230 231 static void 232 vpr(int code, const char *fmt, va_list ap) 233 { 234 char path[MAXPATHLEN+1]; 235 char siz[5], ino[5]; 236 int64_t s, i; 237 238 s = df(); 239 i = inodes(); 240 241 if (errno == ENOSPC && (flags & MNT_SOFTDEP) && (flags & MNT_QUOTA) == 0 && 242 s > 100 && i > 100) { 243 if (getcwd(path, sizeof(path)) == NULL) 244 err(1, "getcwd()"); 245 246 humanize_number(siz, sizeof(siz), s, "", 247 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 248 humanize_number(ino, sizeof(ino), i, "", 249 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 250 251 printf("A syscall has failed with ENOSPC even though free disk " 252 "space for %s is reported as %s and %s inodes.\n", 253 path, siz, ino); 254 } 255 256 257 fprintf(stderr, "%s: ", getprogname()); 258 if (fmt != NULL) { 259 vfprintf(stderr, fmt, ap); 260 fprintf(stderr, ": "); 261 } 262 fprintf(stderr, "%s\n", strerror(code)); 263 } 264 265 void 266 err(int eval, const char *fmt, ...) 267 { 268 va_list ap; 269 int code = errno; 270 271 va_start(ap, fmt); 272 vpr(code, fmt, ap); 273 va_end(ap); 274 exit(eval); 275 } 276 277 void 278 warn(const char *fmt, ...) 279 { 280 va_list ap; 281 int code = errno; 282 283 va_start(ap, fmt); 284 vpr(code, fmt, ap); 285 va_end(ap); 286 } 287