xref: /haiku/src/tests/system/kernel/cache/pages_io_test.cpp (revision 238d7b4ba7f851d052ab213bc0ce571e0fdd8e53)
1*238d7b4bSAxel Dörfler #include <OS.h>
2*238d7b4bSAxel Dörfler #include <fs_interface.h>
3*238d7b4bSAxel Dörfler 
4*238d7b4bSAxel Dörfler #include <stdarg.h>
5*238d7b4bSAxel Dörfler #include <stdio.h>
6*238d7b4bSAxel Dörfler #include <stdlib.h>
7*238d7b4bSAxel Dörfler #include <sys/uio.h>
8*238d7b4bSAxel Dörfler 
9*238d7b4bSAxel Dörfler #define TRACE_FILE_CACHE
10*238d7b4bSAxel Dörfler #define TRACE(x) printf x
11*238d7b4bSAxel Dörfler #define dprintf printf
12*238d7b4bSAxel Dörfler 
13*238d7b4bSAxel Dörfler // maximum number of iovecs per request
14*238d7b4bSAxel Dörfler #define MAX_IO_VECS			64	// 256 kB
15*238d7b4bSAxel Dörfler #define MAX_FILE_IO_VECS	32
16*238d7b4bSAxel Dörfler #define MAX_TEMP_IO_VECS	8
17*238d7b4bSAxel Dörfler 
18*238d7b4bSAxel Dörfler #define CACHED_FILE_EXTENTS	2
19*238d7b4bSAxel Dörfler 	// must be smaller than MAX_FILE_IO_VECS
20*238d7b4bSAxel Dörfler 	// ToDo: find out how much of these are typically used
21*238d7b4bSAxel Dörfler 
22*238d7b4bSAxel Dörfler struct vm_cache_ref;
23*238d7b4bSAxel Dörfler 
24*238d7b4bSAxel Dörfler struct file_extent {
25*238d7b4bSAxel Dörfler 	off_t			offset;
26*238d7b4bSAxel Dörfler 	file_io_vec		disk;
27*238d7b4bSAxel Dörfler };
28*238d7b4bSAxel Dörfler 
29*238d7b4bSAxel Dörfler struct file_map {
30*238d7b4bSAxel Dörfler 	file_map();
31*238d7b4bSAxel Dörfler 	~file_map();
32*238d7b4bSAxel Dörfler 
33*238d7b4bSAxel Dörfler 	file_extent *operator[](uint32 index);
34*238d7b4bSAxel Dörfler 	file_extent *ExtentAt(uint32 index);
35*238d7b4bSAxel Dörfler 	status_t Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset);
36*238d7b4bSAxel Dörfler 	void Free();
37*238d7b4bSAxel Dörfler 
38*238d7b4bSAxel Dörfler 	union {
39*238d7b4bSAxel Dörfler 		file_extent	direct[CACHED_FILE_EXTENTS];
40*238d7b4bSAxel Dörfler 		file_extent	*array;
41*238d7b4bSAxel Dörfler 	};
42*238d7b4bSAxel Dörfler 	size_t			count;
43*238d7b4bSAxel Dörfler };
44*238d7b4bSAxel Dörfler 
45*238d7b4bSAxel Dörfler struct file_cache_ref {
46*238d7b4bSAxel Dörfler 	vm_cache_ref	*cache;
47*238d7b4bSAxel Dörfler 	void			*vnode;
48*238d7b4bSAxel Dörfler 	void			*device;
49*238d7b4bSAxel Dörfler 	void			*cookie;
50*238d7b4bSAxel Dörfler 	file_map		map;
51*238d7b4bSAxel Dörfler };
52*238d7b4bSAxel Dörfler 
53*238d7b4bSAxel Dörfler 
54*238d7b4bSAxel Dörfler file_io_vec gFileVecs[MAX_FILE_IO_VECS];
55*238d7b4bSAxel Dörfler size_t gFileVecCount;
56*238d7b4bSAxel Dörfler off_t gFileSize;
57*238d7b4bSAxel Dörfler 
58*238d7b4bSAxel Dörfler 
59*238d7b4bSAxel Dörfler file_map::file_map()
60*238d7b4bSAxel Dörfler {
61*238d7b4bSAxel Dörfler 	array = NULL;
62*238d7b4bSAxel Dörfler 	count = 0;
63*238d7b4bSAxel Dörfler }
64*238d7b4bSAxel Dörfler 
65*238d7b4bSAxel Dörfler 
66*238d7b4bSAxel Dörfler file_map::~file_map()
67*238d7b4bSAxel Dörfler {
68*238d7b4bSAxel Dörfler 	Free();
69*238d7b4bSAxel Dörfler }
70*238d7b4bSAxel Dörfler 
71*238d7b4bSAxel Dörfler 
72*238d7b4bSAxel Dörfler file_extent *
73*238d7b4bSAxel Dörfler file_map::operator[](uint32 index)
74*238d7b4bSAxel Dörfler {
75*238d7b4bSAxel Dörfler 	return ExtentAt(index);
76*238d7b4bSAxel Dörfler }
77*238d7b4bSAxel Dörfler 
78*238d7b4bSAxel Dörfler 
79*238d7b4bSAxel Dörfler file_extent *
80*238d7b4bSAxel Dörfler file_map::ExtentAt(uint32 index)
81*238d7b4bSAxel Dörfler {
82*238d7b4bSAxel Dörfler 	if (index >= count)
83*238d7b4bSAxel Dörfler 		return NULL;
84*238d7b4bSAxel Dörfler 
85*238d7b4bSAxel Dörfler 	if (count > CACHED_FILE_EXTENTS)
86*238d7b4bSAxel Dörfler 		return &array[index];
87*238d7b4bSAxel Dörfler 
88*238d7b4bSAxel Dörfler 	return &direct[index];
89*238d7b4bSAxel Dörfler }
90*238d7b4bSAxel Dörfler 
91*238d7b4bSAxel Dörfler 
92*238d7b4bSAxel Dörfler status_t
93*238d7b4bSAxel Dörfler file_map::Add(file_io_vec *vecs, size_t vecCount, off_t &lastOffset)
94*238d7b4bSAxel Dörfler {
95*238d7b4bSAxel Dörfler 	TRACE(("file_map::Add(vecCount = %ld)\n", vecCount));
96*238d7b4bSAxel Dörfler 
97*238d7b4bSAxel Dörfler 	off_t offset = 0;
98*238d7b4bSAxel Dörfler 
99*238d7b4bSAxel Dörfler 	if (vecCount <= CACHED_FILE_EXTENTS && count == 0) {
100*238d7b4bSAxel Dörfler 		// just use the reserved area in the file_cache_ref structure
101*238d7b4bSAxel Dörfler 	} else {
102*238d7b4bSAxel Dörfler 		// TODO: once we can invalidate only parts of the file map,
103*238d7b4bSAxel Dörfler 		//	we might need to copy the previously cached file extends
104*238d7b4bSAxel Dörfler 		//	from the direct range
105*238d7b4bSAxel Dörfler 		file_extent *newMap = (file_extent *)realloc(array,
106*238d7b4bSAxel Dörfler 			(count + vecCount) * sizeof(file_extent));
107*238d7b4bSAxel Dörfler 		if (newMap == NULL)
108*238d7b4bSAxel Dörfler 			return B_NO_MEMORY;
109*238d7b4bSAxel Dörfler 
110*238d7b4bSAxel Dörfler 		array = newMap;
111*238d7b4bSAxel Dörfler 
112*238d7b4bSAxel Dörfler 		if (count != 0) {
113*238d7b4bSAxel Dörfler 			file_extent *extent = ExtentAt(count - 1);
114*238d7b4bSAxel Dörfler 			offset = extent->offset + extent->disk.length;
115*238d7b4bSAxel Dörfler 		}
116*238d7b4bSAxel Dörfler 	}
117*238d7b4bSAxel Dörfler 
118*238d7b4bSAxel Dörfler 	int32 start = count;
119*238d7b4bSAxel Dörfler 	count += vecCount;
120*238d7b4bSAxel Dörfler 
121*238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < vecCount; i++) {
122*238d7b4bSAxel Dörfler 		file_extent *extent = ExtentAt(start + i);
123*238d7b4bSAxel Dörfler 
124*238d7b4bSAxel Dörfler 		extent->offset = offset;
125*238d7b4bSAxel Dörfler 		extent->disk = vecs[i];
126*238d7b4bSAxel Dörfler 
127*238d7b4bSAxel Dörfler 		offset += extent->disk.length;
128*238d7b4bSAxel Dörfler 	}
129*238d7b4bSAxel Dörfler 
130*238d7b4bSAxel Dörfler #ifdef TRACE_FILE_CACHE
131*238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
132*238d7b4bSAxel Dörfler 		file_extent *extent = ExtentAt(i);
133*238d7b4bSAxel Dörfler 		dprintf("  [%ld] extend offset %Ld, disk offset %Ld, length %Ld\n",
134*238d7b4bSAxel Dörfler 			i, extent->offset, extent->disk.offset, extent->disk.length);
135*238d7b4bSAxel Dörfler 	}
136*238d7b4bSAxel Dörfler #endif
137*238d7b4bSAxel Dörfler 
138*238d7b4bSAxel Dörfler 	lastOffset = offset;
139*238d7b4bSAxel Dörfler 	return B_OK;
140*238d7b4bSAxel Dörfler }
141*238d7b4bSAxel Dörfler 
142*238d7b4bSAxel Dörfler 
143*238d7b4bSAxel Dörfler void
144*238d7b4bSAxel Dörfler file_map::Free()
145*238d7b4bSAxel Dörfler {
146*238d7b4bSAxel Dörfler 	if (count > CACHED_FILE_EXTENTS)
147*238d7b4bSAxel Dörfler 		free(array);
148*238d7b4bSAxel Dörfler 
149*238d7b4bSAxel Dörfler 	array = NULL;
150*238d7b4bSAxel Dörfler 	count = 0;
151*238d7b4bSAxel Dörfler }
152*238d7b4bSAxel Dörfler 
153*238d7b4bSAxel Dörfler 
154*238d7b4bSAxel Dörfler //	#pragma mark -
155*238d7b4bSAxel Dörfler 
156*238d7b4bSAxel Dörfler 
157*238d7b4bSAxel Dörfler void
158*238d7b4bSAxel Dörfler set_vecs(iovec *vecs, size_t *_count, ...)
159*238d7b4bSAxel Dörfler {
160*238d7b4bSAxel Dörfler 	uint32 base = 0;
161*238d7b4bSAxel Dörfler 	size_t count = 0;
162*238d7b4bSAxel Dörfler 
163*238d7b4bSAxel Dörfler 	va_list args;
164*238d7b4bSAxel Dörfler 	va_start(args, _count);
165*238d7b4bSAxel Dörfler 
166*238d7b4bSAxel Dörfler 	while (count < MAX_IO_VECS) {
167*238d7b4bSAxel Dörfler 		int32 length = va_arg(args, int32);
168*238d7b4bSAxel Dörfler 		if (length < 0)
169*238d7b4bSAxel Dörfler 			break;
170*238d7b4bSAxel Dörfler 
171*238d7b4bSAxel Dörfler 		vecs[count].iov_base = (void *)base;
172*238d7b4bSAxel Dörfler 		vecs[count].iov_len = length;
173*238d7b4bSAxel Dörfler 
174*238d7b4bSAxel Dörfler 		base += length;
175*238d7b4bSAxel Dörfler 		count++;
176*238d7b4bSAxel Dörfler 	}
177*238d7b4bSAxel Dörfler 
178*238d7b4bSAxel Dörfler 	va_end(args);
179*238d7b4bSAxel Dörfler 	*_count = count;
180*238d7b4bSAxel Dörfler }
181*238d7b4bSAxel Dörfler 
182*238d7b4bSAxel Dörfler 
183*238d7b4bSAxel Dörfler void
184*238d7b4bSAxel Dörfler set_file_map(int32 base, int32 length, ...)
185*238d7b4bSAxel Dörfler {
186*238d7b4bSAxel Dörfler 	gFileVecs[0].offset = base;
187*238d7b4bSAxel Dörfler 	gFileVecs[0].length = length;
188*238d7b4bSAxel Dörfler 
189*238d7b4bSAxel Dörfler 	gFileSize = length;
190*238d7b4bSAxel Dörfler 	gFileVecCount = 1;
191*238d7b4bSAxel Dörfler 
192*238d7b4bSAxel Dörfler 	va_list args;
193*238d7b4bSAxel Dörfler 	va_start(args, length);
194*238d7b4bSAxel Dörfler 
195*238d7b4bSAxel Dörfler 	while (gFileVecCount < MAX_FILE_IO_VECS) {
196*238d7b4bSAxel Dörfler 		off_t offset = va_arg(args, int32);
197*238d7b4bSAxel Dörfler 		if (offset < 0)
198*238d7b4bSAxel Dörfler 			break;
199*238d7b4bSAxel Dörfler 
200*238d7b4bSAxel Dörfler 		length = va_arg(args, int32);
201*238d7b4bSAxel Dörfler 
202*238d7b4bSAxel Dörfler 		gFileVecs[gFileVecCount].offset = offset;
203*238d7b4bSAxel Dörfler 		gFileVecs[gFileVecCount].length = length;
204*238d7b4bSAxel Dörfler 
205*238d7b4bSAxel Dörfler 		gFileSize += length;
206*238d7b4bSAxel Dörfler 		gFileVecCount++;
207*238d7b4bSAxel Dörfler 	}
208*238d7b4bSAxel Dörfler 
209*238d7b4bSAxel Dörfler 	va_end(args);
210*238d7b4bSAxel Dörfler }
211*238d7b4bSAxel Dörfler 
212*238d7b4bSAxel Dörfler 
213*238d7b4bSAxel Dörfler status_t
214*238d7b4bSAxel Dörfler find_map_base(off_t offset, off_t &diskOffset, off_t &diskLength,
215*238d7b4bSAxel Dörfler 	off_t &fileOffset)
216*238d7b4bSAxel Dörfler {
217*238d7b4bSAxel Dörfler 	fileOffset = 0;
218*238d7b4bSAxel Dörfler 
219*238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < gFileVecCount; i++) {
220*238d7b4bSAxel Dörfler 		if (offset < gFileVecs[i].length) {
221*238d7b4bSAxel Dörfler 			diskOffset = gFileVecs[i].offset;
222*238d7b4bSAxel Dörfler 			diskLength = gFileVecs[i].length;
223*238d7b4bSAxel Dörfler 			return B_OK;
224*238d7b4bSAxel Dörfler 		}
225*238d7b4bSAxel Dörfler 
226*238d7b4bSAxel Dörfler 		fileOffset += gFileVecs[i].length;
227*238d7b4bSAxel Dörfler 		offset -= gFileVecs[i].length;
228*238d7b4bSAxel Dörfler 	}
229*238d7b4bSAxel Dörfler 
230*238d7b4bSAxel Dörfler 	return B_ENTRY_NOT_FOUND;
231*238d7b4bSAxel Dörfler }
232*238d7b4bSAxel Dörfler 
233*238d7b4bSAxel Dörfler 
234*238d7b4bSAxel Dörfler //	#pragma mark - VFS functions
235*238d7b4bSAxel Dörfler 
236*238d7b4bSAxel Dörfler 
237*238d7b4bSAxel Dörfler static status_t
238*238d7b4bSAxel Dörfler vfs_get_file_map(void *vnode, off_t offset, size_t size, file_io_vec *vecs,
239*238d7b4bSAxel Dörfler 	size_t *_count)
240*238d7b4bSAxel Dörfler {
241*238d7b4bSAxel Dörfler 	off_t diskOffset, diskLength, fileOffset;
242*238d7b4bSAxel Dörfler 	size_t max = *_count;
243*238d7b4bSAxel Dörfler 	uint32 index = 0;
244*238d7b4bSAxel Dörfler 
245*238d7b4bSAxel Dörfler 	while (true) {
246*238d7b4bSAxel Dörfler 		status_t status = find_map_base(offset, diskOffset, diskLength, fileOffset);
247*238d7b4bSAxel Dörfler 		//status_t status = inode->FindBlockRun(offset, run, fileOffset);
248*238d7b4bSAxel Dörfler 		if (status != B_OK)
249*238d7b4bSAxel Dörfler 			return status;
250*238d7b4bSAxel Dörfler 
251*238d7b4bSAxel Dörfler 		vecs[index].offset = diskOffset + offset - fileOffset;
252*238d7b4bSAxel Dörfler 		vecs[index].length = diskLength - offset + fileOffset;
253*238d7b4bSAxel Dörfler 		offset += vecs[index].length;
254*238d7b4bSAxel Dörfler 
255*238d7b4bSAxel Dörfler 		// are we already done?
256*238d7b4bSAxel Dörfler 		if (size <= vecs[index].length
257*238d7b4bSAxel Dörfler 			|| offset >= gFileSize) {
258*238d7b4bSAxel Dörfler 			if (offset > gFileSize) {
259*238d7b4bSAxel Dörfler 				// make sure the extent ends with the last official file
260*238d7b4bSAxel Dörfler 				// block (without taking any preallocations into account)
261*238d7b4bSAxel Dörfler 				vecs[index].length = gFileSize - fileOffset;
262*238d7b4bSAxel Dörfler 			}
263*238d7b4bSAxel Dörfler 			*_count = index + 1;
264*238d7b4bSAxel Dörfler 			return B_OK;
265*238d7b4bSAxel Dörfler 		}
266*238d7b4bSAxel Dörfler 
267*238d7b4bSAxel Dörfler 		size -= vecs[index].length;
268*238d7b4bSAxel Dörfler 		index++;
269*238d7b4bSAxel Dörfler 
270*238d7b4bSAxel Dörfler 		if (index >= max) {
271*238d7b4bSAxel Dörfler 			// we're out of file_io_vecs; let's bail out
272*238d7b4bSAxel Dörfler 			*_count = index;
273*238d7b4bSAxel Dörfler 			return B_BUFFER_OVERFLOW;
274*238d7b4bSAxel Dörfler 		}
275*238d7b4bSAxel Dörfler 	}
276*238d7b4bSAxel Dörfler }
277*238d7b4bSAxel Dörfler 
278*238d7b4bSAxel Dörfler 
279*238d7b4bSAxel Dörfler static status_t
280*238d7b4bSAxel Dörfler vfs_read_pages(void *device, void *cookie, off_t offset,
281*238d7b4bSAxel Dörfler 	const iovec *vecs, size_t count, size_t *bytes, bool kernel)
282*238d7b4bSAxel Dörfler {
283*238d7b4bSAxel Dörfler 	printf("read offset %Ld, length %lu\n", offset, *bytes);
284*238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
285*238d7b4bSAxel Dörfler 		printf("  [%lu] base %lu, length %lu\n",
286*238d7b4bSAxel Dörfler 			i, (uint32)vecs[i].iov_base, vecs[i].iov_len);
287*238d7b4bSAxel Dörfler 	}
288*238d7b4bSAxel Dörfler 	return B_OK;
289*238d7b4bSAxel Dörfler }
290*238d7b4bSAxel Dörfler 
291*238d7b4bSAxel Dörfler 
292*238d7b4bSAxel Dörfler static status_t
293*238d7b4bSAxel Dörfler vfs_write_pages(void *device, void *cookie, off_t offset,
294*238d7b4bSAxel Dörfler 	const iovec *vecs, size_t count, size_t *bytes, bool kernel)
295*238d7b4bSAxel Dörfler {
296*238d7b4bSAxel Dörfler 	printf("write offset %Ld, length %lu\n", offset, *bytes);
297*238d7b4bSAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
298*238d7b4bSAxel Dörfler 		printf("  [%lu] base %lu, length %lu\n",
299*238d7b4bSAxel Dörfler 			i, (uint32)vecs[i].iov_base, vecs[i].iov_len);
300*238d7b4bSAxel Dörfler 	}
301*238d7b4bSAxel Dörfler 	return B_OK;
302*238d7b4bSAxel Dörfler }
303*238d7b4bSAxel Dörfler 
304*238d7b4bSAxel Dörfler 
305*238d7b4bSAxel Dörfler //	#pragma mark - file_cache.cpp copies
306*238d7b4bSAxel Dörfler 
307*238d7b4bSAxel Dörfler 
308*238d7b4bSAxel Dörfler static file_extent *
309*238d7b4bSAxel Dörfler find_file_extent(file_cache_ref *ref, off_t offset, uint32 *_index)
310*238d7b4bSAxel Dörfler {
311*238d7b4bSAxel Dörfler 	// TODO: do binary search
312*238d7b4bSAxel Dörfler 
313*238d7b4bSAxel Dörfler 	for (uint32 index = 0; index < ref->map.count; index++) {
314*238d7b4bSAxel Dörfler 		file_extent *extent = ref->map[index];
315*238d7b4bSAxel Dörfler 
316*238d7b4bSAxel Dörfler 		if (extent->offset <= offset
317*238d7b4bSAxel Dörfler 			&& extent->offset + extent->disk.length > offset) {
318*238d7b4bSAxel Dörfler 			if (_index)
319*238d7b4bSAxel Dörfler 				*_index = index;
320*238d7b4bSAxel Dörfler 			return extent;
321*238d7b4bSAxel Dörfler 		}
322*238d7b4bSAxel Dörfler 	}
323*238d7b4bSAxel Dörfler 
324*238d7b4bSAxel Dörfler 	return NULL;
325*238d7b4bSAxel Dörfler }
326*238d7b4bSAxel Dörfler 
327*238d7b4bSAxel Dörfler 
328*238d7b4bSAxel Dörfler static status_t
329*238d7b4bSAxel Dörfler get_file_map(file_cache_ref *ref, off_t offset, size_t size,
330*238d7b4bSAxel Dörfler 	file_io_vec *vecs, size_t *_count)
331*238d7b4bSAxel Dörfler {
332*238d7b4bSAxel Dörfler 	size_t maxVecs = *_count;
333*238d7b4bSAxel Dörfler 	status_t status = B_OK;
334*238d7b4bSAxel Dörfler 
335*238d7b4bSAxel Dörfler 	if (ref->map.count == 0) {
336*238d7b4bSAxel Dörfler 		// we don't yet have the map of this file, so let's grab it
337*238d7b4bSAxel Dörfler 		// (ordered by offset, so that we can do a binary search on them)
338*238d7b4bSAxel Dörfler 
339*238d7b4bSAxel Dörfler 		//mutex_lock(&ref->cache->lock);
340*238d7b4bSAxel Dörfler 
341*238d7b4bSAxel Dörfler 		// the file map could have been requested in the mean time
342*238d7b4bSAxel Dörfler 		if (ref->map.count == 0) {
343*238d7b4bSAxel Dörfler 			size_t vecCount = maxVecs;
344*238d7b4bSAxel Dörfler 			off_t mapOffset = 0;
345*238d7b4bSAxel Dörfler 
346*238d7b4bSAxel Dörfler 			while (true) {
347*238d7b4bSAxel Dörfler 				status = vfs_get_file_map(ref->vnode, mapOffset, ~0UL, vecs, &vecCount);
348*238d7b4bSAxel Dörfler 				if (status < B_OK && status != B_BUFFER_OVERFLOW) {
349*238d7b4bSAxel Dörfler 					//mutex_unlock(&ref->cache->lock);
350*238d7b4bSAxel Dörfler 					return status;
351*238d7b4bSAxel Dörfler 				}
352*238d7b4bSAxel Dörfler 
353*238d7b4bSAxel Dörfler 				status_t addStatus = ref->map.Add(vecs, vecCount, mapOffset);
354*238d7b4bSAxel Dörfler 				if (addStatus != B_OK) {
355*238d7b4bSAxel Dörfler 					// only clobber the status in case of failure
356*238d7b4bSAxel Dörfler 					status = addStatus;
357*238d7b4bSAxel Dörfler 				}
358*238d7b4bSAxel Dörfler 
359*238d7b4bSAxel Dörfler 				if (status != B_BUFFER_OVERFLOW)
360*238d7b4bSAxel Dörfler 					break;
361*238d7b4bSAxel Dörfler 
362*238d7b4bSAxel Dörfler 				// when we are here, the map has been stored in the array, and
363*238d7b4bSAxel Dörfler 				// the array size was still too small to cover the whole file
364*238d7b4bSAxel Dörfler 				vecCount = maxVecs;
365*238d7b4bSAxel Dörfler 			}
366*238d7b4bSAxel Dörfler 		}
367*238d7b4bSAxel Dörfler 
368*238d7b4bSAxel Dörfler 		//mutex_unlock(&ref->cache->lock);
369*238d7b4bSAxel Dörfler 	}
370*238d7b4bSAxel Dörfler 
371*238d7b4bSAxel Dörfler 	if (status != B_OK) {
372*238d7b4bSAxel Dörfler 		// We must invalidate the (part of the) map we already
373*238d7b4bSAxel Dörfler 		// have, as we cannot know if it's complete or not
374*238d7b4bSAxel Dörfler 		ref->map.Free();
375*238d7b4bSAxel Dörfler 		return status;
376*238d7b4bSAxel Dörfler 	}
377*238d7b4bSAxel Dörfler 
378*238d7b4bSAxel Dörfler 	// We now have cached the map of this file, we now need to
379*238d7b4bSAxel Dörfler 	// translate it for the requested access.
380*238d7b4bSAxel Dörfler 
381*238d7b4bSAxel Dörfler 	uint32 index;
382*238d7b4bSAxel Dörfler 	file_extent *fileExtent = find_file_extent(ref, offset, &index);
383*238d7b4bSAxel Dörfler 	if (fileExtent == NULL) {
384*238d7b4bSAxel Dörfler 		// access outside file bounds? But that's not our problem
385*238d7b4bSAxel Dörfler 		*_count = 0;
386*238d7b4bSAxel Dörfler 		return B_OK;
387*238d7b4bSAxel Dörfler 	}
388*238d7b4bSAxel Dörfler 
389*238d7b4bSAxel Dörfler 	offset -= fileExtent->offset;
390*238d7b4bSAxel Dörfler 	vecs[0].offset = fileExtent->disk.offset + offset;
391*238d7b4bSAxel Dörfler 	vecs[0].length = fileExtent->disk.length - offset;
392*238d7b4bSAxel Dörfler 
393*238d7b4bSAxel Dörfler 	if (vecs[0].length >= size || index >= ref->map.count - 1) {
394*238d7b4bSAxel Dörfler 		*_count = 1;
395*238d7b4bSAxel Dörfler 		return B_OK;
396*238d7b4bSAxel Dörfler 	}
397*238d7b4bSAxel Dörfler 
398*238d7b4bSAxel Dörfler 	// copy the rest of the vecs
399*238d7b4bSAxel Dörfler 
400*238d7b4bSAxel Dörfler 	size -= vecs[0].length;
401*238d7b4bSAxel Dörfler 
402*238d7b4bSAxel Dörfler 	for (index = 1; index < ref->map.count;) {
403*238d7b4bSAxel Dörfler 		fileExtent++;
404*238d7b4bSAxel Dörfler 
405*238d7b4bSAxel Dörfler 		vecs[index] = fileExtent->disk;
406*238d7b4bSAxel Dörfler 		index++;
407*238d7b4bSAxel Dörfler 
408*238d7b4bSAxel Dörfler 		if (index >= maxVecs) {
409*238d7b4bSAxel Dörfler 			*_count = index;
410*238d7b4bSAxel Dörfler 			return B_BUFFER_OVERFLOW;
411*238d7b4bSAxel Dörfler 		}
412*238d7b4bSAxel Dörfler 
413*238d7b4bSAxel Dörfler 		if (size <= fileExtent->disk.length)
414*238d7b4bSAxel Dörfler 			break;
415*238d7b4bSAxel Dörfler 
416*238d7b4bSAxel Dörfler 		size -= fileExtent->disk.length;
417*238d7b4bSAxel Dörfler 	}
418*238d7b4bSAxel Dörfler 
419*238d7b4bSAxel Dörfler 	*_count = index;
420*238d7b4bSAxel Dörfler 	return B_OK;
421*238d7b4bSAxel Dörfler }
422*238d7b4bSAxel Dörfler 
423*238d7b4bSAxel Dörfler 
424*238d7b4bSAxel Dörfler /*!
425*238d7b4bSAxel Dörfler 	Does the dirty work of translating the request into actual disk offsets
426*238d7b4bSAxel Dörfler 	and reads to or writes from the supplied iovecs as specified by \a doWrite.
427*238d7b4bSAxel Dörfler */
428*238d7b4bSAxel Dörfler static status_t
429*238d7b4bSAxel Dörfler pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
430*238d7b4bSAxel Dörfler 	size_t *_numBytes, bool doWrite)
431*238d7b4bSAxel Dörfler {
432*238d7b4bSAxel Dörfler 	TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, vecCount = %lu, %s\n", ref, offset,
433*238d7b4bSAxel Dörfler 		*_numBytes, count, doWrite ? "write" : "read"));
434*238d7b4bSAxel Dörfler 
435*238d7b4bSAxel Dörfler 	// translate the iovecs into direct device accesses
436*238d7b4bSAxel Dörfler 	file_io_vec fileVecs[MAX_FILE_IO_VECS];
437*238d7b4bSAxel Dörfler 	size_t fileVecCount = MAX_FILE_IO_VECS;
438*238d7b4bSAxel Dörfler 	size_t numBytes = *_numBytes;
439*238d7b4bSAxel Dörfler 
440*238d7b4bSAxel Dörfler 	status_t status = get_file_map(ref, offset, numBytes, fileVecs,
441*238d7b4bSAxel Dörfler 		&fileVecCount);
442*238d7b4bSAxel Dörfler 	if (status < B_OK) {
443*238d7b4bSAxel Dörfler 		TRACE(("get_file_map(offset = %Ld, numBytes = %lu) failed\n", offset,
444*238d7b4bSAxel Dörfler 			numBytes));
445*238d7b4bSAxel Dörfler 		return status;
446*238d7b4bSAxel Dörfler 	}
447*238d7b4bSAxel Dörfler 
448*238d7b4bSAxel Dörfler 	// TODO: handle array overflow gracefully!
449*238d7b4bSAxel Dörfler 
450*238d7b4bSAxel Dörfler #ifdef TRACE_FILE_CACHE
451*238d7b4bSAxel Dörfler 	dprintf("got %lu file vecs for %Ld:%lu:\n", fileVecCount, offset, numBytes);
452*238d7b4bSAxel Dörfler 	for (size_t i = 0; i < fileVecCount; i++) {
453*238d7b4bSAxel Dörfler 		dprintf("  [%lu] offset = %Ld, size = %Ld\n",
454*238d7b4bSAxel Dörfler 			i, fileVecs[i].offset, fileVecs[i].length);
455*238d7b4bSAxel Dörfler 	}
456*238d7b4bSAxel Dörfler #endif
457*238d7b4bSAxel Dörfler 
458*238d7b4bSAxel Dörfler 	if (fileVecCount == 0) {
459*238d7b4bSAxel Dörfler 		// There are no file vecs at this offset, so we're obviously trying
460*238d7b4bSAxel Dörfler 		// to access the file outside of its bounds
461*238d7b4bSAxel Dörfler 		TRACE(("pages_io: access outside of vnode %p at offset %Ld\n",
462*238d7b4bSAxel Dörfler 			ref->vnode, offset));
463*238d7b4bSAxel Dörfler 		return B_BAD_VALUE;
464*238d7b4bSAxel Dörfler 	}
465*238d7b4bSAxel Dörfler 
466*238d7b4bSAxel Dörfler 	uint32 fileVecIndex;
467*238d7b4bSAxel Dörfler 	size_t size;
468*238d7b4bSAxel Dörfler 
469*238d7b4bSAxel Dörfler 	if (!doWrite) {
470*238d7b4bSAxel Dörfler 		// now directly read the data from the device
471*238d7b4bSAxel Dörfler 		// the first file_io_vec can be read directly
472*238d7b4bSAxel Dörfler 
473*238d7b4bSAxel Dörfler 		size = fileVecs[0].length;
474*238d7b4bSAxel Dörfler 		if (size > numBytes)
475*238d7b4bSAxel Dörfler 			size = numBytes;
476*238d7b4bSAxel Dörfler 
477*238d7b4bSAxel Dörfler 		status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs,
478*238d7b4bSAxel Dörfler 			count, &size, false);
479*238d7b4bSAxel Dörfler 		if (status < B_OK)
480*238d7b4bSAxel Dörfler 			return status;
481*238d7b4bSAxel Dörfler 
482*238d7b4bSAxel Dörfler 		// TODO: this is a work-around for buggy device drivers!
483*238d7b4bSAxel Dörfler 		//	When our own drivers honour the length, we can:
484*238d7b4bSAxel Dörfler 		//	a) also use this direct I/O for writes (otherwise, it would
485*238d7b4bSAxel Dörfler 		//	   overwrite precious data)
486*238d7b4bSAxel Dörfler 		//	b) panic if the term below is true (at least for writes)
487*238d7b4bSAxel Dörfler 		if (size > fileVecs[0].length) {
488*238d7b4bSAxel Dörfler 			//dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
489*238d7b4bSAxel Dörfler 			size = fileVecs[0].length;
490*238d7b4bSAxel Dörfler 		}
491*238d7b4bSAxel Dörfler 
492*238d7b4bSAxel Dörfler 		//ASSERT(size <= fileVecs[0].length);
493*238d7b4bSAxel Dörfler 
494*238d7b4bSAxel Dörfler 		// If the file portion was contiguous, we're already done now
495*238d7b4bSAxel Dörfler 		if (size == numBytes)
496*238d7b4bSAxel Dörfler 			return B_OK;
497*238d7b4bSAxel Dörfler 
498*238d7b4bSAxel Dörfler 		// if we reached the end of the file, we can return as well
499*238d7b4bSAxel Dörfler 		if (size != fileVecs[0].length) {
500*238d7b4bSAxel Dörfler 			*_numBytes = size;
501*238d7b4bSAxel Dörfler 			return B_OK;
502*238d7b4bSAxel Dörfler 		}
503*238d7b4bSAxel Dörfler 
504*238d7b4bSAxel Dörfler 		fileVecIndex = 1;
505*238d7b4bSAxel Dörfler 	} else {
506*238d7b4bSAxel Dörfler 		fileVecIndex = 0;
507*238d7b4bSAxel Dörfler 		size = 0;
508*238d7b4bSAxel Dörfler 	}
509*238d7b4bSAxel Dörfler 
510*238d7b4bSAxel Dörfler 	// Too bad, let's process the rest of the file_io_vecs
511*238d7b4bSAxel Dörfler 
512*238d7b4bSAxel Dörfler 	size_t totalSize = size;
513*238d7b4bSAxel Dörfler 
514*238d7b4bSAxel Dörfler 	// first, find out where we have to continue in our iovecs
515*238d7b4bSAxel Dörfler 	uint32 i = 0;
516*238d7b4bSAxel Dörfler 	for (; i < count; i++) {
517*238d7b4bSAxel Dörfler 		if (size < vecs[i].iov_len)
518*238d7b4bSAxel Dörfler 			break;
519*238d7b4bSAxel Dörfler 
520*238d7b4bSAxel Dörfler 		size -= vecs[i].iov_len;
521*238d7b4bSAxel Dörfler 	}
522*238d7b4bSAxel Dörfler 
523*238d7b4bSAxel Dörfler 	size_t vecOffset = size;
524*238d7b4bSAxel Dörfler 	size_t bytesLeft = numBytes - size;
525*238d7b4bSAxel Dörfler 
526*238d7b4bSAxel Dörfler 	for (; fileVecIndex < fileVecCount; fileVecIndex++) {
527*238d7b4bSAxel Dörfler 		file_io_vec &fileVec = fileVecs[fileVecIndex];
528*238d7b4bSAxel Dörfler 		off_t fileOffset = fileVec.offset;
529*238d7b4bSAxel Dörfler 		off_t fileLeft = fileVec.length;
530*238d7b4bSAxel Dörfler 
531*238d7b4bSAxel Dörfler 		fileLeft = min_c(fileVec.length, bytesLeft);
532*238d7b4bSAxel Dörfler 
533*238d7b4bSAxel Dörfler printf("FILE VEC [%lu] length %Ld\n", fileVecIndex, fileLeft);
534*238d7b4bSAxel Dörfler 		while (fileLeft > 0) {
535*238d7b4bSAxel Dörfler 			iovec tempVecs[MAX_TEMP_IO_VECS];
536*238d7b4bSAxel Dörfler 			uint32 tempCount = 1;
537*238d7b4bSAxel Dörfler 
538*238d7b4bSAxel Dörfler 			size = min_c(vecs[i].iov_len - vecOffset, fileLeft);
539*238d7b4bSAxel Dörfler 
540*238d7b4bSAxel Dörfler 			tempVecs[0].iov_base = (void *)((addr_t)vecs[i].iov_base + vecOffset);
541*238d7b4bSAxel Dörfler 			tempVecs[0].iov_len = size;
542*238d7b4bSAxel Dörfler 
543*238d7b4bSAxel Dörfler 			if (size >= fileLeft)
544*238d7b4bSAxel Dörfler 				vecOffset += size;
545*238d7b4bSAxel Dörfler 			else
546*238d7b4bSAxel Dörfler 				vecOffset = 0;
547*238d7b4bSAxel Dörfler 
548*238d7b4bSAxel Dörfler 			while (size < fileLeft && ++i < count
549*238d7b4bSAxel Dörfler 				&& tempCount < MAX_TEMP_IO_VECS) {
550*238d7b4bSAxel Dörfler 			TRACE(("fill vec %ld, offset = %lu, size = %lu\n", i, vecOffset, size));
551*238d7b4bSAxel Dörfler 				tempVecs[tempCount].iov_base = vecs[i].iov_base;
552*238d7b4bSAxel Dörfler 
553*238d7b4bSAxel Dörfler 				// is this iovec larger than the file_io_vec?
554*238d7b4bSAxel Dörfler 				if (vecs[i].iov_len + size > fileLeft) {
555*238d7b4bSAxel Dörfler 					size += tempVecs[tempCount].iov_len
556*238d7b4bSAxel Dörfler 						= vecOffset = fileLeft - size;
557*238d7b4bSAxel Dörfler 					tempCount++;
558*238d7b4bSAxel Dörfler 					break;
559*238d7b4bSAxel Dörfler 				}
560*238d7b4bSAxel Dörfler 
561*238d7b4bSAxel Dörfler 				size += tempVecs[tempCount].iov_len = vecs[i].iov_len;
562*238d7b4bSAxel Dörfler 				tempCount++;
563*238d7b4bSAxel Dörfler 			}
564*238d7b4bSAxel Dörfler 
565*238d7b4bSAxel Dörfler 			size_t bytes = size;
566*238d7b4bSAxel Dörfler 			if (doWrite) {
567*238d7b4bSAxel Dörfler 				status = vfs_write_pages(ref->device, ref->cookie, fileOffset,
568*238d7b4bSAxel Dörfler 					tempVecs, tempCount, &bytes, false);
569*238d7b4bSAxel Dörfler 			} else {
570*238d7b4bSAxel Dörfler 				status = vfs_read_pages(ref->device, ref->cookie, fileOffset,
571*238d7b4bSAxel Dörfler 					tempVecs, tempCount, &bytes, false);
572*238d7b4bSAxel Dörfler 			}
573*238d7b4bSAxel Dörfler 			if (status < B_OK)
574*238d7b4bSAxel Dörfler 				return status;
575*238d7b4bSAxel Dörfler 
576*238d7b4bSAxel Dörfler 			totalSize += size;
577*238d7b4bSAxel Dörfler 			bytesLeft -= size;
578*238d7b4bSAxel Dörfler 			fileOffset += size;
579*238d7b4bSAxel Dörfler 			fileLeft -= size;
580*238d7b4bSAxel Dörfler 			printf("-> file left = %Lu\n", fileLeft);
581*238d7b4bSAxel Dörfler 
582*238d7b4bSAxel Dörfler 			if (size != bytes) {
583*238d7b4bSAxel Dörfler 				// there are no more bytes, let's bail out
584*238d7b4bSAxel Dörfler 				*_numBytes = totalSize;
585*238d7b4bSAxel Dörfler 				return B_OK;
586*238d7b4bSAxel Dörfler 			}
587*238d7b4bSAxel Dörfler 		}
588*238d7b4bSAxel Dörfler 	}
589*238d7b4bSAxel Dörfler 
590*238d7b4bSAxel Dörfler 	return B_OK;
591*238d7b4bSAxel Dörfler }
592*238d7b4bSAxel Dörfler 
593*238d7b4bSAxel Dörfler 
594*238d7b4bSAxel Dörfler //	#pragma mark -
595*238d7b4bSAxel Dörfler 
596*238d7b4bSAxel Dörfler 
597*238d7b4bSAxel Dörfler int
598*238d7b4bSAxel Dörfler main(int argc, char **argv)
599*238d7b4bSAxel Dörfler {
600*238d7b4bSAxel Dörfler 	file_cache_ref ref;
601*238d7b4bSAxel Dörfler 	iovec vecs[MAX_IO_VECS];
602*238d7b4bSAxel Dörfler 	size_t count = 1;
603*238d7b4bSAxel Dörfler 	size_t numBytes = 10000;
604*238d7b4bSAxel Dörfler 	off_t offset = 4999;
605*238d7b4bSAxel Dörfler 
606*238d7b4bSAxel Dörfler 	set_vecs(vecs, &count, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 4096, 8192, 16384, 4096, 4096, -1);
607*238d7b4bSAxel Dörfler 	set_file_map(0, 2000, 5000, 3000, 10000, 800, 11000, 20, 12000, 30, 13000, 70, 14000, 100, 15000, 30000, -1);
608*238d7b4bSAxel Dörfler 
609*238d7b4bSAxel Dörfler 	pages_io(&ref, offset, vecs, count, &numBytes, false);
610*238d7b4bSAxel Dörfler 
611*238d7b4bSAxel Dörfler 	return 0;
612*238d7b4bSAxel Dörfler }
613*238d7b4bSAxel Dörfler 
614