1/* 2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include <stdio.h> 8#include <string.h> 9 10#include <fs_cache.h> 11#include <fs_interface.h> 12 13#include <file_cache.h> 14 15 16#define MAX_VECS 32 17 18 19class Map { 20public: 21 Map(const char* name, off_t size); 22 ~Map(); 23 24 void SetTo(const char* name, off_t size); 25 26 Map& Add(off_t offset, off_t length, off_t diskOffset); 27 Map& Clear(); 28 Map& SetSize(off_t size); 29 void Invalidate(off_t start, off_t size); 30 void SetMode(uint32 mode); 31 void Test(); 32 33 status_t GetFileMap(off_t offset, off_t length, file_io_vec* vecs, 34 size_t* _vecCount); 35 36private: 37 void _Error(const char* format, ...); 38 void _Verbose(const char* format, ...); 39 int32 _IndexFor(off_t offset); 40 41 const char* fName; 42 uint32 fTest; 43 void* fMap; 44 off_t fOffsets[MAX_VECS]; 45 file_io_vec fVecs[MAX_VECS]; 46 file_io_vec fTestVecs[MAX_VECS]; 47 uint32 fCount; 48 uint32 fTestCount; 49 off_t fTestOffset; 50 off_t fTestLength; 51 off_t fSize; 52}; 53 54 55static bool sVerbose; 56 57 58Map::Map(const char* name, off_t size) 59 : 60 fName(NULL), 61 fMap(NULL), 62 fCount(0), 63 fSize(0) 64{ 65 SetTo(name, size); 66} 67 68 69Map::~Map() 70{ 71 file_map_delete(fMap); 72} 73 74 75void 76Map::SetTo(const char* name, off_t size) 77{ 78 file_map_delete(fMap); 79 80 fMap = file_map_create((dev_t)this, 0, size); 81 if (fMap == NULL) 82 _Error("Creating file map failed."); 83 84 fName = name; 85 fSize = size; 86 fCount = 0; 87 fTest = 0; 88 89 printf("Running %s\n", fName); 90} 91 92 93Map& 94Map::Add(off_t offset, off_t length, off_t diskOffset) 95{ 96 _Verbose(" Add(): offset %lld, length %lld, diskOffset %lld", offset, 97 length, diskOffset); 98 99 if (fCount < MAX_VECS) { 100 fOffsets[fCount] = offset; 101 fVecs[fCount].offset = diskOffset; 102 fVecs[fCount].length = length; 103 fCount++; 104 } 105 106 return *this; 107} 108 109 110Map& 111Map::Clear() 112{ 113 _Verbose(" Clear()"); 114 fCount = 0; 115 return *this; 116} 117 118 119Map& 120Map::SetSize(off_t size) 121{ 122 _Verbose(" SetSize(): size %lld", size); 123 file_map_set_size(fMap, size); 124 fSize = size; 125 return *this; 126} 127 128 129void 130Map::Invalidate(off_t start, off_t size) 131{ 132 _Verbose(" Invalidate(): start %lld, size %lld", start, size); 133 file_map_invalidate(fMap, start, size); 134} 135 136 137void 138Map::SetMode(uint32 mode) 139{ 140 file_map_set_mode(fMap, mode); 141} 142 143 144void 145Map::Test() 146{ 147 printf(" Test %lu\n", ++fTest); 148 149 for (off_t offset = 0; offset < fSize; offset += 256) { 150 fTestOffset = offset; 151 fTestLength = 256; 152 fTestCount = MAX_VECS; 153 status_t status = file_map_translate(fMap, offset, fTestLength, 154 fTestVecs, &fTestCount, 0); 155 if (status != B_OK) { 156 _Error("file_map_translate(offset %lld) failed: %s", offset, 157 strerror(status)); 158 } 159 160 int32 index = _IndexFor(offset); 161 if (index < 0) 162 _Error("index for offset %lld not found!", offset); 163 164 off_t diff = offset - fOffsets[index]; 165 166 if (fTestVecs[0].length > fSize - diff) { 167 _Error("size too large: got %lld, size is %lld", 168 fTestVecs[0].length, fSize); 169 } 170 if (fTestVecs[0].offset != fVecs[index].offset + diff) { 171 _Error("offset mismatch: got %lld, should be %lld", 172 fTestVecs[0].offset, fVecs[index].offset + diff); 173 } 174 } 175 176 fTestCount = 0; 177} 178 179 180status_t 181Map::GetFileMap(off_t offset, off_t length, file_io_vec* vecs, 182 size_t* _vecCount) 183{ 184 int32 index = _IndexFor(offset); 185 if (index < 0) 186 _Error("No vec for offset %lld\n", offset); 187 188 _Verbose(" GetFileMap(): offset: %lld, length: %lld, index %ld", offset, 189 length, index); 190 191 uint32 count = 0; 192 193 while (length > 0) { 194 if (count >= *_vecCount) 195 return B_BUFFER_OVERFLOW; 196 if ((uint32)index >= fCount) 197 break; 198 199 off_t diff = offset - fOffsets[index]; 200 vecs[count].offset = fVecs[index].offset + diff; 201 vecs[count].length = fVecs[index].length - diff; 202 _Verbose(" [%lu] offset %lld, length %lld", count, 203 vecs[count].offset, vecs[count].length); 204 205 length -= vecs[count].length; 206 offset += vecs[count].length; 207 index++; 208 count++; 209 } 210 211 *_vecCount = count; 212 return B_OK; 213} 214 215 216void 217Map::_Error(const char* format, ...) 218{ 219 va_list args; 220 va_start(args, format); 221 222 fprintf(stderr, "ERROR %s: ", fName); 223 vfprintf(stderr, format, args); 224 fputc('\n', stderr); 225 226 va_end(args); 227 228 fprintf(stderr, " size %lld\n", fSize); 229 230 for (uint32 i = 0; i < fCount; i++) { 231 fprintf(stderr, " [%lu] offset %lld, length %lld, disk offset %lld\n", 232 i, fOffsets[i], fVecs[i].length, fVecs[i].offset); 233 } 234 235 if (fTestCount > 0) { 236 fprintf(stderr, "got for offset %lld, length %lld:\n", 237 fTestOffset, fTestLength); 238 } 239 240 for (uint32 i = 0; i < fTestCount; i++) { 241 fprintf(stderr, " [%lu] offset %lld, length %lld\n", 242 i, fTestVecs[i].offset, fTestVecs[i].length); 243 } 244 245 fflush(stderr); 246 247 debugger("file map error"); 248 exit(1); 249} 250 251 252void 253Map::_Verbose(const char* format, ...) 254{ 255 if (!sVerbose) 256 return; 257 258 va_list args; 259 va_start(args, format); 260 261 vprintf(format, args); 262 putchar('\n'); 263 264 va_end(args); 265 fflush(stdout); 266} 267 268 269int32 270Map::_IndexFor(off_t offset) 271{ 272 for (uint32 i = 0; i < fCount; i++) { 273 if (offset >= fOffsets[i] && offset < fOffsets[i] + fVecs[i].length) 274 return i; 275 } 276 277 return -1; 278} 279 280 281// #pragma mark - VFS support functions 282 283 284extern "C" status_t 285vfs_get_file_map(struct vnode* vnode, off_t offset, uint32 length, 286 file_io_vec* vecs, size_t* _vecCount) 287{ 288 Map* map = (Map*)vnode; 289 return map->GetFileMap(offset, length, vecs, _vecCount); 290} 291 292 293extern "C" status_t 294vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode** _vnode) 295{ 296 *_vnode = (struct vnode*)mountID; 297 return B_OK; 298} 299 300 301// #pragma mark - 302 303 304int 305main(int argc, char** argv) 306{ 307 file_map_init(); 308 sVerbose = true; 309 310 Map map("shrink1", 4096); 311 map.Add(0, 1024, 4096).Add(1024, 3072, 8192); 312 map.Test(); 313 map.SetSize(0).Clear(); 314 map.Test(); 315 map.Add(0, 8192, 1000).SetSize(7777); 316 map.Test(); 317 318 map.SetTo("shrink2", 8888); 319 map.Add(0, 10000, 3330000); 320 map.Test(); 321 map.SetSize(0); 322 map.SetSize(4444); 323 map.Clear(); 324 map.Add(0, 5000, 2220000); 325 map.Test(); 326 327 map.SetTo("shrink3", 256000); 328 map.Add(0, 98304, 188074464); 329 map.Add(98304, 38912, 189057024); 330 map.Add(137216, 118784, 189177856); 331 map.Test(); 332 map.SetSize(0); 333 map.Test(); 334 335 return 0; 336} 337