1 /*
2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <fs_cache.h>
11 #include <fs_interface.h>
12
13 #include <file_cache.h>
14
15
16 #define MAX_VECS 32
17
18
19 class Map {
20 public:
21 Map(const char* name, off_t size);
22 ~Map();
23
24 void SetTo(const char* name, off_t size);
25
26 Map& Add(off_t offset, off_t length, off_t diskOffset);
27 Map& Clear();
28 Map& SetSize(off_t size);
29 void Invalidate(off_t start, off_t size);
30 void SetMode(uint32 mode);
31 void Test();
32
33 status_t GetFileMap(off_t offset, off_t length, file_io_vec* vecs,
34 size_t* _vecCount);
35
36 private:
37 void _Error(const char* format, ...);
38 void _Verbose(const char* format, ...);
39 int32 _IndexFor(off_t offset);
40
41 const char* fName;
42 uint32 fTest;
43 void* fMap;
44 off_t fOffsets[MAX_VECS];
45 file_io_vec fVecs[MAX_VECS];
46 file_io_vec fTestVecs[MAX_VECS];
47 uint32 fCount;
48 uint32 fTestCount;
49 off_t fTestOffset;
50 off_t fTestLength;
51 off_t fSize;
52 };
53
54
55 static bool sVerbose;
56
57
Map(const char * name,off_t size)58 Map::Map(const char* name, off_t size)
59 :
60 fName(NULL),
61 fMap(NULL),
62 fCount(0),
63 fSize(0)
64 {
65 SetTo(name, size);
66 }
67
68
~Map()69 Map::~Map()
70 {
71 file_map_delete(fMap);
72 }
73
74
75 void
SetTo(const char * name,off_t size)76 Map::SetTo(const char* name, off_t size)
77 {
78 file_map_delete(fMap);
79
80 fMap = file_map_create((dev_t)this, 0, size);
81 if (fMap == NULL)
82 _Error("Creating file map failed.");
83
84 fName = name;
85 fSize = size;
86 fCount = 0;
87 fTest = 0;
88
89 printf("Running %s\n", fName);
90 }
91
92
93 Map&
Add(off_t offset,off_t length,off_t diskOffset)94 Map::Add(off_t offset, off_t length, off_t diskOffset)
95 {
96 _Verbose(" Add(): offset %lld, length %lld, diskOffset %lld", offset,
97 length, diskOffset);
98
99 if (fCount < MAX_VECS) {
100 fOffsets[fCount] = offset;
101 fVecs[fCount].offset = diskOffset;
102 fVecs[fCount].length = length;
103 fCount++;
104 }
105
106 return *this;
107 }
108
109
110 Map&
Clear()111 Map::Clear()
112 {
113 _Verbose(" Clear()");
114 fCount = 0;
115 return *this;
116 }
117
118
119 Map&
SetSize(off_t size)120 Map::SetSize(off_t size)
121 {
122 _Verbose(" SetSize(): size %lld", size);
123 file_map_set_size(fMap, size);
124 fSize = size;
125 return *this;
126 }
127
128
129 void
Invalidate(off_t start,off_t size)130 Map::Invalidate(off_t start, off_t size)
131 {
132 _Verbose(" Invalidate(): start %lld, size %lld", start, size);
133 file_map_invalidate(fMap, start, size);
134 }
135
136
137 void
SetMode(uint32 mode)138 Map::SetMode(uint32 mode)
139 {
140 file_map_set_mode(fMap, mode);
141 }
142
143
144 void
Test()145 Map::Test()
146 {
147 printf(" Test %lu\n", ++fTest);
148
149 for (off_t offset = 0; offset < fSize; offset += 256) {
150 fTestOffset = offset;
151 fTestLength = 256;
152 fTestCount = MAX_VECS;
153 status_t status = file_map_translate(fMap, offset, fTestLength,
154 fTestVecs, &fTestCount, 0);
155 if (status != B_OK) {
156 _Error("file_map_translate(offset %lld) failed: %s", offset,
157 strerror(status));
158 }
159
160 int32 index = _IndexFor(offset);
161 if (index < 0)
162 _Error("index for offset %lld not found!", offset);
163
164 off_t diff = offset - fOffsets[index];
165
166 if (fTestVecs[0].length > fSize - diff) {
167 _Error("size too large: got %lld, size is %lld",
168 fTestVecs[0].length, fSize);
169 }
170 if (fTestVecs[0].offset != fVecs[index].offset + diff) {
171 _Error("offset mismatch: got %lld, should be %lld",
172 fTestVecs[0].offset, fVecs[index].offset + diff);
173 }
174 }
175
176 fTestCount = 0;
177 }
178
179
180 status_t
GetFileMap(off_t offset,off_t length,file_io_vec * vecs,size_t * _vecCount)181 Map::GetFileMap(off_t offset, off_t length, file_io_vec* vecs,
182 size_t* _vecCount)
183 {
184 int32 index = _IndexFor(offset);
185 if (index < 0)
186 _Error("No vec for offset %lld\n", offset);
187
188 _Verbose(" GetFileMap(): offset: %lld, length: %lld, index %ld", offset,
189 length, index);
190
191 uint32 count = 0;
192
193 while (length > 0) {
194 if (count >= *_vecCount)
195 return B_BUFFER_OVERFLOW;
196 if ((uint32)index >= fCount)
197 break;
198
199 off_t diff = offset - fOffsets[index];
200 vecs[count].offset = fVecs[index].offset + diff;
201 vecs[count].length = fVecs[index].length - diff;
202 _Verbose(" [%lu] offset %lld, length %lld", count,
203 vecs[count].offset, vecs[count].length);
204
205 length -= vecs[count].length;
206 offset += vecs[count].length;
207 index++;
208 count++;
209 }
210
211 *_vecCount = count;
212 return B_OK;
213 }
214
215
216 void
_Error(const char * format,...)217 Map::_Error(const char* format, ...)
218 {
219 va_list args;
220 va_start(args, format);
221
222 fprintf(stderr, "ERROR %s: ", fName);
223 vfprintf(stderr, format, args);
224 fputc('\n', stderr);
225
226 va_end(args);
227
228 fprintf(stderr, " size %lld\n", fSize);
229
230 for (uint32 i = 0; i < fCount; i++) {
231 fprintf(stderr, " [%lu] offset %lld, length %lld, disk offset %lld\n",
232 i, fOffsets[i], fVecs[i].length, fVecs[i].offset);
233 }
234
235 if (fTestCount > 0) {
236 fprintf(stderr, "got for offset %lld, length %lld:\n",
237 fTestOffset, fTestLength);
238 }
239
240 for (uint32 i = 0; i < fTestCount; i++) {
241 fprintf(stderr, " [%lu] offset %lld, length %lld\n",
242 i, fTestVecs[i].offset, fTestVecs[i].length);
243 }
244
245 fflush(stderr);
246
247 debugger("file map error");
248 exit(1);
249 }
250
251
252 void
_Verbose(const char * format,...)253 Map::_Verbose(const char* format, ...)
254 {
255 if (!sVerbose)
256 return;
257
258 va_list args;
259 va_start(args, format);
260
261 vprintf(format, args);
262 putchar('\n');
263
264 va_end(args);
265 fflush(stdout);
266 }
267
268
269 int32
_IndexFor(off_t offset)270 Map::_IndexFor(off_t offset)
271 {
272 for (uint32 i = 0; i < fCount; i++) {
273 if (offset >= fOffsets[i] && offset < fOffsets[i] + fVecs[i].length)
274 return i;
275 }
276
277 return -1;
278 }
279
280
281 // #pragma mark - VFS support functions
282
283
284 extern "C" status_t
vfs_get_file_map(struct vnode * vnode,off_t offset,uint32 length,file_io_vec * vecs,size_t * _vecCount)285 vfs_get_file_map(struct vnode* vnode, off_t offset, uint32 length,
286 file_io_vec* vecs, size_t* _vecCount)
287 {
288 Map* map = (Map*)vnode;
289 return map->GetFileMap(offset, length, vecs, _vecCount);
290 }
291
292
293 extern "C" status_t
vfs_lookup_vnode(dev_t mountID,ino_t vnodeID,struct vnode ** _vnode)294 vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode** _vnode)
295 {
296 *_vnode = (struct vnode*)mountID;
297 return B_OK;
298 }
299
300
301 // #pragma mark -
302
303
304 int
main(int argc,char ** argv)305 main(int argc, char** argv)
306 {
307 file_map_init();
308 sVerbose = true;
309
310 Map map("shrink1", 4096);
311 map.Add(0, 1024, 4096).Add(1024, 3072, 8192);
312 map.Test();
313 map.SetSize(0).Clear();
314 map.Test();
315 map.Add(0, 8192, 1000).SetSize(7777);
316 map.Test();
317
318 map.SetTo("shrink2", 8888);
319 map.Add(0, 10000, 3330000);
320 map.Test();
321 map.SetSize(0);
322 map.SetSize(4444);
323 map.Clear();
324 map.Add(0, 5000, 2220000);
325 map.Test();
326
327 map.SetTo("shrink3", 256000);
328 map.Add(0, 98304, 188074464);
329 map.Add(98304, 38912, 189057024);
330 map.Add(137216, 118784, 189177856);
331 map.Test();
332 map.SetSize(0);
333 map.Test();
334
335 return 0;
336 }
337