xref: /haiku/src/tests/system/kernel/cache/pages_io_test.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
1df0ca8caSAxel Dörfler /*
2df0ca8caSAxel Dörfler  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3df0ca8caSAxel Dörfler  * Distributed under the terms of the MIT License.
4df0ca8caSAxel Dörfler  */
5df0ca8caSAxel Dörfler 
6df0ca8caSAxel Dörfler 
7238d7b4bSAxel Dörfler #include <OS.h>
8238d7b4bSAxel Dörfler #include <fs_interface.h>
9238d7b4bSAxel Dörfler 
10238d7b4bSAxel Dörfler #include <stdarg.h>
11238d7b4bSAxel Dörfler #include <stdio.h>
12238d7b4bSAxel Dörfler #include <stdlib.h>
1370a11cecSAxel Dörfler #include <string.h>
14238d7b4bSAxel Dörfler #include <sys/uio.h>
15238d7b4bSAxel Dörfler 
16238d7b4bSAxel Dörfler #define TRACE_FILE_CACHE
17238d7b4bSAxel Dörfler #define TRACE(x) printf x
18238d7b4bSAxel Dörfler #define dprintf printf
19238d7b4bSAxel Dörfler 
20df0ca8caSAxel Dörfler #ifndef ASSERT
21df0ca8caSAxel Dörfler #	define ASSERT(x) ;
22df0ca8caSAxel Dörfler #endif
23df0ca8caSAxel Dörfler 
24238d7b4bSAxel Dörfler // maximum number of iovecs per request
25238d7b4bSAxel Dörfler #define MAX_IO_VECS			64	// 256 kB
2670a11cecSAxel Dörfler #define MAX_FILE_IO_VECS	4
27238d7b4bSAxel Dörfler #define MAX_TEMP_IO_VECS	8
28238d7b4bSAxel Dörfler 
29238d7b4bSAxel Dörfler #define CACHED_FILE_EXTENTS	2
30238d7b4bSAxel Dörfler 	// must be smaller than MAX_FILE_IO_VECS
31238d7b4bSAxel Dörfler 	// ToDo: find out how much of these are typically used
32238d7b4bSAxel Dörfler 
33238d7b4bSAxel Dörfler struct vm_cache_ref;
34238d7b4bSAxel Dörfler 
35238d7b4bSAxel Dörfler struct file_extent {
36238d7b4bSAxel Dörfler 	off_t			offset;
37238d7b4bSAxel Dörfler 	file_io_vec		disk;
38238d7b4bSAxel Dörfler };
39238d7b4bSAxel Dörfler 
40238d7b4bSAxel Dörfler struct file_map {
41238d7b4bSAxel Dörfler 	file_map();
42238d7b4bSAxel Dörfler 	~file_map();
43238d7b4bSAxel Dörfler 
44238d7b4bSAxel Dörfler 	file_extent *operator[](uint32 index);
45238d7b4bSAxel Dörfler 	file_extent *ExtentAt(uint32 index);
46238d7b4bSAxel Dörfler 	status_t Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset);
47238d7b4bSAxel Dörfler 	void Free();
48238d7b4bSAxel Dörfler 
49238d7b4bSAxel Dörfler 	union {
50238d7b4bSAxel Dörfler 		file_extent	direct[CACHED_FILE_EXTENTS];
51238d7b4bSAxel Dörfler 		file_extent	*array;
52238d7b4bSAxel Dörfler 	};
53238d7b4bSAxel Dörfler 	size_t			count;
54238d7b4bSAxel Dörfler };
55238d7b4bSAxel Dörfler 
56238d7b4bSAxel Dörfler struct file_cache_ref {
57238d7b4bSAxel Dörfler 	vm_cache_ref	*cache;
58238d7b4bSAxel Dörfler 	void			*vnode;
59238d7b4bSAxel Dörfler 	void			*device;
60238d7b4bSAxel Dörfler 	void			*cookie;
61238d7b4bSAxel Dörfler 	file_map		map;
62238d7b4bSAxel Dörfler };
63238d7b4bSAxel Dörfler 
64238d7b4bSAxel Dörfler 
6570a11cecSAxel Dörfler const uint32 kMaxFileVecs = 1024;
6670a11cecSAxel Dörfler 
6770a11cecSAxel Dörfler file_io_vec gFileVecs[kMaxFileVecs];
68238d7b4bSAxel Dörfler size_t gFileVecCount;
69238d7b4bSAxel Dörfler off_t gFileSize;
70238d7b4bSAxel Dörfler 
71238d7b4bSAxel Dörfler 
file_map()72238d7b4bSAxel Dörfler file_map::file_map()
73238d7b4bSAxel Dörfler {
74238d7b4bSAxel Dörfler 	array = NULL;
75238d7b4bSAxel Dörfler 	count = 0;
76238d7b4bSAxel Dörfler }
77238d7b4bSAxel Dörfler 
78238d7b4bSAxel Dörfler 
~file_map()79238d7b4bSAxel Dörfler file_map::~file_map()
80238d7b4bSAxel Dörfler {
81238d7b4bSAxel Dörfler 	Free();
82238d7b4bSAxel Dörfler }
83238d7b4bSAxel Dörfler 
84238d7b4bSAxel Dörfler 
85238d7b4bSAxel Dörfler file_extent *
operator [](uint32 index)86238d7b4bSAxel Dörfler file_map::operator[](uint32 index)
87238d7b4bSAxel Dörfler {
88238d7b4bSAxel Dörfler 	return ExtentAt(index);
89238d7b4bSAxel Dörfler }
90238d7b4bSAxel Dörfler 
91238d7b4bSAxel Dörfler 
92238d7b4bSAxel Dörfler file_extent *
ExtentAt(uint32 index)93238d7b4bSAxel Dörfler file_map::ExtentAt(uint32 index)
94238d7b4bSAxel Dörfler {
95238d7b4bSAxel Dörfler 	if (index >= count)
96238d7b4bSAxel Dörfler 		return NULL;
97238d7b4bSAxel Dörfler 
98238d7b4bSAxel Dörfler 	if (count > CACHED_FILE_EXTENTS)
99238d7b4bSAxel Dörfler 		return &array[index];
100238d7b4bSAxel Dörfler 
101238d7b4bSAxel Dörfler 	return &direct[index];
102238d7b4bSAxel Dörfler }
103238d7b4bSAxel Dörfler 
104238d7b4bSAxel Dörfler 
105238d7b4bSAxel Dörfler status_t
Add(file_io_vec * vecs,size_t vecCount,off_t & lastOffset)106238d7b4bSAxel Dörfler file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
107238d7b4bSAxel Dörfler {
108238d7b4bSAxel Dörfler 	TRACE(("file_map::Add(vecCount = %ld)\n", vecCount));
109238d7b4bSAxel Dörfler 
110238d7b4bSAxel Dörfler 	off_t offset = 0;
111238d7b4bSAxel Dörfler 
112238d7b4bSAxel Dörfler 	if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
113238d7b4bSAxel Dörfler 		// just use the reserved area in the file_cache_ref structure
114238d7b4bSAxel Dörfler 	} else {
115238d7b4bSAxel Dörfler 		// TODO: once we can invalidate only parts of the file map,
116238d7b4bSAxel Dörfler 		//	we might need to copy the previously cached file extends
117238d7b4bSAxel Dörfler 		//	from the direct range
118238d7b4bSAxel Dörfler 		file_extent *newMap = (file_extent *)realloc(array,
119238d7b4bSAxel Dörfler 			(count + vecCount) * sizeof(file_extent));
120238d7b4bSAxel Dörfler 		if (newMap == NULL)
121238d7b4bSAxel Dörfler 			return B_NO_MEMORY;
122238d7b4bSAxel Dörfler 
123238d7b4bSAxel Dörfler 		array = newMap;
124238d7b4bSAxel Dörfler 
125238d7b4bSAxel Dörfler 		if (count != 0) {
126238d7b4bSAxel Dörfler 			file_extent *extent = ExtentAt(count - 1);
127238d7b4bSAxel Dörfler 			offset = extent->offset + extent->disk.length;
128238d7b4bSAxel Dörfler 		}
129238d7b4bSAxel Dörfler 	}
130238d7b4bSAxel Dörfler 
131238d7b4bSAxel Dörfler 	int32 start = count;
132238d7b4bSAxel Dörfler 	count += vecCount;
133238d7b4bSAxel Dörfler 
134238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < vecCount; i++) {
135238d7b4bSAxel Dörfler 		file_extent *extent = ExtentAt(start + i);
136238d7b4bSAxel Dörfler 
137238d7b4bSAxel Dörfler 		extent->offset = offset;
138238d7b4bSAxel Dörfler 		extent->disk = vecs[i];
139238d7b4bSAxel Dörfler 
140238d7b4bSAxel Dörfler 		offset += extent->disk.length;
141238d7b4bSAxel Dörfler 	}
142238d7b4bSAxel Dörfler 
143238d7b4bSAxel Dörfler #ifdef TRACE_FILE_CACHE
144238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
145238d7b4bSAxel Dörfler 		file_extent *extent = ExtentAt(i);
146*425ac1b6SAlexander von Gluck IV 		dprintf("  [%ld] extend offset %lld, disk offset %lld, length %lld\n",
147238d7b4bSAxel Dörfler 			i, extent->offset, extent->disk.offset, extent->disk.length);
148238d7b4bSAxel Dörfler 	}
149238d7b4bSAxel Dörfler #endif
150238d7b4bSAxel Dörfler 
151238d7b4bSAxel Dörfler 	lastOffset = offset;
152238d7b4bSAxel Dörfler 	return B_OK;
153238d7b4bSAxel Dörfler }
154238d7b4bSAxel Dörfler 
155238d7b4bSAxel Dörfler 
156238d7b4bSAxel Dörfler void
Free()157238d7b4bSAxel Dörfler file_map::Free()
158238d7b4bSAxel Dörfler {
159238d7b4bSAxel Dörfler 	if (count > CACHED_FILE_EXTENTS)
160238d7b4bSAxel Dörfler 		free(array);
161238d7b4bSAxel Dörfler 
162238d7b4bSAxel Dörfler 	array = NULL;
163238d7b4bSAxel Dörfler 	count = 0;
164238d7b4bSAxel Dörfler }
165238d7b4bSAxel Dörfler 
166238d7b4bSAxel Dörfler 
167238d7b4bSAxel Dörfler //	#pragma mark -
168238d7b4bSAxel Dörfler 
169238d7b4bSAxel Dörfler 
170238d7b4bSAxel Dörfler void
set_vecs(iovec * vecs,size_t * _count,...)171238d7b4bSAxel Dörfler set_vecs(iovec *vecs, size_t *_count, ...)
172238d7b4bSAxel Dörfler {
173238d7b4bSAxel Dörfler 	uint32 base = 0;
174238d7b4bSAxel Dörfler 	size_t count = 0;
175238d7b4bSAxel Dörfler 
176238d7b4bSAxel Dörfler 	va_list args;
177238d7b4bSAxel Dörfler 	va_start(args, _count);
178238d7b4bSAxel Dörfler 
179238d7b4bSAxel Dörfler 	while (count < MAX_IO_VECS) {
180238d7b4bSAxel Dörfler 		int32 length = va_arg(args, int32);
181238d7b4bSAxel Dörfler 		if (length < 0)
182238d7b4bSAxel Dörfler 			break;
183238d7b4bSAxel Dörfler 
184238d7b4bSAxel Dörfler 		vecs[count].iov_base = (void *)base;
185238d7b4bSAxel Dörfler 		vecs[count].iov_len = length;
186238d7b4bSAxel Dörfler 
187238d7b4bSAxel Dörfler 		base += length;
188238d7b4bSAxel Dörfler 		count++;
189238d7b4bSAxel Dörfler 	}
190238d7b4bSAxel Dörfler 
191238d7b4bSAxel Dörfler 	va_end(args);
192238d7b4bSAxel Dörfler 	*_count = count;
193238d7b4bSAxel Dörfler }
194238d7b4bSAxel Dörfler 
195238d7b4bSAxel Dörfler 
196238d7b4bSAxel Dörfler void
set_file_map(int32 base,int32 length,...)197238d7b4bSAxel Dörfler set_file_map(int32 base, int32 length, ...)
198238d7b4bSAxel Dörfler {
199238d7b4bSAxel Dörfler 	gFileVecs[0].offset = base;
200238d7b4bSAxel Dörfler 	gFileVecs[0].length = length;
201238d7b4bSAxel Dörfler 
202238d7b4bSAxel Dörfler 	gFileSize = length;
203238d7b4bSAxel Dörfler 	gFileVecCount = 1;
204238d7b4bSAxel Dörfler 
205238d7b4bSAxel Dörfler 	va_list args;
206238d7b4bSAxel Dörfler 	va_start(args, length);
207238d7b4bSAxel Dörfler 
20870a11cecSAxel Dörfler 	while (gFileVecCount < kMaxFileVecs) {
209238d7b4bSAxel Dörfler 		off_t offset = va_arg(args, int32);
210238d7b4bSAxel Dörfler 		if (offset < 0)
211238d7b4bSAxel Dörfler 			break;
212238d7b4bSAxel Dörfler 
213238d7b4bSAxel Dörfler 		length = va_arg(args, int32);
214238d7b4bSAxel Dörfler 
215238d7b4bSAxel Dörfler 		gFileVecs[gFileVecCount].offset = offset;
216238d7b4bSAxel Dörfler 		gFileVecs[gFileVecCount].length = length;
217238d7b4bSAxel Dörfler 
218238d7b4bSAxel Dörfler 		gFileSize += length;
219238d7b4bSAxel Dörfler 		gFileVecCount++;
220238d7b4bSAxel Dörfler 	}
221238d7b4bSAxel Dörfler 
222238d7b4bSAxel Dörfler 	va_end(args);
223238d7b4bSAxel Dörfler }
224238d7b4bSAxel Dörfler 
225238d7b4bSAxel Dörfler 
226238d7b4bSAxel Dörfler status_t
find_map_base(off_t offset,off_t & diskOffset,off_t & diskLength,off_t & fileOffset)227238d7b4bSAxel Dörfler find_map_base(off_t offset, off_t &diskOffset, off_t &diskLength,
228238d7b4bSAxel Dörfler 	off_t &fileOffset)
229238d7b4bSAxel Dörfler {
230238d7b4bSAxel Dörfler 	fileOffset = 0;
231238d7b4bSAxel Dörfler 
232238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < gFileVecCount; i++) {
233238d7b4bSAxel Dörfler 		if (offset < gFileVecs[i].length) {
234238d7b4bSAxel Dörfler 			diskOffset = gFileVecs[i].offset;
235238d7b4bSAxel Dörfler 			diskLength = gFileVecs[i].length;
236238d7b4bSAxel Dörfler 			return B_OK;
237238d7b4bSAxel Dörfler 		}
238238d7b4bSAxel Dörfler 
239238d7b4bSAxel Dörfler 		fileOffset += gFileVecs[i].length;
240238d7b4bSAxel Dörfler 		offset -= gFileVecs[i].length;
241238d7b4bSAxel Dörfler 	}
242238d7b4bSAxel Dörfler 
243238d7b4bSAxel Dörfler 	return B_ENTRY_NOT_FOUND;
244238d7b4bSAxel Dörfler }
245238d7b4bSAxel Dörfler 
246238d7b4bSAxel Dörfler 
247238d7b4bSAxel Dörfler //	#pragma mark - VFS functions
248238d7b4bSAxel Dörfler 
249238d7b4bSAxel Dörfler 
250238d7b4bSAxel Dörfler static status_t
vfs_get_file_map(void * vnode,off_t offset,size_t size,file_io_vec * vecs,size_t * _count)251238d7b4bSAxel Dörfler vfs_get_file_map(void *vnode, off_t offset, size_t size, file_io_vec *vecs,
252238d7b4bSAxel Dörfler 	size_t *_count)
253238d7b4bSAxel Dörfler {
254238d7b4bSAxel Dörfler 	off_t diskOffset, diskLength, fileOffset;
255238d7b4bSAxel Dörfler 	size_t max = *_count;
256238d7b4bSAxel Dörfler 	uint32 index = 0;
257238d7b4bSAxel Dörfler 
258*425ac1b6SAlexander von Gluck IV 	printf("vfs_get_file_map(offset = %lld, size = %lu, count = %lu)\n",
25970a11cecSAxel Dörfler 		offset, size, *_count);
26070a11cecSAxel Dörfler 
261238d7b4bSAxel Dörfler 	while (true) {
262238d7b4bSAxel Dörfler 		status_t status = find_map_base(offset, diskOffset, diskLength, fileOffset);
263238d7b4bSAxel Dörfler 		//status_t status = inode->FindBlockRun(offset, run, fileOffset);
264238d7b4bSAxel Dörfler 		if (status != B_OK)
265238d7b4bSAxel Dörfler 			return status;
266238d7b4bSAxel Dörfler 
267238d7b4bSAxel Dörfler 		vecs[index].offset = diskOffset + offset - fileOffset;
268238d7b4bSAxel Dörfler 		vecs[index].length = diskLength - offset + fileOffset;
269238d7b4bSAxel Dörfler 		offset += vecs[index].length;
270238d7b4bSAxel Dörfler 
271238d7b4bSAxel Dörfler 		// are we already done?
272238d7b4bSAxel Dörfler 		if (size <= vecs[index].length
273238d7b4bSAxel Dörfler 			|| offset >= gFileSize) {
274238d7b4bSAxel Dörfler 			if (offset > gFileSize) {
275238d7b4bSAxel Dörfler 				// make sure the extent ends with the last official file
276238d7b4bSAxel Dörfler 				// block (without taking any preallocations into account)
277238d7b4bSAxel Dörfler 				vecs[index].length = gFileSize - fileOffset;
278238d7b4bSAxel Dörfler 			}
279238d7b4bSAxel Dörfler 			*_count = index + 1;
280238d7b4bSAxel Dörfler 			return B_OK;
281238d7b4bSAxel Dörfler 		}
282238d7b4bSAxel Dörfler 
283238d7b4bSAxel Dörfler 		size -= vecs[index].length;
284238d7b4bSAxel Dörfler 		index++;
285238d7b4bSAxel Dörfler 
286238d7b4bSAxel Dörfler 		if (index >= max) {
287238d7b4bSAxel Dörfler 			// we're out of file_io_vecs; let's bail out
288238d7b4bSAxel Dörfler 			*_count = index;
289238d7b4bSAxel Dörfler 			return B_BUFFER_OVERFLOW;
290238d7b4bSAxel Dörfler 		}
291238d7b4bSAxel Dörfler 	}
292238d7b4bSAxel Dörfler }
293238d7b4bSAxel Dörfler 
294238d7b4bSAxel Dörfler 
295238d7b4bSAxel Dörfler static status_t
vfs_read_pages(void * device,void * cookie,off_t offset,const iovec * vecs,size_t count,size_t * bytes,bool kernel)296238d7b4bSAxel Dörfler vfs_read_pages(void *device, void *cookie, off_t offset,
297238d7b4bSAxel Dörfler 	const iovec *vecs, size_t count, size_t *bytes, bool kernel)
298238d7b4bSAxel Dörfler {
299*425ac1b6SAlexander von Gluck IV 	printf("read offset %lld, length %lu\n", offset, *bytes);
300238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
301238d7b4bSAxel Dörfler 		printf("  [%lu] base %lu, length %lu\n",
302238d7b4bSAxel Dörfler 			i, (uint32)vecs[i].iov_base, vecs[i].iov_len);
303238d7b4bSAxel Dörfler 	}
304238d7b4bSAxel Dörfler 	return B_OK;
305238d7b4bSAxel Dörfler }
306238d7b4bSAxel Dörfler 
307238d7b4bSAxel Dörfler 
308238d7b4bSAxel Dörfler static status_t
vfs_write_pages(void * device,void * cookie,off_t offset,const iovec * vecs,size_t count,size_t * bytes,bool kernel)309238d7b4bSAxel Dörfler vfs_write_pages(void *device, void *cookie, off_t offset,
310238d7b4bSAxel Dörfler 	const iovec *vecs, size_t count, size_t *bytes, bool kernel)
311238d7b4bSAxel Dörfler {
312*425ac1b6SAlexander von Gluck IV 	printf("write offset %lld, length %lu\n", offset, *bytes);
313238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
314238d7b4bSAxel Dörfler 		printf("  [%lu] base %lu, length %lu\n",
315238d7b4bSAxel Dörfler 			i, (uint32)vecs[i].iov_base, vecs[i].iov_len);
316238d7b4bSAxel Dörfler 	}
317238d7b4bSAxel Dörfler 	return B_OK;
318238d7b4bSAxel Dörfler }
319238d7b4bSAxel Dörfler 
320238d7b4bSAxel Dörfler 
321238d7b4bSAxel Dörfler //	#pragma mark - file_cache.cpp copies
322238d7b4bSAxel Dörfler 
323238d7b4bSAxel Dörfler 
324238d7b4bSAxel Dörfler static file_extent *
find_file_extent(file_cache_ref * ref,off_t offset,uint32 * _index)325238d7b4bSAxel Dörfler find_file_extent(file_cache_ref *ref, off_t offset, uint32 *_index)
326238d7b4bSAxel Dörfler {
327238d7b4bSAxel Dörfler 	// TODO: do binary search
328238d7b4bSAxel Dörfler 
329238d7b4bSAxel Dörfler 	for (uint32 index = 0; index < ref->map.count; index++) {
330238d7b4bSAxel Dörfler 		file_extent *extent = ref->map[index];
331238d7b4bSAxel Dörfler 
332238d7b4bSAxel Dörfler 		if (extent->offset <= offset
333238d7b4bSAxel Dörfler 			&& extent->offset + extent->disk.length > offset) {
334238d7b4bSAxel Dörfler 			if (_index)
335238d7b4bSAxel Dörfler 				*_index = index;
336238d7b4bSAxel Dörfler 			return extent;
337238d7b4bSAxel Dörfler 		}
338238d7b4bSAxel Dörfler 	}
339238d7b4bSAxel Dörfler 
340238d7b4bSAxel Dörfler 	return NULL;
341238d7b4bSAxel Dörfler }
342238d7b4bSAxel Dörfler 
343238d7b4bSAxel Dörfler 
344238d7b4bSAxel Dörfler static status_t
get_file_map(file_cache_ref * ref,off_t offset,size_t size,file_io_vec * vecs,size_t * _count)345238d7b4bSAxel Dörfler get_file_map(file_cache_ref *ref, off_t offset, size_t size,
346238d7b4bSAxel Dörfler 	file_io_vec *vecs, size_t *_count)
347238d7b4bSAxel Dörfler {
348238d7b4bSAxel Dörfler 	size_t maxVecs = *_count;
349238d7b4bSAxel Dörfler 	status_t status = B_OK;
350238d7b4bSAxel Dörfler 
351238d7b4bSAxel Dörfler 	if (ref->map.count == 0) {
352238d7b4bSAxel Dörfler 		// we don't yet have the map of this file, so let's grab it
353238d7b4bSAxel Dörfler 		// (ordered by offset, so that we can do a binary search on them)
354238d7b4bSAxel Dörfler 
355238d7b4bSAxel Dörfler 		//mutex_lock(&ref->cache->lock);
356238d7b4bSAxel Dörfler 
357238d7b4bSAxel Dörfler 		// the file map could have been requested in the mean time
358238d7b4bSAxel Dörfler 		if (ref->map.count == 0) {
359238d7b4bSAxel Dörfler 			size_t vecCount = maxVecs;
360238d7b4bSAxel Dörfler 			off_t mapOffset = 0;
361238d7b4bSAxel Dörfler 
362238d7b4bSAxel Dörfler 			while (true) {
363238d7b4bSAxel Dörfler 				status = vfs_get_file_map(ref->vnode, mapOffset, ~0UL, vecs, &vecCount);
364238d7b4bSAxel Dörfler 				if (status < B_OK && status != B_BUFFER_OVERFLOW) {
365238d7b4bSAxel Dörfler 					//mutex_unlock(&ref->cache->lock);
366238d7b4bSAxel Dörfler 					return status;
367238d7b4bSAxel Dörfler 				}
368238d7b4bSAxel Dörfler 
369238d7b4bSAxel Dörfler 				status_t addStatus = ref->map.Add(vecs, vecCount, mapOffset);
370238d7b4bSAxel Dörfler 				if (addStatus != B_OK) {
371238d7b4bSAxel Dörfler 					// only clobber the status in case of failure
372238d7b4bSAxel Dörfler 					status = addStatus;
373238d7b4bSAxel Dörfler 				}
374238d7b4bSAxel Dörfler 
375238d7b4bSAxel Dörfler 				if (status != B_BUFFER_OVERFLOW)
376238d7b4bSAxel Dörfler 					break;
377238d7b4bSAxel Dörfler 
378238d7b4bSAxel Dörfler 				// when we are here, the map has been stored in the array, and
379238d7b4bSAxel Dörfler 				// the array size was still too small to cover the whole file
380238d7b4bSAxel Dörfler 				vecCount = maxVecs;
381238d7b4bSAxel Dörfler 			}
382238d7b4bSAxel Dörfler 		}
383238d7b4bSAxel Dörfler 
384238d7b4bSAxel Dörfler 		//mutex_unlock(&ref->cache->lock);
385238d7b4bSAxel Dörfler 	}
386238d7b4bSAxel Dörfler 
387238d7b4bSAxel Dörfler 	if (status != B_OK) {
388238d7b4bSAxel Dörfler 		// We must invalidate the (part of the) map we already
389238d7b4bSAxel Dörfler 		// have, as we cannot know if it's complete or not
390238d7b4bSAxel Dörfler 		ref->map.Free();
391238d7b4bSAxel Dörfler 		return status;
392238d7b4bSAxel Dörfler 	}
393238d7b4bSAxel Dörfler 
394238d7b4bSAxel Dörfler 	// We now have cached the map of this file, we now need to
395238d7b4bSAxel Dörfler 	// translate it for the requested access.
396238d7b4bSAxel Dörfler 
397238d7b4bSAxel Dörfler 	uint32 index;
398238d7b4bSAxel Dörfler 	file_extent *fileExtent = find_file_extent(ref, offset, &index);
399238d7b4bSAxel Dörfler 	if (fileExtent == NULL) {
400238d7b4bSAxel Dörfler 		// access outside file bounds? But that's not our problem
401238d7b4bSAxel Dörfler 		*_count = 0;
402238d7b4bSAxel Dörfler 		return B_OK;
403238d7b4bSAxel Dörfler 	}
404238d7b4bSAxel Dörfler 
405238d7b4bSAxel Dörfler 	offset -= fileExtent->offset;
406238d7b4bSAxel Dörfler 	vecs[0].offset = fileExtent->disk.offset + offset;
407238d7b4bSAxel Dörfler 	vecs[0].length = fileExtent->disk.length - offset;
408238d7b4bSAxel Dörfler 
409238d7b4bSAxel Dörfler 	if (vecs[0].length >= size || index >= ref->map.count - 1) {
410238d7b4bSAxel Dörfler 		*_count = 1;
411238d7b4bSAxel Dörfler 		return B_OK;
412238d7b4bSAxel Dörfler 	}
413238d7b4bSAxel Dörfler 
414238d7b4bSAxel Dörfler 	// copy the rest of the vecs
415238d7b4bSAxel Dörfler 
416238d7b4bSAxel Dörfler 	size -= vecs[0].length;
417238d7b4bSAxel Dörfler 
418238d7b4bSAxel Dörfler 	for (index = 1; index < ref->map.count;) {
419238d7b4bSAxel Dörfler 		fileExtent++;
420238d7b4bSAxel Dörfler 
421238d7b4bSAxel Dörfler 		vecs[index] = fileExtent->disk;
422238d7b4bSAxel Dörfler 		index++;
423238d7b4bSAxel Dörfler 
42470a11cecSAxel Dörfler 		if (size <= fileExtent->disk.length)
42570a11cecSAxel Dörfler 			break;
42670a11cecSAxel Dörfler 
427238d7b4bSAxel Dörfler 		if (index >= maxVecs) {
428238d7b4bSAxel Dörfler 			*_count = index;
429238d7b4bSAxel Dörfler 			return B_BUFFER_OVERFLOW;
430238d7b4bSAxel Dörfler 		}
431238d7b4bSAxel Dörfler 
432238d7b4bSAxel Dörfler 		size -= fileExtent->disk.length;
433238d7b4bSAxel Dörfler 	}
434238d7b4bSAxel Dörfler 
435238d7b4bSAxel Dörfler 	*_count = index;
436238d7b4bSAxel Dörfler 	return B_OK;
437238d7b4bSAxel Dörfler }
438238d7b4bSAxel Dörfler 
439238d7b4bSAxel Dörfler 
440238d7b4bSAxel Dörfler /*!
441238d7b4bSAxel Dörfler 	Does the dirty work of translating the request into actual disk offsets
442238d7b4bSAxel Dörfler 	and reads to or writes from the supplied iovecs as specified by \a doWrite.
443238d7b4bSAxel Dörfler */
444238d7b4bSAxel Dörfler static status_t
pages_io(file_cache_ref * ref,off_t offset,const iovec * vecs,size_t count,size_t * _numBytes,bool doWrite)445238d7b4bSAxel Dörfler pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
446238d7b4bSAxel Dörfler 	size_t *_numBytes, bool doWrite)
447238d7b4bSAxel Dörfler {
448*425ac1b6SAlexander von Gluck IV 	TRACE(("pages_io: ref = %p, offset = %lld, size = %lu, vecCount = %lu, %s\n", ref, offset,
449238d7b4bSAxel Dörfler 		*_numBytes, count, doWrite ? "write" : "read"));
450238d7b4bSAxel Dörfler 
451238d7b4bSAxel Dörfler 	// translate the iovecs into direct device accesses
452238d7b4bSAxel Dörfler 	file_io_vec fileVecs[MAX_FILE_IO_VECS];
453238d7b4bSAxel Dörfler 	size_t fileVecCount = MAX_FILE_IO_VECS;
454238d7b4bSAxel Dörfler 	size_t numBytes = *_numBytes;
455238d7b4bSAxel Dörfler 
456238d7b4bSAxel Dörfler 	status_t status = get_file_map(ref, offset, numBytes, fileVecs,
457238d7b4bSAxel Dörfler 		&fileVecCount);
45870a11cecSAxel Dörfler 	if (status < B_OK && status != B_BUFFER_OVERFLOW) {
459*425ac1b6SAlexander von Gluck IV 		TRACE(("get_file_map(offset = %lld, numBytes = %lu) failed: %s\n", offset,
46070a11cecSAxel Dörfler 			numBytes, strerror(status)));
461238d7b4bSAxel Dörfler 		return status;
462238d7b4bSAxel Dörfler 	}
463238d7b4bSAxel Dörfler 
46470a11cecSAxel Dörfler 	bool bufferOverflow = status == B_BUFFER_OVERFLOW;
465238d7b4bSAxel Dörfler 
466238d7b4bSAxel Dörfler #ifdef TRACE_FILE_CACHE
467*425ac1b6SAlexander von Gluck IV 	dprintf("got %lu file vecs for %lld:%lu%s:\n", fileVecCount, offset, numBytes,
46870a11cecSAxel Dörfler 		bufferOverflow ? " (array too small)" : "");
469238d7b4bSAxel Dörfler 	for (size_t i = 0; i < fileVecCount; i++) {
470*425ac1b6SAlexander von Gluck IV 		dprintf("  [%lu] offset = %lld, size = %lld\n",
471238d7b4bSAxel Dörfler 			i, fileVecs[i].offset, fileVecs[i].length);
472238d7b4bSAxel Dörfler 	}
473238d7b4bSAxel Dörfler #endif
474238d7b4bSAxel Dörfler 
475238d7b4bSAxel Dörfler 	if (fileVecCount == 0) {
476238d7b4bSAxel Dörfler 		// There are no file vecs at this offset, so we're obviously trying
477238d7b4bSAxel Dörfler 		// to access the file outside of its bounds
478*425ac1b6SAlexander von Gluck IV 		TRACE(("pages_io: access outside of vnode %p at offset %lld\n",
479238d7b4bSAxel Dörfler 			ref->vnode, offset));
480238d7b4bSAxel Dörfler 		return B_BAD_VALUE;
481238d7b4bSAxel Dörfler 	}
482238d7b4bSAxel Dörfler 
483238d7b4bSAxel Dörfler 	uint32 fileVecIndex;
484238d7b4bSAxel Dörfler 	size_t size;
485238d7b4bSAxel Dörfler 
486238d7b4bSAxel Dörfler 	if (!doWrite) {
487238d7b4bSAxel Dörfler 		// now directly read the data from the device
488238d7b4bSAxel Dörfler 		// the first file_io_vec can be read directly
489238d7b4bSAxel Dörfler 
490238d7b4bSAxel Dörfler 		size = fileVecs[0].length;
491238d7b4bSAxel Dörfler 		if (size > numBytes)
492238d7b4bSAxel Dörfler 			size = numBytes;
493238d7b4bSAxel Dörfler 
494238d7b4bSAxel Dörfler 		status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs,
495238d7b4bSAxel Dörfler 			count, &size, false);
496238d7b4bSAxel Dörfler 		if (status < B_OK)
497238d7b4bSAxel Dörfler 			return status;
498238d7b4bSAxel Dörfler 
499238d7b4bSAxel Dörfler 		// TODO: this is a work-around for buggy device drivers!
500238d7b4bSAxel Dörfler 		//	When our own drivers honour the length, we can:
501238d7b4bSAxel Dörfler 		//	a) also use this direct I/O for writes (otherwise, it would
502238d7b4bSAxel Dörfler 		//	   overwrite precious data)
503238d7b4bSAxel Dörfler 		//	b) panic if the term below is true (at least for writes)
504238d7b4bSAxel Dörfler 		if (size > fileVecs[0].length) {
505238d7b4bSAxel Dörfler 			//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
506238d7b4bSAxel Dörfler 			size = fileVecs[0].length;
507238d7b4bSAxel Dörfler 		}
508238d7b4bSAxel Dörfler 
509df0ca8caSAxel Dörfler 		ASSERT(size <= fileVecs[0].length);
510238d7b4bSAxel Dörfler 
511238d7b4bSAxel Dörfler 		// If the file portion was contiguous, we're already done now
512238d7b4bSAxel Dörfler 		if (size == numBytes)
513238d7b4bSAxel Dörfler 			return B_OK;
514238d7b4bSAxel Dörfler 
515238d7b4bSAxel Dörfler 		// if we reached the end of the file, we can return as well
516238d7b4bSAxel Dörfler 		if (size != fileVecs[0].length) {
517238d7b4bSAxel Dörfler 			*_numBytes = size;
518238d7b4bSAxel Dörfler 			return B_OK;
519238d7b4bSAxel Dörfler 		}
520238d7b4bSAxel Dörfler 
521238d7b4bSAxel Dörfler 		fileVecIndex = 1;
522238d7b4bSAxel Dörfler 	} else {
523238d7b4bSAxel Dörfler 		fileVecIndex = 0;
524238d7b4bSAxel Dörfler 		size = 0;
525238d7b4bSAxel Dörfler 	}
526238d7b4bSAxel Dörfler 
527238d7b4bSAxel Dörfler 	// Too bad, let's process the rest of the file_io_vecs
528238d7b4bSAxel Dörfler 
529238d7b4bSAxel Dörfler 	size_t totalSize = size;
530238d7b4bSAxel Dörfler 
531238d7b4bSAxel Dörfler 	// first, find out where we have to continue in our iovecs
532238d7b4bSAxel Dörfler 	uint32 i = 0;
533238d7b4bSAxel Dörfler 	for (; i < count; i++) {
534238d7b4bSAxel Dörfler 		if (size < vecs[i].iov_len)
535238d7b4bSAxel Dörfler 			break;
536238d7b4bSAxel Dörfler 
537238d7b4bSAxel Dörfler 		size -= vecs[i].iov_len;
538238d7b4bSAxel Dörfler 	}
539238d7b4bSAxel Dörfler 
540238d7b4bSAxel Dörfler 	size_t vecOffset = size;
541238d7b4bSAxel Dörfler 	size_t bytesLeft = numBytes - size;
542238d7b4bSAxel Dörfler 
54370a11cecSAxel Dörfler 	while (true) {
544238d7b4bSAxel Dörfler 		for (; fileVecIndex < fileVecCount; fileVecIndex++) {
545238d7b4bSAxel Dörfler 			file_io_vec &fileVec = fileVecs[fileVecIndex];
546238d7b4bSAxel Dörfler 			off_t fileOffset = fileVec.offset;
54770a11cecSAxel Dörfler 			off_t fileLeft = min_c(fileVec.length, bytesLeft);
548238d7b4bSAxel Dörfler 
549*425ac1b6SAlexander von Gluck IV 			TRACE(("FILE VEC [%lu] length %lld\n", fileVecIndex, fileLeft));
550df0ca8caSAxel Dörfler 
551df0ca8caSAxel Dörfler 			// process the complete fileVec
552238d7b4bSAxel Dörfler 			while (fileLeft > 0) {
553238d7b4bSAxel Dörfler 				iovec tempVecs[MAX_TEMP_IO_VECS];
554df0ca8caSAxel Dörfler 				uint32 tempCount = 0;
555238d7b4bSAxel Dörfler 
556df0ca8caSAxel Dörfler 				// size tracks how much of what is left of the current fileVec
557df0ca8caSAxel Dörfler 				// (fileLeft) has been assigned to tempVecs
558df0ca8caSAxel Dörfler 				size = 0;
559238d7b4bSAxel Dörfler 
560df0ca8caSAxel Dörfler 				// assign what is left of the current fileVec to the tempVecs
561df0ca8caSAxel Dörfler 				for (size = 0; size < fileLeft && i < count
562df0ca8caSAxel Dörfler 						&& tempCount < MAX_TEMP_IO_VECS;) {
563df0ca8caSAxel Dörfler 					// try to satisfy one iovec per iteration (or as much as
564df0ca8caSAxel Dörfler 					// possible)
565238d7b4bSAxel Dörfler 
566df0ca8caSAxel Dörfler 					// bytes left of the current iovec
567df0ca8caSAxel Dörfler 					size_t vecLeft = vecs[i].iov_len - vecOffset;
568df0ca8caSAxel Dörfler 					if (vecLeft == 0) {
569238d7b4bSAxel Dörfler 						vecOffset = 0;
570df0ca8caSAxel Dörfler 						i++;
571df0ca8caSAxel Dörfler 						continue;
572238d7b4bSAxel Dörfler 					}
573238d7b4bSAxel Dörfler 
57470a11cecSAxel Dörfler 					TRACE(("fill vec %ld, offset = %lu, size = %lu\n",
57570a11cecSAxel Dörfler 						i, vecOffset, size));
57670a11cecSAxel Dörfler 
577df0ca8caSAxel Dörfler 					// actually available bytes
578df0ca8caSAxel Dörfler 					size_t tempVecSize = min_c(vecLeft, fileLeft - size);
579df0ca8caSAxel Dörfler 
580df0ca8caSAxel Dörfler 					tempVecs[tempCount].iov_base
581df0ca8caSAxel Dörfler 						= (void *)((addr_t)vecs[i].iov_base + vecOffset);
582df0ca8caSAxel Dörfler 					tempVecs[tempCount].iov_len = tempVecSize;
583238d7b4bSAxel Dörfler 					tempCount++;
584df0ca8caSAxel Dörfler 
585df0ca8caSAxel Dörfler 					size += tempVecSize;
586df0ca8caSAxel Dörfler 					vecOffset += tempVecSize;
587238d7b4bSAxel Dörfler 				}
588238d7b4bSAxel Dörfler 
589238d7b4bSAxel Dörfler 				size_t bytes = size;
590238d7b4bSAxel Dörfler 				if (doWrite) {
59170a11cecSAxel Dörfler 					status = vfs_write_pages(ref->device, ref->cookie,
59270a11cecSAxel Dörfler 						fileOffset, tempVecs, tempCount, &bytes, false);
593238d7b4bSAxel Dörfler 				} else {
59470a11cecSAxel Dörfler 					status = vfs_read_pages(ref->device, ref->cookie,
59570a11cecSAxel Dörfler 						fileOffset, tempVecs, tempCount, &bytes, false);
596238d7b4bSAxel Dörfler 				}
597238d7b4bSAxel Dörfler 				if (status < B_OK)
598238d7b4bSAxel Dörfler 					return status;
599238d7b4bSAxel Dörfler 
600df0ca8caSAxel Dörfler 				totalSize += bytes;
601238d7b4bSAxel Dörfler 				bytesLeft -= size;
602238d7b4bSAxel Dörfler 				fileOffset += size;
603238d7b4bSAxel Dörfler 				fileLeft -= size;
604df0ca8caSAxel Dörfler 				//dprintf("-> file left = %Lu\n", fileLeft);
605238d7b4bSAxel Dörfler 
606df0ca8caSAxel Dörfler 				if (size != bytes || i >= count) {
607df0ca8caSAxel Dörfler 					// there are no more bytes or iovecs, let's bail out
608238d7b4bSAxel Dörfler 					*_numBytes = totalSize;
609238d7b4bSAxel Dörfler 					return B_OK;
610238d7b4bSAxel Dörfler 				}
611238d7b4bSAxel Dörfler 			}
612238d7b4bSAxel Dörfler 		}
613238d7b4bSAxel Dörfler 
61470a11cecSAxel Dörfler 		if (bufferOverflow) {
61570a11cecSAxel Dörfler 			status = get_file_map(ref, offset + totalSize, bytesLeft, fileVecs,
61670a11cecSAxel Dörfler 				&fileVecCount);
61770a11cecSAxel Dörfler 			if (status < B_OK && status != B_BUFFER_OVERFLOW) {
618*425ac1b6SAlexander von Gluck IV 				TRACE(("get_file_map(offset = %lld, numBytes = %lu) failed: %s\n",
61970a11cecSAxel Dörfler 					offset, numBytes, strerror(status)));
62070a11cecSAxel Dörfler 				return status;
62170a11cecSAxel Dörfler 			}
62270a11cecSAxel Dörfler 
62370a11cecSAxel Dörfler 			bufferOverflow = status == B_BUFFER_OVERFLOW;
62470a11cecSAxel Dörfler 			fileVecIndex = 0;
62570a11cecSAxel Dörfler 
62670a11cecSAxel Dörfler #ifdef TRACE_FILE_CACHE
627*425ac1b6SAlexander von Gluck IV 			dprintf("got %lu file vecs for %lld:%lu%s:\n", fileVecCount,
62870a11cecSAxel Dörfler 				offset + totalSize, numBytes,
62970a11cecSAxel Dörfler 				bufferOverflow ? " (array too small)" : "");
63070a11cecSAxel Dörfler 			for (size_t i = 0; i < fileVecCount; i++) {
631*425ac1b6SAlexander von Gluck IV 				dprintf("  [%lu] offset = %lld, size = %lld\n",
63270a11cecSAxel Dörfler 					i, fileVecs[i].offset, fileVecs[i].length);
63370a11cecSAxel Dörfler 			}
63470a11cecSAxel Dörfler #endif
63570a11cecSAxel Dörfler 		} else
63670a11cecSAxel Dörfler 			break;
63770a11cecSAxel Dörfler 	}
63870a11cecSAxel Dörfler 
639df0ca8caSAxel Dörfler 	*_numBytes = totalSize;
640238d7b4bSAxel Dörfler 	return B_OK;
641238d7b4bSAxel Dörfler }
642238d7b4bSAxel Dörfler 
643238d7b4bSAxel Dörfler 
644238d7b4bSAxel Dörfler //	#pragma mark -
645238d7b4bSAxel Dörfler 
646238d7b4bSAxel Dörfler 
647238d7b4bSAxel Dörfler int
main(int argc,char ** argv)648238d7b4bSAxel Dörfler main(int argc, char **argv)
649238d7b4bSAxel Dörfler {
650238d7b4bSAxel Dörfler 	file_cache_ref ref;
651238d7b4bSAxel Dörfler 	iovec vecs[MAX_IO_VECS];
652238d7b4bSAxel Dörfler 	size_t count = 1;
653238d7b4bSAxel Dörfler 	size_t numBytes = 10000;
654238d7b4bSAxel Dörfler 	off_t offset = 4999;
655238d7b4bSAxel Dörfler 
65670a11cecSAxel Dörfler 	set_vecs(vecs, &count, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
65770a11cecSAxel Dörfler 		16, 4096, 8192, 16384, 4096, 4096, -1);
65870a11cecSAxel Dörfler 	set_file_map(0, 2000, 5000, 3000, 10000, 800, 11000, 20, 12000, 30,
65970a11cecSAxel Dörfler 		13000, 70, 14000, 100, 15000, 900, 20000, 30000, -1);
660238d7b4bSAxel Dörfler 
66170a11cecSAxel Dörfler 	status_t status = pages_io(&ref, offset, vecs, count, &numBytes, false);
66270a11cecSAxel Dörfler 	if (status < B_OK)
66370a11cecSAxel Dörfler 		fprintf(stderr, "pages_io() returned: %s\n", strerror(status));
664238d7b4bSAxel Dörfler 
665238d7b4bSAxel Dörfler 	return 0;
666238d7b4bSAxel Dörfler }
667238d7b4bSAxel Dörfler 
668