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