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 19 class Map { 20 public: 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 36 private: 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 55 static bool sVerbose; 56 57 58 Map::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 69 Map::~Map() 70 { 71 file_map_delete(fMap); 72 } 73 74 75 void 76 Map::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 93 Map& 94 Map::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 110 Map& 111 Map::Clear() 112 { 113 _Verbose(" Clear()"); 114 fCount = 0; 115 return *this; 116 } 117 118 119 Map& 120 Map::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 129 void 130 Map::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 137 void 138 Map::SetMode(uint32 mode) 139 { 140 file_map_set_mode(fMap, mode); 141 } 142 143 144 void 145 Map::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 180 status_t 181 Map::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 216 void 217 Map::_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 252 void 253 Map::_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 269 int32 270 Map::_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 284 extern "C" status_t 285 vfs_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 293 extern "C" status_t 294 vfs_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 304 int 305 main(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