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
19class Map {
20public:
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
36private:
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
55static bool sVerbose;
56
57
58Map::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
69Map::~Map()
70{
71	file_map_delete(fMap);
72}
73
74
75void
76Map::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
93Map&
94Map::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
110Map&
111Map::Clear()
112{
113	_Verbose("  Clear()");
114	fCount = 0;
115	return *this;
116}
117
118
119Map&
120Map::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
129void
130Map::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
137void
138Map::SetMode(uint32 mode)
139{
140	file_map_set_mode(fMap, mode);
141}
142
143
144void
145Map::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
180status_t
181Map::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
216void
217Map::_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
252void
253Map::_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
269int32
270Map::_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
284extern "C" status_t
285vfs_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
293extern "C" status_t
294vfs_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
304int
305main(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