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