1 1.25 bouyer /* $NetBSD: rcache.c,v 1.25 2015/08/24 17:34:03 bouyer Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /*- 4 1.1 bouyer * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 1.1 bouyer * All rights reserved. 6 1.1 bouyer * 7 1.1 bouyer * This code is derived from software contributed to The NetBSD Foundation 8 1.10 lukem * by Martin J. Laubach <mjl (at) emsi.priv.at> and 9 1.1 bouyer * Manuel Bouyer <Manuel.Bouyer (at) lip6.fr>. 10 1.1 bouyer * 11 1.1 bouyer * Redistribution and use in source and binary forms, with or without 12 1.1 bouyer * modification, are permitted provided that the following conditions 13 1.1 bouyer * are met: 14 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 15 1.1 bouyer * notice, this list of conditions and the following disclaimer. 16 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 18 1.1 bouyer * documentation and/or other materials provided with the distribution. 19 1.1 bouyer * 20 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.10 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 bouyer * POSSIBILITY OF SUCH DAMAGE. 31 1.1 bouyer */ 32 1.11 lukem 33 1.11 lukem #include <sys/cdefs.h> 34 1.11 lukem #ifndef lint 35 1.25 bouyer __RCSID("$NetBSD: rcache.c,v 1.25 2015/08/24 17:34:03 bouyer Exp $"); 36 1.11 lukem #endif /* not lint */ 37 1.11 lukem 38 1.1 bouyer #include <sys/types.h> 39 1.1 bouyer #include <sys/uio.h> 40 1.1 bouyer #include <sys/mman.h> 41 1.1 bouyer #include <sys/param.h> 42 1.1 bouyer #include <sys/sysctl.h> 43 1.1 bouyer 44 1.1 bouyer #include <stdio.h> 45 1.1 bouyer #include <stdlib.h> 46 1.1 bouyer #include <unistd.h> 47 1.1 bouyer #include <fcntl.h> 48 1.1 bouyer #include <errno.h> 49 1.1 bouyer #include <string.h> 50 1.1 bouyer 51 1.1 bouyer #include "dump.h" 52 1.1 bouyer 53 1.1 bouyer /*-----------------------------------------------------------------------*/ 54 1.1 bouyer #define MAXCACHEBUFS 512 /* max 512 buffers */ 55 1.1 bouyer #define MAXMEMPART 6 /* max 15% of the user mem */ 56 1.1 bouyer 57 1.1 bouyer /*-----------------------------------------------------------------------*/ 58 1.13 hannken union cdesc { 59 1.13 hannken volatile size_t cd_count; 60 1.13 hannken struct { 61 1.13 hannken volatile daddr_t blkstart; 62 1.14 enami volatile daddr_t blkend; /* start + nblksread */ 63 1.13 hannken volatile daddr_t blocksRead; 64 1.13 hannken volatile size_t time; 65 1.1 bouyer #ifdef DIAGNOSTICS 66 1.13 hannken volatile pid_t owner; 67 1.1 bouyer #endif 68 1.13 hannken } desc; 69 1.13 hannken #define cd_blkstart desc.blkstart 70 1.13 hannken #define cd_blkend desc.blkend 71 1.13 hannken #define cd_blocksRead desc.blocksRead 72 1.13 hannken #define cd_time desc.time 73 1.13 hannken #define cd_owner desc.owner 74 1.1 bouyer }; 75 1.1 bouyer 76 1.6 lukem static int findlru(void); 77 1.1 bouyer 78 1.1 bouyer static void *shareBuffer = NULL; 79 1.13 hannken static union cdesc *cheader; 80 1.13 hannken static union cdesc *cdesc; 81 1.1 bouyer static char *cdata; 82 1.1 bouyer static int cachebufs; 83 1.1 bouyer static int nblksread; 84 1.1 bouyer 85 1.1 bouyer #ifdef STATS 86 1.1 bouyer static int nreads; 87 1.1 bouyer static int nphysread; 88 1.1 bouyer static int64_t readsize; 89 1.1 bouyer static int64_t physreadsize; 90 1.1 bouyer #endif 91 1.1 bouyer 92 1.16 enami #define CSIZE (nblksread << dev_bshift) /* cache buf size */ 93 1.16 enami #define CDATA(desc) (cdata + ((desc) - cdesc) * CSIZE) 94 1.1 bouyer 95 1.10 lukem void 96 1.6 lukem initcache(int cachesize, int readblksize) 97 1.1 bouyer { 98 1.1 bouyer size_t len; 99 1.14 enami size_t sharedSize; 100 1.1 bouyer 101 1.25 bouyer if (readblksize == -1) { /* use kern.maxphys */ 102 1.25 bouyer int kern_maxphys; 103 1.25 bouyer int mib[2] = { CTL_KERN, KERN_MAXPHYS }; 104 1.25 bouyer 105 1.25 bouyer len = sizeof(kern_maxphys); 106 1.25 bouyer if (sysctl(mib, 2, &kern_maxphys, &len, NULL, 0) < 0) { 107 1.25 bouyer msg("sysctl(kern.maxphys) failed: %s\n", 108 1.25 bouyer strerror(errno)); 109 1.25 bouyer return; 110 1.25 bouyer } 111 1.25 bouyer readblksize = kern_maxphys; 112 1.25 bouyer } 113 1.25 bouyer 114 1.15 enami /* Convert read block size in terms of filesystem block size */ 115 1.14 enami nblksread = howmany(readblksize, ufsib->ufs_bsize); 116 1.15 enami 117 1.15 enami /* Then, convert it in terms of device block size */ 118 1.15 enami nblksread <<= ufsib->ufs_bshift - dev_bshift; 119 1.15 enami 120 1.14 enami if (cachesize == -1) { /* Compute from memory available */ 121 1.23 spz uint64_t usermem, cachetmp; 122 1.21 simonb int mib[2] = { CTL_HW, HW_USERMEM64 }; 123 1.10 lukem 124 1.1 bouyer len = sizeof(usermem); 125 1.1 bouyer if (sysctl(mib, 2, &usermem, &len, NULL, 0) < 0) { 126 1.14 enami msg("sysctl(hw.usermem) failed: %s\n", 127 1.14 enami strerror(errno)); 128 1.1 bouyer return; 129 1.1 bouyer } 130 1.23 spz cachetmp = (usermem / MAXMEMPART) / CSIZE; 131 1.23 spz /* for those with TB of RAM */ 132 1.23 spz cachebufs = (cachetmp > INT_MAX) ? INT_MAX : cachetmp; 133 1.1 bouyer } else { /* User specified */ 134 1.1 bouyer cachebufs = cachesize; 135 1.1 bouyer } 136 1.10 lukem 137 1.14 enami if (cachebufs) { /* Don't allocate if zero --> no caching */ 138 1.1 bouyer if (cachebufs > MAXCACHEBUFS) 139 1.1 bouyer cachebufs = MAXCACHEBUFS; 140 1.1 bouyer 141 1.13 hannken sharedSize = sizeof(union cdesc) + 142 1.13 hannken sizeof(union cdesc) * cachebufs + 143 1.16 enami cachebufs * CSIZE; 144 1.10 lukem #ifdef STATS 145 1.1 bouyer fprintf(stderr, "Using %d buffers (%d bytes)\n", cachebufs, 146 1.1 bouyer sharedSize); 147 1.1 bouyer #endif 148 1.1 bouyer shareBuffer = mmap(NULL, sharedSize, PROT_READ | PROT_WRITE, 149 1.1 bouyer MAP_ANON | MAP_SHARED, -1, 0); 150 1.14 enami if (shareBuffer == MAP_FAILED) { 151 1.1 bouyer msg("can't mmap shared memory for buffer: %s\n", 152 1.1 bouyer strerror(errno)); 153 1.1 bouyer return; 154 1.1 bouyer } 155 1.1 bouyer cheader = shareBuffer; 156 1.13 hannken cdesc = (union cdesc *) (((char *) shareBuffer) + 157 1.13 hannken sizeof(union cdesc)); 158 1.13 hannken cdata = ((char *) shareBuffer) + sizeof(union cdesc) + 159 1.13 hannken sizeof(union cdesc) * cachebufs; 160 1.1 bouyer 161 1.1 bouyer memset(shareBuffer, '\0', sharedSize); 162 1.1 bouyer } 163 1.1 bouyer } 164 1.1 bouyer 165 1.6 lukem /* 166 1.6 lukem * Find the cache buffer descriptor that shows the minimal access time 167 1.6 lukem */ 168 1.10 lukem static int 169 1.6 lukem findlru(void) 170 1.1 bouyer { 171 1.8 lukem int i; 172 1.13 hannken size_t minTime = cdesc[0].cd_time; 173 1.8 lukem int minIdx = 0; 174 1.1 bouyer 175 1.1 bouyer for (i = 0; i < cachebufs; i++) { 176 1.13 hannken if (cdesc[i].cd_time < minTime) { 177 1.1 bouyer minIdx = i; 178 1.13 hannken minTime = cdesc[i].cd_time; 179 1.1 bouyer } 180 1.1 bouyer } 181 1.1 bouyer 182 1.1 bouyer return minIdx; 183 1.1 bouyer } 184 1.6 lukem 185 1.1 bouyer /* 186 1.1 bouyer * Read data directly from disk, with smart error handling. 187 1.1 bouyer * Try to recover from hard errors by reading in sector sized pieces. 188 1.1 bouyer * Error recovery is attempted at most BREADEMAX times before seeking 189 1.1 bouyer * consent from the operator to continue. 190 1.1 bouyer */ 191 1.1 bouyer 192 1.1 bouyer static int breaderrors = 0; 193 1.1 bouyer #define BREADEMAX 32 194 1.1 bouyer 195 1.10 lukem void 196 1.6 lukem rawread(daddr_t blkno, char *buf, int size) 197 1.1 bouyer { 198 1.1 bouyer int cnt, i; 199 1.14 enami 200 1.1 bouyer #ifdef STATS 201 1.1 bouyer nphysread++; 202 1.1 bouyer physreadsize += size; 203 1.1 bouyer #endif 204 1.1 bouyer 205 1.14 enami loop: 206 1.18 enami if (lseek(diskfd, ((off_t) blkno << dev_bshift), SEEK_SET) == -1) { 207 1.1 bouyer msg("rawread: lseek fails\n"); 208 1.1 bouyer goto err; 209 1.1 bouyer } 210 1.14 enami if ((cnt = read(diskfd, buf, size)) == size) 211 1.1 bouyer return; 212 1.16 enami if (blkno + (size >> dev_bshift) > ufsib->ufs_dsize) { 213 1.7 lukem /* 214 1.7 lukem * Trying to read the final fragment. 215 1.7 lukem * 216 1.7 lukem * NB - dump only works in TP_BSIZE blocks, hence 217 1.7 lukem * rounds `dev_bsize' fragments up to TP_BSIZE pieces. 218 1.7 lukem * It should be smarter about not actually trying to 219 1.7 lukem * read more than it can get, but for the time being 220 1.7 lukem * we punt and scale back the read only when it gets 221 1.7 lukem * us into trouble. (mkm 9/25/83) 222 1.7 lukem */ 223 1.7 lukem size -= dev_bsize; 224 1.7 lukem goto loop; 225 1.7 lukem } 226 1.1 bouyer if (cnt == -1) 227 1.12 fvdl msg("read error from %s: %s: [block %lld]: count=%d\n", 228 1.14 enami disk, strerror(errno), (long long)blkno, size); 229 1.1 bouyer else 230 1.14 enami msg("short read error from %s: [block %lld]: " 231 1.14 enami "count=%d, got=%d\n", 232 1.14 enami disk, (long long)blkno, size, cnt); 233 1.1 bouyer err: 234 1.1 bouyer if (++breaderrors > BREADEMAX) { 235 1.5 briggs msg("More than %d block read errors from %s\n", 236 1.14 enami BREADEMAX, disk); 237 1.1 bouyer broadcast("DUMP IS AILING!\n"); 238 1.1 bouyer msg("This is an unrecoverable error.\n"); 239 1.14 enami if (!query("Do you want to attempt to continue?")) { 240 1.1 bouyer dumpabort(0); 241 1.1 bouyer /*NOTREACHED*/ 242 1.1 bouyer } else 243 1.1 bouyer breaderrors = 0; 244 1.1 bouyer } 245 1.1 bouyer /* 246 1.1 bouyer * Zero buffer, then try to read each sector of buffer separately. 247 1.1 bouyer */ 248 1.1 bouyer memset(buf, 0, size); 249 1.1 bouyer for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) { 250 1.14 enami if (lseek(diskfd, ((off_t)blkno << dev_bshift), 251 1.18 enami SEEK_SET) == -1) { 252 1.1 bouyer msg("rawread: lseek2 fails: %s!\n", 253 1.1 bouyer strerror(errno)); 254 1.1 bouyer continue; 255 1.1 bouyer } 256 1.1 bouyer if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize) 257 1.1 bouyer continue; 258 1.1 bouyer if (cnt == -1) { 259 1.14 enami msg("read error from %s: %s: [sector %lld]: " 260 1.19 enami "count=%ld\n", disk, strerror(errno), 261 1.19 enami (long long)blkno, dev_bsize); 262 1.1 bouyer continue; 263 1.1 bouyer } 264 1.14 enami msg("short read error from %s: [sector %lld]: " 265 1.14 enami "count=%ld, got=%d\n", 266 1.12 fvdl disk, (long long)blkno, dev_bsize, cnt); 267 1.1 bouyer } 268 1.1 bouyer } 269 1.1 bouyer 270 1.10 lukem void 271 1.6 lukem bread(daddr_t blkno, char *buf, int size) 272 1.1 bouyer { 273 1.16 enami int osize = size, idx; 274 1.1 bouyer daddr_t oblkno = blkno; 275 1.1 bouyer char *obuf = buf; 276 1.14 enami daddr_t numBlocks = howmany(size, dev_bsize); 277 1.1 bouyer 278 1.1 bouyer #ifdef STATS 279 1.1 bouyer nreads++; 280 1.1 bouyer readsize += size; 281 1.1 bouyer #endif 282 1.1 bouyer 283 1.1 bouyer if (!shareBuffer) { 284 1.1 bouyer rawread(blkno, buf, size); 285 1.1 bouyer return; 286 1.1 bouyer } 287 1.1 bouyer 288 1.1 bouyer if (flock(diskfd, LOCK_EX)) { 289 1.1 bouyer msg("flock(LOCK_EX) failed: %s\n", 290 1.1 bouyer strerror(errno)); 291 1.1 bouyer rawread(blkno, buf, size); 292 1.1 bouyer return; 293 1.1 bouyer } 294 1.1 bouyer 295 1.1 bouyer retry: 296 1.16 enami idx = 0; 297 1.16 enami while (size > 0) { 298 1.8 lukem int i; 299 1.10 lukem 300 1.1 bouyer for (i = 0; i < cachebufs; i++) { 301 1.16 enami union cdesc *curr = &cdesc[(i + idx) % cachebufs]; 302 1.1 bouyer 303 1.1 bouyer #ifdef DIAGNOSTICS 304 1.13 hannken if (curr->cd_owner) { 305 1.1 bouyer fprintf(stderr, "Owner is set (%d, me=%d), can" 306 1.13 hannken "not happen.\n", curr->cd_owner, getpid()); 307 1.1 bouyer } 308 1.1 bouyer #endif 309 1.1 bouyer 310 1.13 hannken if (curr->cd_blkend == 0) 311 1.1 bouyer continue; 312 1.1 bouyer /* 313 1.1 bouyer * If we find a bit of the read in the buffers, 314 1.1 bouyer * now compute how many blocks we can copy, 315 1.1 bouyer * copy them out, adjust blkno, buf and size, 316 1.1 bouyer * and restart 317 1.1 bouyer */ 318 1.13 hannken if (curr->cd_blkstart <= blkno && 319 1.13 hannken blkno < curr->cd_blkend) { 320 1.1 bouyer /* Number of data blocks to be copied */ 321 1.6 lukem int toCopy = MIN(size, 322 1.16 enami (curr->cd_blkend - blkno) << dev_bshift); 323 1.1 bouyer #ifdef DIAGNOSTICS 324 1.16 enami if (toCopy <= 0 || toCopy > CSIZE) { 325 1.1 bouyer fprintf(stderr, "toCopy %d !\n", 326 1.1 bouyer toCopy); 327 1.1 bouyer dumpabort(0); 328 1.1 bouyer } 329 1.16 enami if (CDATA(curr) + 330 1.16 enami ((blkno - curr->cd_blkstart) << 331 1.17 enami dev_bshift) < CDATA(curr) || 332 1.16 enami CDATA(curr) + 333 1.16 enami ((blkno - curr->cd_blkstart) << 334 1.17 enami dev_bshift) > CDATA(curr) + CSIZE) { 335 1.1 bouyer fprintf(stderr, "%p < %p !!!\n", 336 1.16 enami CDATA(curr) + ((blkno - 337 1.16 enami curr->cd_blkstart) << dev_bshift), 338 1.16 enami CDATA(curr)); 339 1.16 enami fprintf(stderr, 340 1.16 enami "cdesc[i].cd_blkstart %lld " 341 1.16 enami "blkno %lld dev_bsize %ld\n", 342 1.16 enami (long long)curr->cd_blkstart, 343 1.16 enami (long long)blkno, 344 1.16 enami dev_bsize); 345 1.1 bouyer dumpabort(0); 346 1.1 bouyer } 347 1.1 bouyer #endif 348 1.16 enami memcpy(buf, CDATA(curr) + 349 1.17 enami ((blkno - curr->cd_blkstart) << 350 1.17 enami dev_bshift), 351 1.1 bouyer toCopy); 352 1.1 bouyer 353 1.1 bouyer buf += toCopy; 354 1.1 bouyer size -= toCopy; 355 1.14 enami blkno += howmany(toCopy, dev_bsize); 356 1.14 enami numBlocks -= howmany(toCopy, dev_bsize); 357 1.1 bouyer 358 1.13 hannken curr->cd_time = cheader->cd_count++; 359 1.1 bouyer 360 1.1 bouyer /* 361 1.1 bouyer * If all data of a cache block have been 362 1.1 bouyer * read, chances are good no more reads 363 1.1 bouyer * will occur, so expire the cache immediately 364 1.1 bouyer */ 365 1.1 bouyer 366 1.13 hannken curr->cd_blocksRead += 367 1.14 enami howmany(toCopy, dev_bsize); 368 1.13 hannken if (curr->cd_blocksRead >= nblksread) 369 1.13 hannken curr->cd_time = 0; 370 1.1 bouyer 371 1.1 bouyer goto retry; 372 1.1 bouyer } 373 1.1 bouyer } 374 1.1 bouyer 375 1.1 bouyer /* No more to do? */ 376 1.1 bouyer if (size == 0) 377 1.1 bouyer break; 378 1.9 lukem 379 1.1 bouyer /* 380 1.1 bouyer * This does actually not happen if fs blocks are not greater 381 1.1 bouyer * than nblksread. 382 1.1 bouyer */ 383 1.9 lukem if (numBlocks > nblksread || blkno >= ufsib->ufs_dsize) { 384 1.1 bouyer rawread(oblkno, obuf, osize); 385 1.1 bouyer break; 386 1.1 bouyer } else { 387 1.8 lukem ssize_t rsize; 388 1.8 lukem daddr_t blockBlkNo; 389 1.1 bouyer 390 1.1 bouyer blockBlkNo = (blkno / nblksread) * nblksread; 391 1.1 bouyer idx = findlru(); 392 1.6 lukem rsize = MIN(nblksread, 393 1.16 enami ufsib->ufs_dsize - blockBlkNo) << dev_bshift; 394 1.3 perseant 395 1.1 bouyer #ifdef DIAGNOSTICS 396 1.13 hannken if (cdesc[idx].cd_owner) 397 1.1 bouyer fprintf(stderr, "Owner is set (%d, me=%d), can" 398 1.13 hannken "not happen(2).\n", cdesc[idx].cd_owner, 399 1.1 bouyer getpid()); 400 1.13 hannken cdesc[idx].cd_owner = getpid(); 401 1.1 bouyer #endif 402 1.13 hannken cdesc[idx].cd_time = cheader->cd_count++; 403 1.13 hannken cdesc[idx].cd_blkstart = blockBlkNo; 404 1.16 enami cdesc[idx].cd_blkend = 0; 405 1.13 hannken cdesc[idx].cd_blocksRead = 0; 406 1.1 bouyer 407 1.14 enami if (lseek(diskfd, ((off_t) blockBlkNo << dev_bshift), 408 1.18 enami SEEK_SET) == -1) { 409 1.1 bouyer msg("readBlocks: lseek fails: %s\n", 410 1.1 bouyer strerror(errno)); 411 1.1 bouyer rsize = -1; 412 1.1 bouyer } else { 413 1.16 enami rsize = read(diskfd, 414 1.16 enami CDATA(&cdesc[idx]), rsize); 415 1.1 bouyer if (rsize < 0) { 416 1.1 bouyer msg("readBlocks: read fails: %s\n", 417 1.1 bouyer strerror(errno)); 418 1.1 bouyer } 419 1.1 bouyer } 420 1.1 bouyer 421 1.1 bouyer /* On errors, panic, punt, try to read without 422 1.1 bouyer * cache and let raw read routine do the rest. 423 1.1 bouyer */ 424 1.1 bouyer 425 1.1 bouyer if (rsize <= 0) { 426 1.1 bouyer rawread(oblkno, obuf, osize); 427 1.1 bouyer #ifdef DIAGNOSTICS 428 1.13 hannken if (cdesc[idx].cd_owner != getpid()) 429 1.1 bouyer fprintf(stderr, "Owner changed from " 430 1.1 bouyer "%d to %d, can't happen\n", 431 1.13 hannken getpid(), cdesc[idx].cd_owner); 432 1.13 hannken cdesc[idx].cd_owner = 0; 433 1.1 bouyer #endif 434 1.1 bouyer break; 435 1.1 bouyer } 436 1.1 bouyer 437 1.1 bouyer /* On short read, just note the fact and go on */ 438 1.13 hannken cdesc[idx].cd_blkend = blockBlkNo + rsize / dev_bsize; 439 1.1 bouyer 440 1.1 bouyer #ifdef STATS 441 1.1 bouyer nphysread++; 442 1.1 bouyer physreadsize += rsize; 443 1.1 bouyer #endif 444 1.1 bouyer #ifdef DIAGNOSTICS 445 1.13 hannken if (cdesc[idx].cd_owner != getpid()) 446 1.1 bouyer fprintf(stderr, "Owner changed from " 447 1.1 bouyer "%d to %d, can't happen\n", 448 1.13 hannken getpid(), cdesc[idx].cd_owner); 449 1.13 hannken cdesc[idx].cd_owner = 0; 450 1.1 bouyer #endif 451 1.1 bouyer /* 452 1.1 bouyer * We swapped some of data in, let the loop fetch 453 1.1 bouyer * them from cache 454 1.1 bouyer */ 455 1.1 bouyer } 456 1.1 bouyer } 457 1.10 lukem 458 1.1 bouyer if (flock(diskfd, LOCK_UN)) 459 1.1 bouyer msg("flock(LOCK_UN) failed: %s\n", 460 1.1 bouyer strerror(errno)); 461 1.1 bouyer } 462 1.1 bouyer 463 1.1 bouyer void 464 1.6 lukem printcachestats(void) 465 1.1 bouyer { 466 1.14 enami 467 1.1 bouyer #ifdef STATS 468 1.1 bouyer fprintf(stderr, "Pid %d: %d reads (%u bytes) " 469 1.1 bouyer "%d physical reads (%u bytes) %d%% hits, %d%% overhead\n", 470 1.1 bouyer getpid(), nreads, (u_int) readsize, nphysread, 471 1.1 bouyer (u_int) physreadsize, (nreads - nphysread) * 100 / nreads, 472 1.1 bouyer (int) (((physreadsize - readsize) * 100) / readsize)); 473 1.1 bouyer #endif 474 1.1 bouyer } 475