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