]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/dump/cache.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / dump / cache.c
1 /*
2  * CACHE.C
3  *
4  *      Block cache for dump
5  *
6  * $FreeBSD$
7  */
8
9 #include <sys/param.h>
10 #include <sys/stat.h>
11 #include <sys/mman.h>
12
13 #ifdef sunos
14 #include <sys/vnode.h>
15
16 #include <ufs/fs.h>
17 #include <ufs/fsdir.h>
18 #include <ufs/inode.h>
19 #else
20 #include <ufs/ufs/dir.h>
21 #include <ufs/ufs/dinode.h>
22 #include <ufs/ffs/fs.h>
23 #endif
24
25 #include <protocols/dumprestore.h>
26
27 #include <ctype.h>
28 #include <stdio.h>
29 #ifdef __STDC__
30 #include <errno.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #endif
35 #include "dump.h"
36
37 typedef struct Block {
38         struct Block    *b_HNext;       /* must be first field */
39         off_t           b_Offset;
40         char            *b_Data;
41 } Block;
42
43 #define HFACTOR         4
44 #define BLKFACTOR       4
45
46 static char  *DataBase;
47 static Block **BlockHash;
48 static int   BlockSize;
49 static int   HSize;
50 static int   NBlocks;
51
52 static void
53 cinit(void)
54 {
55         int i;
56         int hi;
57         Block *base;
58
59         if ((BlockSize = sblock->fs_bsize * BLKFACTOR) > MAXBSIZE)
60                 BlockSize = MAXBSIZE;
61         NBlocks = cachesize / BlockSize;
62         HSize = NBlocks / HFACTOR;
63
64         msg("Cache %d MB, blocksize = %d\n", 
65             NBlocks * BlockSize / (1024 * 1024), BlockSize);
66
67         base = calloc(sizeof(Block), NBlocks);
68         BlockHash = calloc(sizeof(Block *), HSize);
69         DataBase = mmap(NULL, NBlocks * BlockSize, 
70                         PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
71         for (i = 0; i < NBlocks; ++i) {
72                 base[i].b_Data = DataBase + i * BlockSize;
73                 base[i].b_Offset = (off_t)-1;
74                 hi = i / HFACTOR;
75                 base[i].b_HNext = BlockHash[hi];
76                 BlockHash[hi] = &base[i];
77         }
78 }
79
80 ssize_t
81 cread(int fd, void *buf, size_t nbytes, off_t offset)
82 {
83         Block *blk;
84         Block **pblk;
85         Block **ppblk;
86         int hi;
87         int n;
88         off_t mask;
89
90         /*
91          * If the cache is disabled, or we do not yet know the filesystem
92          * block size, then revert to pread.  Otherwise initialize the
93          * cache as necessary and continue.
94          */
95         if (cachesize <= 0 || sblock->fs_bsize == 0)
96                 return(pread(fd, buf, nbytes, offset));
97         if (DataBase == NULL)
98                 cinit();
99
100         /*
101          * If the request crosses a cache block boundary, or the
102          * request is larger or equal to the cache block size,
103          * revert to pread().  Full-block-reads are typically
104          * one-time calls and caching would be detrimental.
105          */
106         mask = ~(off_t)(BlockSize - 1);
107         if (nbytes >= BlockSize ||
108             ((offset ^ (offset + nbytes - 1)) & mask) != 0) {
109                 return(pread(fd, buf, nbytes, offset));
110         }
111
112         /*
113          * Obtain and access the cache block.  Cache a successful
114          * result.  If an error occurs, revert to pread() (this might
115          * occur near the end of the media).
116          */
117         hi = (offset / BlockSize) % HSize;
118         pblk = &BlockHash[hi];
119         ppblk = NULL;
120         while ((blk = *pblk) != NULL) {
121                 if (((blk->b_Offset ^ offset) & mask) == 0)
122                         break;
123                 ppblk = pblk;
124                 pblk = &blk->b_HNext;
125         }
126         if (blk == NULL) {
127                 blk = *ppblk;
128                 pblk = ppblk;
129                 blk->b_Offset = offset & mask;
130                 n = pread(fd, blk->b_Data, BlockSize, blk->b_Offset);
131                 if (n != BlockSize) {
132                         blk->b_Offset = (off_t)-1;
133                         blk = NULL;
134                 }
135         }
136         if (blk) {
137                 bcopy(blk->b_Data + (offset - blk->b_Offset), buf, nbytes);
138                 *pblk = blk->b_HNext;
139                 blk->b_HNext = BlockHash[hi];
140                 BlockHash[hi] = blk;
141                 return(nbytes);
142         } else {
143                 return(pread(fd, buf, nbytes, offset));
144         }
145 }
146