xref: /haiku/src/tests/system/kernel/cache/file_map_test.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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 
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 
69 Map::~Map()
70 {
71 	file_map_delete(fMap);
72 }
73 
74 
75 void
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&
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&
111 Map::Clear()
112 {
113 	_Verbose("  Clear()");
114 	fCount = 0;
115 	return *this;
116 }
117 
118 
119 Map&
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
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
138 Map::SetMode(uint32 mode)
139 {
140 	file_map_set_mode(fMap, mode);
141 }
142 
143 
144 void
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
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
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
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
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
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
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
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