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