1109187Sdillon/* 2109187Sdillon * CACHE.C 3109187Sdillon * 4109187Sdillon * Block cache for dump 5109187Sdillon * 6109187Sdillon * $FreeBSD$ 7109187Sdillon */ 8109187Sdillon 9109187Sdillon#include <sys/param.h> 10109187Sdillon#include <sys/stat.h> 11109187Sdillon#include <sys/mman.h> 12109187Sdillon 13109187Sdillon#ifdef sunos 14109187Sdillon#include <sys/vnode.h> 15109187Sdillon 16109187Sdillon#include <ufs/fs.h> 17109187Sdillon#include <ufs/fsdir.h> 18109187Sdillon#include <ufs/inode.h> 19109187Sdillon#else 20109187Sdillon#include <ufs/ufs/dir.h> 21109187Sdillon#include <ufs/ufs/dinode.h> 22109187Sdillon#include <ufs/ffs/fs.h> 23109187Sdillon#endif 24109187Sdillon 25109187Sdillon#include <protocols/dumprestore.h> 26109187Sdillon 27109187Sdillon#include <ctype.h> 28109187Sdillon#include <stdio.h> 29109187Sdillon#ifdef __STDC__ 30109187Sdillon#include <errno.h> 31109187Sdillon#include <string.h> 32109187Sdillon#include <stdlib.h> 33109187Sdillon#include <unistd.h> 34109187Sdillon#endif 35109187Sdillon#include "dump.h" 36109187Sdillon 37109187Sdillontypedef struct Block { 38109187Sdillon struct Block *b_HNext; /* must be first field */ 39109187Sdillon off_t b_Offset; 40109187Sdillon char *b_Data; 41109187Sdillon} Block; 42109187Sdillon 43109187Sdillon#define HFACTOR 4 44109187Sdillon#define BLKFACTOR 4 45109187Sdillon 46109187Sdillonstatic char *DataBase; 47109187Sdillonstatic Block **BlockHash; 48109187Sdillonstatic int BlockSize; 49109187Sdillonstatic int HSize; 50109187Sdillonstatic int NBlocks; 51109187Sdillon 52109187Sdillonstatic void 53109187Sdilloncinit(void) 54109187Sdillon{ 55109187Sdillon int i; 56109187Sdillon int hi; 57109187Sdillon Block *base; 58109187Sdillon 59109187Sdillon if ((BlockSize = sblock->fs_bsize * BLKFACTOR) > MAXBSIZE) 60109187Sdillon BlockSize = MAXBSIZE; 61109187Sdillon NBlocks = cachesize / BlockSize; 62109187Sdillon HSize = NBlocks / HFACTOR; 63109187Sdillon 64109187Sdillon msg("Cache %d MB, blocksize = %d\n", 65109187Sdillon NBlocks * BlockSize / (1024 * 1024), BlockSize); 66109187Sdillon 67109187Sdillon base = calloc(sizeof(Block), NBlocks); 68109187Sdillon BlockHash = calloc(sizeof(Block *), HSize); 69109187Sdillon DataBase = mmap(NULL, NBlocks * BlockSize, 70109187Sdillon PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 71109187Sdillon for (i = 0; i < NBlocks; ++i) { 72109187Sdillon base[i].b_Data = DataBase + i * BlockSize; 73109187Sdillon base[i].b_Offset = (off_t)-1; 74109187Sdillon hi = i / HFACTOR; 75109187Sdillon base[i].b_HNext = BlockHash[hi]; 76109187Sdillon BlockHash[hi] = &base[i]; 77109187Sdillon } 78109187Sdillon} 79109187Sdillon 80109187Sdillonssize_t 81109187Sdilloncread(int fd, void *buf, size_t nbytes, off_t offset) 82109187Sdillon{ 83109187Sdillon Block *blk; 84109187Sdillon Block **pblk; 85109187Sdillon Block **ppblk; 86109187Sdillon int hi; 87109187Sdillon int n; 88109187Sdillon off_t mask; 89109187Sdillon 90109187Sdillon /* 91109825Sdillon * If the cache is disabled, or we do not yet know the filesystem 92109825Sdillon * block size, then revert to pread. Otherwise initialize the 93109825Sdillon * cache as necessary and continue. 94109187Sdillon */ 95109825Sdillon if (cachesize <= 0 || sblock->fs_bsize == 0) 96109825Sdillon return(pread(fd, buf, nbytes, offset)); 97109825Sdillon if (DataBase == NULL) 98109187Sdillon cinit(); 99109187Sdillon 100109187Sdillon /* 101109187Sdillon * If the request crosses a cache block boundary, or the 102109187Sdillon * request is larger or equal to the cache block size, 103109187Sdillon * revert to pread(). Full-block-reads are typically 104109187Sdillon * one-time calls and caching would be detrimental. 105109187Sdillon */ 106109187Sdillon mask = ~(off_t)(BlockSize - 1); 107109187Sdillon if (nbytes >= BlockSize || 108109187Sdillon ((offset ^ (offset + nbytes - 1)) & mask) != 0) { 109109187Sdillon return(pread(fd, buf, nbytes, offset)); 110109187Sdillon } 111109187Sdillon 112109187Sdillon /* 113109187Sdillon * Obtain and access the cache block. Cache a successful 114109187Sdillon * result. If an error occurs, revert to pread() (this might 115109187Sdillon * occur near the end of the media). 116109187Sdillon */ 117109187Sdillon hi = (offset / BlockSize) % HSize; 118109187Sdillon pblk = &BlockHash[hi]; 119109187Sdillon ppblk = NULL; 120109187Sdillon while ((blk = *pblk) != NULL) { 121109825Sdillon if (((blk->b_Offset ^ offset) & mask) == 0) 122109187Sdillon break; 123109187Sdillon ppblk = pblk; 124109187Sdillon pblk = &blk->b_HNext; 125109187Sdillon } 126109187Sdillon if (blk == NULL) { 127109187Sdillon blk = *ppblk; 128109187Sdillon pblk = ppblk; 129109187Sdillon blk->b_Offset = offset & mask; 130109187Sdillon n = pread(fd, blk->b_Data, BlockSize, blk->b_Offset); 131109187Sdillon if (n != BlockSize) { 132109187Sdillon blk->b_Offset = (off_t)-1; 133109187Sdillon blk = NULL; 134109187Sdillon } 135109187Sdillon } 136109187Sdillon if (blk) { 137109187Sdillon bcopy(blk->b_Data + (offset - blk->b_Offset), buf, nbytes); 138109187Sdillon *pblk = blk->b_HNext; 139109187Sdillon blk->b_HNext = BlockHash[hi]; 140109187Sdillon BlockHash[hi] = blk; 141109187Sdillon return(nbytes); 142109187Sdillon } else { 143109187Sdillon return(pread(fd, buf, nbytes, offset)); 144109187Sdillon } 145109187Sdillon} 146109187Sdillon 147