xref: /dragonfly/sbin/dump/cache.c (revision 9dbf638f)
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