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