cache.c revision 109187
1/* 2 * CACHE.C 3 * 4 * Block cache for dump 5 * 6 * $FreeBSD: head/sbin/dump/cache.c 109187 2003-01-13 19:42:41Z dillon $ 7 */ 8 9#include <sys/param.h> 10#include <sys/stat.h> 11#include <sys/mman.h> 12 13#ifdef sunos 14#include <sys/vnode.h> 15 16#include <ufs/fs.h> 17#include <ufs/fsdir.h> 18#include <ufs/inode.h> 19#else 20#include <ufs/ufs/dir.h> 21#include <ufs/ufs/dinode.h> 22#include <ufs/ffs/fs.h> 23#endif 24 25#include <protocols/dumprestore.h> 26 27#include <ctype.h> 28#include <stdio.h> 29#ifdef __STDC__ 30#include <errno.h> 31#include <string.h> 32#include <stdlib.h> 33#include <unistd.h> 34#endif 35#include "dump.h" 36 37typedef struct Block { 38 struct Block *b_HNext; /* must be first field */ 39 off_t b_Offset; 40 char *b_Data; 41} Block; 42 43#define HFACTOR 4 44#define BLKFACTOR 4 45 46static char *DataBase; 47static Block **BlockHash; 48static int BlockSize; 49static int HSize; 50static int NBlocks; 51 52static void 53cinit(void) 54{ 55 int i; 56 int hi; 57 Block *base; 58 59 if ((BlockSize = sblock->fs_bsize * BLKFACTOR) > MAXBSIZE) 60 BlockSize = MAXBSIZE; 61 NBlocks = cachesize / BlockSize; 62 HSize = NBlocks / HFACTOR; 63 64 msg("Cache %d MB, blocksize = %d\n", 65 NBlocks * BlockSize / (1024 * 1024), BlockSize); 66 67 base = calloc(sizeof(Block), NBlocks); 68 BlockHash = calloc(sizeof(Block *), HSize); 69 DataBase = mmap(NULL, NBlocks * BlockSize, 70 PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 71 for (i = 0; i < NBlocks; ++i) { 72 base[i].b_Data = DataBase + i * BlockSize; 73 base[i].b_Offset = (off_t)-1; 74 hi = i / HFACTOR; 75 base[i].b_HNext = BlockHash[hi]; 76 BlockHash[hi] = &base[i]; 77 } 78} 79 80ssize_t 81cread(int fd, void *buf, size_t nbytes, off_t offset) 82{ 83 Block *blk; 84 Block **pblk; 85 Block **ppblk; 86 int hi; 87 int n; 88 off_t mask; 89 90 /* 91 * If the cache is disabled, revert to pread. If the 92 * cache has not been initialized, initialize the cache. 93 */ 94 if (sblock->fs_bsize && DataBase == NULL) { 95 if (cachesize <= 0) 96 return(pread(fd, buf, nbytes, offset)); 97 cinit(); 98 } 99 100 /* 101 * If the request crosses a cache block boundary, or the 102 * request is larger or equal to the cache block size, 103 * revert to pread(). Full-block-reads are typically 104 * one-time calls and caching would be detrimental. 105 */ 106 mask = ~(off_t)(BlockSize - 1); 107 if (nbytes >= BlockSize || 108 ((offset ^ (offset + nbytes - 1)) & mask) != 0) { 109 return(pread(fd, buf, nbytes, offset)); 110 } 111 112 /* 113 * Obtain and access the cache block. Cache a successful 114 * result. If an error occurs, revert to pread() (this might 115 * occur near the end of the media). 116 */ 117 hi = (offset / BlockSize) % HSize; 118 pblk = &BlockHash[hi]; 119 ppblk = NULL; 120 while ((blk = *pblk) != NULL) { 121 if (((blk->b_Offset ^ offset) & mask) == 0) { 122#if 0 123 fprintf(stderr, "%08llx %d (%08x)\n", offset, nbytes, 124 sblock->fs_size * sblock->fs_fsize); 125#endif 126 break; 127 } 128 ppblk = pblk; 129 pblk = &blk->b_HNext; 130 } 131 if (blk == NULL) { 132 blk = *ppblk; 133 pblk = ppblk; 134 blk->b_Offset = offset & mask; 135 n = pread(fd, blk->b_Data, BlockSize, blk->b_Offset); 136 if (n != BlockSize) { 137 blk->b_Offset = (off_t)-1; 138 blk = NULL; 139 } 140 } 141 if (blk) { 142 bcopy(blk->b_Data + (offset - blk->b_Offset), buf, nbytes); 143 *pblk = blk->b_HNext; 144 blk->b_HNext = BlockHash[hi]; 145 BlockHash[hi] = blk; 146 return(nbytes); 147 } else { 148 return(pread(fd, buf, nbytes, offset)); 149 } 150} 151 152