15941e412SMatthew Dillon /*
25941e412SMatthew Dillon * CACHE.C
35941e412SMatthew Dillon *
45941e412SMatthew Dillon * Block cache for dump
55941e412SMatthew Dillon */
65941e412SMatthew Dillon
75941e412SMatthew Dillon #include <sys/param.h>
85941e412SMatthew Dillon #include <sys/stat.h>
95941e412SMatthew Dillon #include <sys/mman.h>
105941e412SMatthew Dillon
115941e412SMatthew Dillon #ifdef sunos
125941e412SMatthew Dillon #include <sys/vnode.h>
135941e412SMatthew Dillon
145941e412SMatthew Dillon #include <ufs/fs.h>
155941e412SMatthew Dillon #include <ufs/fsdir.h>
165941e412SMatthew Dillon #include <ufs/inode.h>
175941e412SMatthew Dillon #else
185941e412SMatthew Dillon #include <ufs/ufs/dir.h>
195941e412SMatthew Dillon #include <ufs/ufs/dinode.h>
205941e412SMatthew Dillon #include <ufs/ffs/fs.h>
215941e412SMatthew Dillon #endif
225941e412SMatthew Dillon
235941e412SMatthew Dillon #include <protocols/dumprestore.h>
245941e412SMatthew Dillon
255941e412SMatthew Dillon #include <ctype.h>
265941e412SMatthew Dillon #include <stdio.h>
275941e412SMatthew Dillon #ifdef __STDC__
285941e412SMatthew Dillon #include <errno.h>
295941e412SMatthew Dillon #include <string.h>
305941e412SMatthew Dillon #include <stdlib.h>
315941e412SMatthew Dillon #include <unistd.h>
325941e412SMatthew Dillon #endif
335941e412SMatthew Dillon #include "dump.h"
345941e412SMatthew Dillon
355941e412SMatthew Dillon typedef struct Block {
365941e412SMatthew Dillon struct Block *b_HNext; /* must be first field */
375941e412SMatthew Dillon off_t b_Offset;
385941e412SMatthew Dillon char *b_Data;
395941e412SMatthew Dillon } Block;
405941e412SMatthew Dillon
415941e412SMatthew Dillon #define HFACTOR 4
425941e412SMatthew Dillon #define BLKFACTOR 4
435941e412SMatthew Dillon
445941e412SMatthew Dillon static char *DataBase;
455941e412SMatthew Dillon static Block **BlockHash;
465941e412SMatthew Dillon static int BlockSize;
475941e412SMatthew Dillon static int HSize;
485941e412SMatthew Dillon static int NBlocks;
495941e412SMatthew Dillon
505941e412SMatthew Dillon static void
cinit(void)515941e412SMatthew Dillon cinit(void)
525941e412SMatthew Dillon {
535941e412SMatthew Dillon int i;
545941e412SMatthew Dillon int hi;
555941e412SMatthew Dillon Block *base;
565941e412SMatthew Dillon
575941e412SMatthew Dillon if ((BlockSize = sblock->fs_bsize * BLKFACTOR) > MAXBSIZE)
585941e412SMatthew Dillon BlockSize = MAXBSIZE;
595941e412SMatthew Dillon NBlocks = cachesize / BlockSize;
605941e412SMatthew Dillon HSize = NBlocks / HFACTOR;
615941e412SMatthew Dillon
625941e412SMatthew Dillon msg("Cache %d MB, blocksize = %d\n",
635941e412SMatthew Dillon NBlocks * BlockSize / (1024 * 1024), BlockSize);
645941e412SMatthew Dillon
655941e412SMatthew Dillon base = calloc(sizeof(Block), NBlocks);
665941e412SMatthew Dillon BlockHash = calloc(sizeof(Block *), HSize);
675941e412SMatthew Dillon DataBase = mmap(NULL, NBlocks * BlockSize,
685941e412SMatthew Dillon PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
695941e412SMatthew Dillon for (i = 0; i < NBlocks; ++i) {
705941e412SMatthew Dillon base[i].b_Data = DataBase + i * BlockSize;
715941e412SMatthew Dillon base[i].b_Offset = (off_t)-1;
725941e412SMatthew Dillon hi = i / HFACTOR;
735941e412SMatthew Dillon base[i].b_HNext = BlockHash[hi];
745941e412SMatthew Dillon BlockHash[hi] = &base[i];
755941e412SMatthew Dillon }
765941e412SMatthew Dillon }
775941e412SMatthew Dillon
785941e412SMatthew Dillon ssize_t
cread(int fd,void * buf,size_t nbytes,off_t offset)795941e412SMatthew Dillon cread(int fd, void *buf, size_t nbytes, off_t offset)
805941e412SMatthew Dillon {
815941e412SMatthew Dillon Block *blk;
825941e412SMatthew Dillon Block **pblk;
835941e412SMatthew Dillon Block **ppblk;
845941e412SMatthew Dillon int hi;
855941e412SMatthew Dillon int n;
865941e412SMatthew Dillon off_t mask;
875941e412SMatthew Dillon
885941e412SMatthew Dillon /*
89*049b1245SMatthew Dillon * If the cache is disabled, or we do not yet know the filesystem
90*049b1245SMatthew Dillon * block size, then revert to pread. Otherwise initialize the
91*049b1245SMatthew Dillon * cache as necessary and continue.
925941e412SMatthew Dillon */
93*049b1245SMatthew Dillon if (cachesize <= 0 || sblock->fs_bsize == 0)
945941e412SMatthew Dillon return(pread(fd, buf, nbytes, offset));
95*049b1245SMatthew Dillon if (DataBase == NULL)
965941e412SMatthew Dillon cinit();
975941e412SMatthew Dillon
985941e412SMatthew Dillon /*
995941e412SMatthew Dillon * If the request crosses a cache block boundary, or the
1005941e412SMatthew Dillon * request is larger or equal to the cache block size,
1015941e412SMatthew Dillon * revert to pread(). Full-block-reads are typically
1025941e412SMatthew Dillon * one-time calls and caching would be detrimental.
1035941e412SMatthew Dillon */
1045941e412SMatthew Dillon mask = ~(off_t)(BlockSize - 1);
1055941e412SMatthew Dillon if (nbytes >= BlockSize ||
1065941e412SMatthew Dillon ((offset ^ (offset + nbytes - 1)) & mask) != 0) {
1075941e412SMatthew Dillon return(pread(fd, buf, nbytes, offset));
1085941e412SMatthew Dillon }
1095941e412SMatthew Dillon
1105941e412SMatthew Dillon /*
1115941e412SMatthew Dillon * Obtain and access the cache block. Cache a successful
1125941e412SMatthew Dillon * result. If an error occurs, revert to pread() (this might
1135941e412SMatthew Dillon * occur near the end of the media).
1145941e412SMatthew Dillon */
1155941e412SMatthew Dillon hi = (offset / BlockSize) % HSize;
1165941e412SMatthew Dillon pblk = &BlockHash[hi];
1175941e412SMatthew Dillon ppblk = NULL;
1185941e412SMatthew Dillon while ((blk = *pblk) != NULL) {
119*049b1245SMatthew Dillon if (((blk->b_Offset ^ offset) & mask) == 0)
1205941e412SMatthew Dillon break;
1215941e412SMatthew Dillon ppblk = pblk;
1225941e412SMatthew Dillon pblk = &blk->b_HNext;
1235941e412SMatthew Dillon }
1245941e412SMatthew Dillon if (blk == NULL) {
1255941e412SMatthew Dillon blk = *ppblk;
1265941e412SMatthew Dillon pblk = ppblk;
1275941e412SMatthew Dillon blk->b_Offset = offset & mask;
1285941e412SMatthew Dillon n = pread(fd, blk->b_Data, BlockSize, blk->b_Offset);
1295941e412SMatthew Dillon if (n != BlockSize) {
1305941e412SMatthew Dillon blk->b_Offset = (off_t)-1;
1315941e412SMatthew Dillon blk = NULL;
1325941e412SMatthew Dillon }
1335941e412SMatthew Dillon }
1345941e412SMatthew Dillon if (blk) {
1355941e412SMatthew Dillon bcopy(blk->b_Data + (offset - blk->b_Offset), buf, nbytes);
1365941e412SMatthew Dillon *pblk = blk->b_HNext;
1375941e412SMatthew Dillon blk->b_HNext = BlockHash[hi];
1385941e412SMatthew Dillon BlockHash[hi] = blk;
1395941e412SMatthew Dillon return(nbytes);
1405941e412SMatthew Dillon } else {
1415941e412SMatthew Dillon return(pread(fd, buf, nbytes, offset));
1425941e412SMatthew Dillon }
1435941e412SMatthew Dillon }
1445941e412SMatthew Dillon
145