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