cc295a1d35d8746542ee7870113cb3bf45cf4359
[dragonfly.git] / sbin / dump / cache.c
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.2 2003/06/17 04:27:32 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 <ufs/ufs/dir.h>
22 #include <ufs/ufs/dinode.h>
23 #include <ufs/ffs/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