1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 7 /*********************************************************************/ 8 9 OSSTATUS __fastcall WCacheCheckLimits(IN PW_CACHE Cache, 10 IN PVOID Context, 11 IN lba_t ReqLba, 12 IN ULONG BCount); 13 14 OSSTATUS __fastcall WCacheCheckLimitsRAM(IN PW_CACHE Cache, 15 IN PVOID Context, 16 IN lba_t ReqLba, 17 IN ULONG BCount); 18 19 OSSTATUS __fastcall WCacheCheckLimitsRW(IN PW_CACHE Cache, 20 IN PVOID Context, 21 IN lba_t ReqLba, 22 IN ULONG BCount); 23 24 OSSTATUS __fastcall WCacheCheckLimitsR(IN PW_CACHE Cache, 25 IN PVOID Context, 26 IN lba_t ReqLba, 27 IN ULONG BCount); 28 29 VOID __fastcall WCachePurgeAllRW(IN PW_CACHE Cache, 30 IN PVOID Context); 31 32 VOID __fastcall WCacheFlushAllRW(IN PW_CACHE Cache, 33 IN PVOID Context); 34 35 VOID __fastcall WCachePurgeAllR(IN PW_CACHE Cache, 36 IN PVOID Context); 37 38 OSSTATUS __fastcall WCacheDecodeFlags(IN PW_CACHE Cache, 39 IN ULONG Flags); 40 41 #define ASYNC_STATE_NONE 0 42 #define ASYNC_STATE_READ_PRE 1 43 #define ASYNC_STATE_READ 2 44 #define ASYNC_STATE_WRITE_PRE 3 45 #define ASYNC_STATE_WRITE 4 46 #define ASYNC_STATE_DONE 5 47 48 #define ASYNC_CMD_NONE 0 49 #define ASYNC_CMD_READ 1 50 #define ASYNC_CMD_UPDATE 2 51 52 #define WCACHE_MAX_CHAIN (0x10) 53 54 #define MEM_WCCTX_TAG 'xtCW' 55 #define MEM_WCFRM_TAG 'rfCW' 56 #define MEM_WCBUF_TAG 'fbCW' 57 58 #define USE_WC_PRINT 59 60 #ifdef USE_WC_PRINT 61 #define WcPrint UDFPrint 62 #else 63 #define WcPrint(x) {;} 64 #endif 65 66 typedef struct _W_CACHE_ASYNC { 67 UDF_PH_CALL_CONTEXT PhContext; 68 ULONG State; 69 ULONG Cmd; 70 PW_CACHE Cache; 71 PVOID Buffer; 72 PVOID Buffer2; 73 SIZE_T TransferredBytes; 74 ULONG BCount; 75 lba_t Lba; 76 struct _W_CACHE_ASYNC* NextWContext; 77 struct _W_CACHE_ASYNC* PrevWContext; 78 } W_CACHE_ASYNC, *PW_CACHE_ASYNC; 79 80 VOID 81 WCacheUpdatePacketComplete( 82 IN PW_CACHE Cache, // pointer to the Cache Control structure 83 IN PVOID Context, // user-supplied context for IO callbacks 84 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context 85 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context 86 IN BOOLEAN FreePacket = TRUE 87 ); 88 89 /*********************************************************************/ 90 ULONG WCache_random; 91 92 /* 93 WCacheInit__() fills all necesary fileds in passed in PW_CACHE Cache 94 structure, allocates memory and synchronization resources. 95 Cacheable area is subdiveded on Frames - contiguous sets of blocks. 96 Internally each Frame is an array of pointers and attributes of cached 97 Blocks. To optimize memory usage WCache keeps in memory limited number 98 of frames (MaxFrames). 99 Frame length (number of Blocks) must be be a power of 2 and aligned on 100 minimum writeable block size - Packet. 101 Packet size must be a power of 2 (2, 4, 8, 16, etc.). 102 Each cached Block belongs to one of the Frames. To optimize memory usage 103 WCache keeps in memory limited number of Blocks (MaxBlocks). Block size 104 must be a power of 2. 105 WCache splits low-level request(s) into some parts if requested data length 106 exceeds MaxBytesToRead. 107 If requested data length exceeds maximum cache size WCache makes 108 recursive calls to read/write routines with shorter requests 109 110 WCacheInit__() returns initialization status. If initialization failed, 111 all allocated memory and resources are automaticelly freed. 112 113 Public routine 114 */ 115 OSSTATUS 116 WCacheInit__( 117 IN PW_CACHE Cache, // pointer to the Cache Control structure to be initialized 118 IN ULONG MaxFrames, // maximum number of Frames to be kept in memory 119 // simultaneously 120 IN ULONG MaxBlocks, // maximum number of Blocks to be kept in memory 121 // simultaneously 122 IN SIZE_T MaxBytesToRead, // maximum IO length (split boundary) 123 IN ULONG PacketSizeSh, // number of blocks in packet (bit shift) 124 // Packes size = 2^PacketSizeSh 125 IN ULONG BlockSizeSh, // Block size (bit shift) 126 // Block size = 2^BlockSizeSh 127 IN ULONG BlocksPerFrameSh,// number of blocks in Frame (bit shift) 128 // Frame size = 2^BlocksPerFrameSh 129 IN lba_t FirstLba, // Logical Block Address (LBA) of the 1st block 130 // in cacheable area 131 IN lba_t LastLba, // Logical Block Address (LBA) of the last block 132 // in cacheable area 133 IN ULONG Mode, // media mode: 134 // WCACHE_MODE_ROM 135 // WCACHE_MODE_RW 136 // WCACHE_MODE_R 137 // WCACHE_MODE_RAM 138 // the following modes are planned to be implemented: 139 // WCACHE_MODE_EWR 140 IN ULONG Flags, // cache mode flags: 141 // WCACHE_CACHE_WHOLE_PACKET 142 // read long (Packet-sized) blocks of 143 // data from media 144 IN ULONG FramesToKeepFree, 145 // number of Frames to be flushed & purged from cache 146 // when Frame counter reaches top-limit and allocation 147 // of a new Frame required 148 IN PWRITE_BLOCK WriteProc, 149 // pointer to synchronous physical write call-back routine 150 IN PREAD_BLOCK ReadProc, 151 // pointer to synchronous physical read call-back routine 152 IN PWRITE_BLOCK_ASYNC WriteProcAsync, 153 // pointer to _asynchronous_ physical write call-back routine 154 // currently must be set to NULL because async support 155 // is not completly implemented 156 IN PREAD_BLOCK_ASYNC ReadProcAsync, 157 // pointer to _asynchronous_ physical read call-back routine 158 // must be set to NULL (see above) 159 IN PCHECK_BLOCK CheckUsedProc, 160 // pointer to call-back routine that checks whether the Block 161 // specified (by LBA) is allocated for some data or should 162 // be treated as unused (and thus, zero-filled). 163 // Is used to avoid physical reads and writes from/to such Blocks 164 IN PUPDATE_RELOC UpdateRelocProc, 165 // pointer to call-back routine that updates caller's 166 // relocation table _after_ physical write (append) in WORM 167 // (WCACHE_MODE_R) mode. WCache sends original and new 168 // (derived from last LBA) logical addresses to this routine 169 IN PWC_ERROR_HANDLER ErrorHandlerProc 170 ) 171 { 172 ULONG l1, l2, l3; 173 ULONG PacketSize = (1) << PacketSizeSh; 174 ULONG BlockSize = (1) << BlockSizeSh; 175 ULONG BlocksPerFrame = (1) << BlocksPerFrameSh; 176 OSSTATUS RC = STATUS_SUCCESS; 177 LARGE_INTEGER rseed; 178 ULONG res_init_flags = 0; 179 180 #define WCLOCK_RES 1 181 182 _SEH2_TRY { 183 // check input parameters 184 if(Mode == WCACHE_MODE_R) { 185 UDFPrint(("Disable Async-Write for WORM media\n")); 186 WriteProcAsync = NULL; 187 } 188 if((MaxBlocks % PacketSize) || !MaxBlocks) { 189 UDFPrint(("Total number of sectors must be packet-size-aligned\n")); 190 try_return(RC = STATUS_INVALID_PARAMETER); 191 } 192 if(BlocksPerFrame % PacketSize) { 193 UDFPrint(("Number of sectors per Frame must be packet-size-aligned\n")); 194 try_return(RC = STATUS_INVALID_PARAMETER); 195 } 196 if(!ReadProc) { 197 UDFPrint(("Read routine pointer must be valid\n")); 198 try_return(RC = STATUS_INVALID_PARAMETER); 199 } 200 if(FirstLba >= LastLba) { 201 UDFPrint(("Invalid cached area parameters: (%x - %x)\n",FirstLba, LastLba)); 202 try_return(RC = STATUS_INVALID_PARAMETER); 203 } 204 if(!MaxFrames) { 205 UDFPrint(("Total frame number must be non-zero\n",FirstLba, LastLba)); 206 try_return(RC = STATUS_INVALID_PARAMETER); 207 } 208 if(Mode > WCACHE_MODE_MAX) { 209 UDFPrint(("Invalid media mode. Should be 0-%x\n",WCACHE_MODE_MAX)); 210 try_return(RC = STATUS_INVALID_PARAMETER); 211 } 212 if(FramesToKeepFree >= MaxFrames/2) { 213 UDFPrint(("Invalid FramesToKeepFree (%x). Should be Less or equal to MaxFrames/2 (%x)\n", FramesToKeepFree, MaxFrames/2)); 214 try_return(RC = STATUS_INVALID_PARAMETER); 215 } 216 // check 'features' 217 if(!WriteProc) { 218 UDFPrint(("Write routine not specified\n")); 219 UDFPrint(("Read-only mode enabled\n")); 220 } 221 MaxBlocks = max(MaxBlocks, BlocksPerFrame*3); 222 // initialize required structures 223 // we'll align structure size on system page size to 224 // avoid system crashes caused by pool fragmentation 225 if(!(Cache->FrameList = 226 (PW_CACHE_FRAME)MyAllocatePoolTag__(NonPagedPool, l1 = (((LastLba >> BlocksPerFrameSh)+1)*sizeof(W_CACHE_FRAME)), MEM_WCFRM_TAG) )) { 227 UDFPrint(("Cache init err 1\n")); 228 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 229 } 230 if(!(Cache->CachedBlocksList = 231 (PULONG)MyAllocatePoolTag__(NonPagedPool, l2 = ((MaxBlocks+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) { 232 UDFPrint(("Cache init err 2\n")); 233 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 234 } 235 if(!(Cache->CachedModifiedBlocksList = 236 (PULONG)MyAllocatePoolTag__(NonPagedPool, l2, MEM_WCFRM_TAG) )) { 237 UDFPrint(("Cache init err 3\n")); 238 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 239 } 240 if(!(Cache->CachedFramesList = 241 (PULONG)MyAllocatePoolTag__(NonPagedPool, l3 = ((MaxFrames+2)*sizeof(lba_t)), MEM_WCFRM_TAG) )) { 242 UDFPrint(("Cache init err 4\n")); 243 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 244 } 245 RtlZeroMemory(Cache->FrameList, l1); 246 RtlZeroMemory(Cache->CachedBlocksList, l2); 247 RtlZeroMemory(Cache->CachedModifiedBlocksList, l2); 248 RtlZeroMemory(Cache->CachedFramesList, l3); 249 // remember all useful parameters 250 Cache->BlocksPerFrame = BlocksPerFrame; 251 Cache->BlocksPerFrameSh = BlocksPerFrameSh; 252 Cache->BlockCount = 0; 253 Cache->MaxBlocks = MaxBlocks; 254 Cache->MaxBytesToRead = MaxBytesToRead; 255 Cache->FrameCount = 0; 256 Cache->MaxFrames = MaxFrames; 257 Cache->PacketSize = PacketSize; 258 Cache->PacketSizeSh = PacketSizeSh; 259 Cache->BlockSize = BlockSize; 260 Cache->BlockSizeSh = BlockSizeSh; 261 Cache->WriteCount = 0; 262 Cache->FirstLba = FirstLba; 263 Cache->LastLba = LastLba; 264 Cache->Mode = Mode; 265 266 if(!OS_SUCCESS(RC = WCacheDecodeFlags(Cache, Flags))) { 267 return RC; 268 } 269 270 Cache->FramesToKeepFree = FramesToKeepFree; 271 Cache->WriteProc = WriteProc; 272 Cache->ReadProc = ReadProc; 273 Cache->WriteProcAsync = WriteProcAsync; 274 Cache->ReadProcAsync = ReadProcAsync; 275 Cache->CheckUsedProc = CheckUsedProc; 276 Cache->UpdateRelocProc = UpdateRelocProc; 277 Cache->ErrorHandlerProc = ErrorHandlerProc; 278 // init permanent tmp buffers 279 if(!(Cache->tmp_buff = 280 (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) { 281 UDFPrint(("Cache init err 5.W\n")); 282 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 283 } 284 if(!(Cache->tmp_buff_r = 285 (PCHAR)MyAllocatePoolTag__(NonPagedPool, PacketSize*BlockSize, MEM_WCFRM_TAG))) { 286 UDFPrint(("Cache init err 5.R\n")); 287 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 288 } 289 if(!(Cache->reloc_tab = 290 (PULONG)MyAllocatePoolTag__(NonPagedPool, Cache->PacketSize*sizeof(ULONG), MEM_WCFRM_TAG))) { 291 UDFPrint(("Cache init err 6\n")); 292 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 293 } 294 if(!OS_SUCCESS(RC = ExInitializeResourceLite(&(Cache->WCacheLock)))) { 295 UDFPrint(("Cache init err (res)\n")); 296 try_return(RC); 297 } 298 res_init_flags |= WCLOCK_RES; 299 KeQuerySystemTime((PLARGE_INTEGER)(&rseed)); 300 WCache_random = rseed.LowPart; 301 302 try_exit: NOTHING; 303 304 } _SEH2_FINALLY { 305 306 if(!OS_SUCCESS(RC)) { 307 if(res_init_flags & WCLOCK_RES) 308 ExDeleteResourceLite(&(Cache->WCacheLock)); 309 if(Cache->FrameList) 310 MyFreePool__(Cache->FrameList); 311 if(Cache->CachedBlocksList) 312 MyFreePool__(Cache->CachedBlocksList); 313 if(Cache->CachedModifiedBlocksList) 314 MyFreePool__(Cache->CachedModifiedBlocksList); 315 if(Cache->CachedFramesList) 316 MyFreePool__(Cache->CachedFramesList); 317 if(Cache->tmp_buff_r) 318 MyFreePool__(Cache->tmp_buff_r); 319 if(Cache->tmp_buff) 320 MyFreePool__(Cache->tmp_buff); 321 if(Cache->reloc_tab) 322 MyFreePool__(Cache->reloc_tab); 323 RtlZeroMemory(Cache, sizeof(W_CACHE)); 324 } else { 325 Cache->Tag = 0xCAC11E00; 326 } 327 328 } _SEH2_END; 329 330 return RC; 331 } // end WCacheInit__() 332 333 /* 334 WCacheRandom() - just a random generator 335 Returns random LONGLONG number 336 Internal routine 337 */ 338 LONGLONG 339 WCacheRandom(VOID) 340 { 341 WCache_random = (WCache_random * 0x8088405 + 1); 342 return WCache_random; 343 } // end WCacheRandom() 344 345 /* 346 WCacheFindLbaToRelease() finds Block to be flushed and purged from cache 347 Returns random LBA 348 Internal routine 349 */ 350 lba_t 351 __fastcall 352 WCacheFindLbaToRelease( 353 IN PW_CACHE Cache 354 ) 355 { 356 if(!(Cache->BlockCount)) 357 return WCACHE_INVALID_LBA; 358 return(Cache->CachedBlocksList[((ULONG)WCacheRandom() % Cache->BlockCount)]); 359 } // end WCacheFindLbaToRelease() 360 361 /* 362 WCacheFindModifiedLbaToRelease() finds Block to be flushed and purged from cache. 363 This routine looks for Blocks among modified ones 364 Returns random LBA (nodified) 365 Internal routine 366 */ 367 lba_t 368 __fastcall 369 WCacheFindModifiedLbaToRelease( 370 IN PW_CACHE Cache 371 ) 372 { 373 if(!(Cache->WriteCount)) 374 return WCACHE_INVALID_LBA; 375 return(Cache->CachedModifiedBlocksList[((ULONG)WCacheRandom() % Cache->WriteCount)]); 376 } // end WCacheFindModifiedLbaToRelease() 377 378 /* 379 WCacheFindFrameToRelease() finds Frame to be flushed and purged with all 380 Blocks (from this Frame) from cache 381 Returns random Frame number 382 Internal routine 383 */ 384 lba_t 385 __fastcall 386 WCacheFindFrameToRelease( 387 IN PW_CACHE Cache 388 ) 389 { 390 ULONG i, j; 391 ULONG frame = 0; 392 ULONG prev_uc = -1; 393 ULONG uc = -1; 394 lba_t lba; 395 BOOLEAN mod = FALSE; 396 397 if(!(Cache->FrameCount)) 398 return 0; 399 /* 400 return(Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]); 401 */ 402 403 for(i=0; i<Cache->FrameCount; i++) { 404 405 j = Cache->CachedFramesList[i]; 406 407 mod |= (Cache->FrameList[j].UpdateCount != 0); 408 uc = Cache->FrameList[j].UpdateCount*32 + Cache->FrameList[j].AccessCount; 409 410 if(prev_uc > uc) { 411 prev_uc = uc; 412 frame = j; 413 } 414 } 415 if(!mod) { 416 frame = Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]; 417 lba = frame << Cache->BlocksPerFrameSh; 418 WcPrint(("WC:-frm %x\n", lba)); 419 } else { 420 lba = frame << Cache->BlocksPerFrameSh; 421 WcPrint(("WC:-frm(mod) %x\n", lba)); 422 for(i=0; i<Cache->FrameCount; i++) { 423 424 j = Cache->CachedFramesList[i]; 425 Cache->FrameList[j].UpdateCount = (Cache->FrameList[j].UpdateCount*2)/3; 426 Cache->FrameList[j].AccessCount = (Cache->FrameList[j].AccessCount*3)/4; 427 } 428 } 429 return frame; 430 } // end WCacheFindFrameToRelease() 431 432 /* 433 WCacheGetSortedListIndex() returns index of searched Lba 434 (Lba is ULONG in sorted array) or index of minimal cached Lba 435 greater than searched. 436 If requested Lba is less than minimum cached, 0 is returned. 437 If requested Lba is greater than maximum cached, BlockCount value 438 is returned. 439 Internal routine 440 */ 441 442 #ifdef _MSC_VER 443 #pragma warning(push) 444 #pragma warning(disable:4035) // re-enable below 445 #endif 446 447 ULONG 448 //__fastcall 449 WCacheGetSortedListIndex( 450 IN ULONG BlockCount, // number of items in array (pointed by List) 451 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs 452 IN lba_t Lba // ULONG value to be searched for 453 ) 454 { 455 if(!BlockCount) 456 return 0; 457 458 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 459 460 __asm push ecx 461 __asm push ebx 462 __asm push edx 463 __asm push esi 464 __asm push edi 465 // left = 0; 466 // right = BlockCount - 1; 467 // pos = 0; 468 __asm xor edx,edx // left 469 __asm mov ebx,BlockCount 470 __asm dec ebx // right 471 __asm xor esi,esi // pos 472 __asm mov edi,List // List 473 __asm mov ecx,Lba // Lba 474 475 While_1: 476 // while(left != right) { 477 __asm cmp edx,ebx 478 __asm jz EO_while_1 479 480 // pos = (left + right) >> 1; 481 __asm lea esi,[ebx+edx] 482 __asm shr esi,1 483 // if(List[pos] == Lba) 484 // return pos; 485 __asm mov eax,[edi+esi*4] 486 __asm cmp eax,ecx 487 __asm jz EO_while_2 488 489 // if(right - left == 1) { 490 __asm sub ebx,edx 491 __asm cmp ebx,1 492 __asm jne NO_r_sub_l_eq_1 493 // if(List[pos+1] < Lba) <=> if(List[pos+1] >= Lba) 494 // return (pos+2); <=> break; 495 // break; <=> return (pos+2); 496 __asm cmp [edi+esi*4+4],ecx 497 __asm jae EO_while_1 498 __asm add esi,2 499 __asm jmp EO_while_2 500 // } 501 NO_r_sub_l_eq_1: 502 // if(List[pos] < Lba) { 503 __asm cmp eax,ecx 504 __asm jae Update_r 505 // left = pos; 506 __asm add ebx,edx 507 __asm mov edx,esi 508 __asm jmp While_1 509 // } else { 510 Update_r: 511 // right = pos; 512 __asm mov ebx,esi 513 __asm jmp While_1 514 // } 515 // } 516 EO_while_1: 517 // if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++; 518 __asm mov eax,[edi+esi*4] 519 __asm cmp eax,ecx 520 __asm jae EO_while_2 521 __asm inc esi 522 __asm cmp esi,BlockCount 523 __asm jbe EO_while_2 524 __asm dec esi 525 EO_while_2: 526 // return pos; 527 __asm mov eax,esi 528 529 __asm pop edi 530 __asm pop esi 531 __asm pop edx 532 __asm pop ebx 533 __asm pop ecx 534 535 #else // NO X86 optimization , use generic C/C++ 536 537 ULONG pos; 538 ULONG left; 539 ULONG right; 540 541 if(!BlockCount) 542 return 0; 543 544 left = 0; 545 right = BlockCount - 1; 546 pos = 0; 547 while(left != right) { 548 pos = (left + right) >> 1; 549 if(List[pos] == Lba) 550 return pos; 551 if(right - left == 1) { 552 if(List[pos+1] < Lba) 553 return (pos+2); 554 break; 555 } 556 if(List[pos] < Lba) { 557 left = pos; 558 } else { 559 right = pos; 560 } 561 } 562 if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++; 563 564 return pos; 565 566 #endif // _X86_ 567 568 } 569 570 #ifdef _MSC_VER 571 #pragma warning(pop) // re-enable warning #4035 572 #endif 573 574 /* 575 WCacheInsertRangeToList() inserts values laying in range described 576 by Lba (1st value) and BCount (number of sequentially incremented 577 values) in sorted array of ULONGs pointed by List. 578 Ex.: (Lba, BCount)=(7,3) will insert values {7,8,9}. 579 If target array already contains one or more values falling in 580 requested range, they will be removed before insertion. 581 WCacheInsertRangeToList() updates value of (*BlockCount) to reflect 582 performed changes. 583 WCacheInsertRangeToList() assumes that target array is of enough size. 584 Internal routine 585 */ 586 VOID 587 __fastcall 588 WCacheInsertRangeToList( 589 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs 590 IN PULONG BlockCount, // pointer to number of items in array (pointed by List) 591 IN lba_t Lba, // initial value for insertion 592 IN ULONG BCount // number of sequentially incremented values to be inserted 593 ) 594 { 595 if(!BCount) 596 return; 597 598 ASSERT(!(BCount & 0x80000000)); 599 600 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba); 601 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+BCount); 602 ULONG offs = firstPos + BCount - lastPos; 603 604 if(offs) { 605 // move list tail 606 // ASSERT(lastPos+offs + ((*BlockCount) - lastPos) <= qq); 607 if(*BlockCount) { 608 #ifdef WCACHE_BOUND_CHECKS 609 MyCheckArray(List, lastPos+offs+(*BlockCount)-lastPos-1); 610 #endif //WCACHE_BOUND_CHECKS 611 DbgMoveMemory(&(List[lastPos+offs]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG)); 612 } 613 lastPos += offs; 614 for(; firstPos<lastPos; firstPos++) { 615 #ifdef WCACHE_BOUND_CHECKS 616 MyCheckArray(List, firstPos); 617 #endif //WCACHE_BOUND_CHECKS 618 List[firstPos] = Lba; 619 Lba++; 620 } 621 (*BlockCount) += offs; 622 } 623 } // end WCacheInsertRangeToList() 624 625 /* 626 WCacheInsertItemToList() inserts value Lba in sorted array of 627 ULONGs pointed by List. 628 If target array already contains requested value, no 629 operations are performed. 630 WCacheInsertItemToList() updates value of (*BlockCount) to reflect 631 performed changes. 632 WCacheInsertItemToList() assumes that target array is of enough size. 633 Internal routine 634 */ 635 VOID 636 __fastcall 637 WCacheInsertItemToList( 638 IN lba_t* List, // pointer to sorted (ASC) array of lba_t's 639 IN PULONG BlockCount, // pointer to number of items in array (pointed by List) 640 IN lba_t Lba // value to be inserted 641 ) 642 { 643 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+1); 644 if(firstPos && (List[firstPos-1] == Lba)) 645 return; 646 647 // move list tail 648 if(*BlockCount) { 649 #ifdef WCACHE_BOUND_CHECKS 650 MyCheckArray(List, firstPos+1+(*BlockCount)-firstPos-1); 651 #endif //WCACHE_BOUND_CHECKS 652 // DbgMoveMemory(&(List[firstPos+1]), &(List[firstPos]), ((*BlockCount) - firstPos)*sizeof(ULONG)); 653 DbgMoveMemory(&(List[firstPos+1]), &(List[firstPos]), ((*BlockCount) - firstPos) * sizeof(ULONG)); 654 } 655 #ifdef WCACHE_BOUND_CHECKS 656 MyCheckArray(List, firstPos); 657 #endif //WCACHE_BOUND_CHECKS 658 List[firstPos] = Lba; 659 (*BlockCount) ++; 660 } // end WCacheInsertItemToList() 661 662 /* 663 WCacheRemoveRangeFromList() removes values falling in range described 664 by Lba (1st value) and BCount (number of sequentially incremented 665 values) from sorted array of ULONGs pointed by List. 666 Ex.: (Lba, BCount)=(7,3) will remove values {7,8,9}. 667 If target array doesn't contain values falling in 668 requested range, no operation is performed. 669 WCacheRemoveRangeFromList() updates value of (*BlockCount) to reflect 670 performed changes. 671 Internal routine 672 */ 673 VOID 674 __fastcall 675 WCacheRemoveRangeFromList( 676 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs 677 IN PULONG BlockCount, // pointer to number of items in array (pointed by List) 678 IN lba_t Lba, // initial value for removal 679 IN ULONG BCount // number of sequentially incremented values to be removed 680 ) 681 { 682 ULONG firstPos = WCacheGetSortedListIndex(*BlockCount, List, Lba); 683 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+BCount); 684 ULONG offs = lastPos - firstPos; 685 686 if(offs) { 687 // move list tail 688 DbgMoveMemory(&(List[lastPos-offs]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG)); 689 (*BlockCount) -= offs; 690 } 691 } // end WCacheRemoveRangeFromList() 692 693 /* 694 WCacheRemoveItemFromList() removes value Lba from sorted array 695 of ULONGs pointed by List. 696 If target array doesn't contain requested value, no 697 operations are performed. 698 WCacheRemoveItemFromList() updates value of (*BlockCount) to reflect 699 performed changes. 700 Internal routine 701 */ 702 VOID 703 __fastcall 704 WCacheRemoveItemFromList( 705 IN lba_t* List, // pointer to sorted (ASC) array of ULONGs 706 IN PULONG BlockCount, // pointer to number of items in array (pointed by List) 707 IN lba_t Lba // value to be removed 708 ) 709 { 710 if(!(*BlockCount)) return; 711 ULONG lastPos = WCacheGetSortedListIndex(*BlockCount, List, Lba+1); 712 if(!lastPos || (lastPos && (List[lastPos-1] != Lba))) 713 return; 714 715 // move list tail 716 DbgMoveMemory(&(List[lastPos-1]), &(List[lastPos]), ((*BlockCount) - lastPos) * sizeof(ULONG)); 717 (*BlockCount) --; 718 } // end WCacheRemoveItemFromList() 719 720 /* 721 WCacheInitFrame() allocates storage for Frame (block_array) 722 with index 'frame', fills it with 0 (none of Blocks from 723 this Frame is cached) and inserts it's index to sorted array 724 of frame indexes. 725 WCacheInitFrame() also checks if number of frames reaches limit 726 and invokes WCacheCheckLimits() to free some Frames/Blocks 727 Internal routine 728 */ 729 PW_CACHE_ENTRY 730 __fastcall 731 WCacheInitFrame( 732 IN PW_CACHE Cache, // pointer to the Cache Control structure 733 IN PVOID Context, // caller's context (currently unused) 734 IN ULONG frame // frame index 735 ) 736 { 737 PW_CACHE_ENTRY block_array; 738 ULONG l; 739 #ifdef DBG 740 ULONG old_count = Cache->FrameCount; 741 #endif //DBG 742 743 // We are about to add new cache frame. 744 // Thus check if we have enough free entries and 745 // flush unused ones if it is neccessary. 746 if(Cache->FrameCount >= Cache->MaxFrames) { 747 BrutePoint(); 748 WCacheCheckLimits(Cache, Context, frame << Cache->BlocksPerFrameSh, Cache->PacketSize*2); 749 } 750 ASSERT(Cache->FrameCount < Cache->MaxFrames); 751 block_array = (PW_CACHE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l = sizeof(W_CACHE_ENTRY) << Cache->BlocksPerFrameSh, MEM_WCFRM_TAG); 752 Cache->FrameList[frame].Frame = block_array; 753 754 // Keep history !!! 755 //Cache->FrameList[frame].UpdateCount = 0; 756 //Cache->FrameList[frame].AccessCount = 0; 757 758 if(block_array) { 759 ASSERT((ULONG_PTR)block_array > 0x1000); 760 WCacheInsertItemToList(Cache->CachedFramesList, &(Cache->FrameCount), frame); 761 RtlZeroMemory(block_array, l); 762 } else { 763 BrutePoint(); 764 } 765 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 766 #ifdef DBG 767 ASSERT(old_count < Cache->FrameCount); 768 #endif //DBG 769 return block_array; 770 } // end WCacheInitFrame() 771 772 /* 773 WCacheRemoveFrame() frees storage for Frame (block_array) with 774 index 'frame' and removes it's index from sorted array of 775 frame indexes. 776 Internal routine 777 */ 778 VOID 779 __fastcall 780 WCacheRemoveFrame( 781 IN PW_CACHE Cache, // pointer to the Cache Control structure 782 IN PVOID Context, // user's context (currently unused) 783 IN ULONG frame // frame index 784 ) 785 { 786 PW_CACHE_ENTRY block_array; 787 #ifdef DBG 788 ULONG old_count = Cache->FrameCount; 789 #endif //DBG 790 791 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 792 block_array = Cache->FrameList[frame].Frame; 793 794 WCacheRemoveItemFromList(Cache->CachedFramesList, &(Cache->FrameCount), frame); 795 MyFreePool__(block_array); 796 // ASSERT(!(Cache->FrameList[frame].WriteCount)); 797 // ASSERT(!(Cache->FrameList[frame].WriteCount)); 798 Cache->FrameList[frame].Frame = NULL; 799 ASSERT(Cache->FrameCount < Cache->MaxFrames); 800 #ifdef DBG 801 ASSERT(old_count > Cache->FrameCount); 802 #endif //DBG 803 804 } // end WCacheRemoveFrame() 805 806 /* 807 WCacheSetModFlag() sets Modified flag for Block with offset 'i' 808 in Frame 'block_array' 809 Internal routine 810 */ 811 #define WCacheSetModFlag(block_array, i) \ 812 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_MODIFIED 813 814 /* 815 WCacheClrModFlag() clears Modified flag for Block with offset 'i' 816 in Frame 'block_array' 817 Internal routine 818 */ 819 #define WCacheClrModFlag(block_array, i) \ 820 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_MODIFIED 821 822 /* 823 WCacheGetModFlag() returns non-zero value if Modified flag for 824 Block with offset 'i' in Frame 'block_array' is set. Otherwise 825 0 is returned. 826 Internal routine 827 */ 828 #define WCacheGetModFlag(block_array, i) \ 829 (*((PULONG)&(block_array[i].Sector)) & WCACHE_FLAG_MODIFIED) 830 831 #if 0 832 /* 833 WCacheSetBadFlag() sets Modified flag for Block with offset 'i' 834 in Frame 'block_array' 835 Internal routine 836 */ 837 #define WCacheSetBadFlag(block_array, i) \ 838 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_BAD 839 840 /* 841 WCacheClrBadFlag() clears Modified flag for Block with offset 'i' 842 in Frame 'block_array' 843 Internal routine 844 */ 845 #define WCacheClrBadFlag(block_array, i) \ 846 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_BAD 847 848 /* 849 WCacheGetBadFlag() returns non-zero value if Modified flag for 850 Block with offset 'i' in Frame 'block_array' is set. Otherwise 851 0 is returned. 852 Internal routine 853 */ 854 #define WCacheGetBadFlag(block_array, i) \ 855 (((UCHAR)(block_array[i].Sector)) & WCACHE_FLAG_BAD) 856 #endif //0 857 858 /* 859 WCacheSectorAddr() returns pointer to memory block containing cached 860 data for Block described by Frame (block_array) and offset in this 861 Frame (i). If requested Block is not cached yet NULL is returned. 862 Internal routine 863 */ 864 #define WCacheSectorAddr(block_array, i) \ 865 ((ULONG_PTR)(block_array[i].Sector) & WCACHE_ADDR_MASK) 866 867 /* 868 WCacheFreeSector() releases memory block containing cached 869 data for Block described by Frame (block_array) and offset in this 870 Frame (i). Should never be called for non-cached Blocks. 871 Internal routine 872 */ 873 #define WCacheFreeSector(frame, offs) \ 874 { \ 875 DbgFreePool((PVOID)WCacheSectorAddr(block_array, offs)); \ 876 block_array[offs].Sector = NULL; \ 877 Cache->FrameList[frame].BlockCount--; \ 878 } 879 880 /* 881 WCacheAllocAsyncEntry() allocates storage for async IO context, 882 links it to previously allocated async IO context (if any), 883 initializes synchronization (completion) event 884 and allocates temporary IO buffers. 885 Async IO contexts are used to create chained set of IO requests 886 durring top-level request precessing and wait for their completion. 887 Internal routine 888 */ 889 PW_CACHE_ASYNC 890 WCacheAllocAsyncEntry( 891 IN PW_CACHE Cache, // pointer to the Cache Control structure 892 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to the pointer to 893 // the head of async IO context chain 894 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to the storage for pointer 895 // to newly allocated async IO context chain 896 IN ULONG BufferSize // requested IO buffer size 897 ) 898 { 899 PW_CACHE_ASYNC WContext; 900 PCHAR Buffer; 901 902 WContext = (PW_CACHE_ASYNC)MyAllocatePoolTag__(NonPagedPool,sizeof(W_CACHE_ASYNC), MEM_WCCTX_TAG); 903 if(!WContext) 904 return NULL; 905 Buffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, BufferSize*(2-Cache->Chained), MEM_WCBUF_TAG); 906 if(!Buffer) { 907 MyFreePool__(WContext); 908 return NULL; 909 } 910 911 if(!Cache->Chained) 912 KeInitializeEvent(&(WContext->PhContext.event), SynchronizationEvent, FALSE); 913 WContext->Cache = Cache; 914 if(*PrevWContext) 915 (*PrevWContext)->NextWContext = WContext; 916 // WContext->NextWContext = (*PrevWContext); 917 WContext->NextWContext = NULL; 918 WContext->Buffer = Buffer; 919 WContext->Buffer2 = Buffer+(Cache->Chained ? 0 : BufferSize); 920 921 if(!(*FirstWContext)) 922 (*FirstWContext) = WContext; 923 (*PrevWContext) = WContext; 924 925 return WContext; 926 } // end WCacheAllocAsyncEntry() 927 928 /* 929 WCacheFreeAsyncEntry() releases storage previously allocated for 930 async IO context. 931 Internal routine 932 */ 933 VOID 934 WCacheFreeAsyncEntry( 935 IN PW_CACHE Cache, // pointer to the Cache Control structure 936 PW_CACHE_ASYNC WContext // pointer to async IO context to release 937 ) 938 { 939 DbgFreePool(WContext->Buffer); 940 MyFreePool__(WContext); 941 } // end WCacheFreeAsyncEntry() 942 943 //#define WCacheRaiseIoError(c, ct, s, l, bc, b, o, r) 944 945 OSSTATUS 946 WCacheRaiseIoError( 947 IN PW_CACHE Cache, // pointer to the Cache Control structure 948 IN PVOID Context, 949 IN OSSTATUS Status, 950 IN ULONG Lba, 951 IN ULONG BCount, 952 IN PVOID Buffer, 953 IN BOOLEAN ReadOp, 954 IN PBOOLEAN Retry 955 ) 956 { 957 if(!Cache->ErrorHandlerProc) 958 return Status; 959 960 WCACHE_ERROR_CONTEXT ec; 961 962 ec.WCErrorCode = ReadOp ? WCACHE_ERROR_READ : WCACHE_ERROR_WRITE; 963 ec.Status = Status; 964 ec.ReadWrite.Lba = Lba; 965 ec.ReadWrite.BCount = BCount; 966 ec.ReadWrite.Buffer = Buffer; 967 Status = Cache->ErrorHandlerProc(Context, &ec); 968 if(Retry) 969 (*Retry) = ec.Retry; 970 971 return Status; 972 973 } // end WCacheRaiseIoError() 974 975 /* 976 WCacheUpdatePacket() attempts to updates packet containing target Block. 977 If async IO is enabled new IO context is added to the chain. 978 If packet containing target Block is modified and PrefereWrite flag 979 is NOT set, function returns with status STATUS_RETRY. This setting is 980 user in WCACHE_MODE_R mode to reduce physical writes on flush. 981 'State' parameter is used in async mode to determine the next processing 982 stege for given request 983 Internal routine 984 */ 985 OSSTATUS 986 WCacheUpdatePacket( 987 IN PW_CACHE Cache, // pointer to the Cache Control structure 988 IN PVOID Context, // user's context to be passed to user-supplied 989 // low-level IO routines (IO callbacks) 990 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context 991 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context 992 IN PW_CACHE_ENTRY block_array, // pointer to target Frame 993 IN lba_t firstLba, // LBA of the 1st block in target Frame 994 IN lba_t Lba, // LBA of target Block 995 IN ULONG BSh, // bit shift for Block size 996 IN ULONG BS, // Block size (bytes) 997 IN ULONG PS, // Packet size (bytes) 998 IN ULONG PSs, // Packet size (sectors) 999 IN PSIZE_T ReadBytes, // pointer to number of successfully read/written bytes 1000 IN BOOLEAN PrefereWrite, // allow physical write (flush) of modified packet 1001 IN ULONG State // callers state 1002 ) 1003 { 1004 OSSTATUS status; 1005 PCHAR tmp_buff = Cache->tmp_buff; 1006 PCHAR tmp_buff2 = Cache->tmp_buff; 1007 BOOLEAN mod; 1008 BOOLEAN read; 1009 BOOLEAN zero; 1010 ULONG i; 1011 lba_t Lba0; 1012 PW_CACHE_ASYNC WContext; 1013 BOOLEAN Async = (Cache->ReadProcAsync && Cache->WriteProcAsync); 1014 ULONG block_type; 1015 BOOLEAN Chained = Cache->Chained; 1016 1017 // Check if we are going to write down to disk 1018 // all prewiously prepared (chained) data 1019 if(State == ASYNC_STATE_WRITE) { 1020 WContext = (*PrevWContext); 1021 tmp_buff = (PCHAR)(WContext->Buffer); 1022 tmp_buff2 = (PCHAR)(WContext->Buffer2); 1023 if(!Chained) 1024 mod = (DbgCompareMemory(tmp_buff2, tmp_buff, PS) != PS); 1025 goto try_write; 1026 } 1027 1028 // Check if packet contains modified blocks 1029 // If packet contains non-cached and unchanged, but used 1030 // blocks, it must be read from media before modification 1031 mod = read = zero = FALSE; 1032 Lba0 = Lba - firstLba; 1033 for(i=0; i<PSs; i++, Lba0++) { 1034 if(WCacheGetModFlag(block_array, Lba0)) { 1035 mod = TRUE; 1036 } else if(!WCacheSectorAddr(block_array,Lba0) && 1037 ((block_type = Cache->CheckUsedProc(Context, Lba+i)) & WCACHE_BLOCK_USED) ) { 1038 // 1039 if(block_type & WCACHE_BLOCK_ZERO) { 1040 zero = TRUE; 1041 } else { 1042 read = TRUE; 1043 } 1044 } 1045 } 1046 // check if we are allowed to write to media 1047 if(mod && !PrefereWrite) { 1048 return STATUS_RETRY; 1049 } 1050 // return STATUS_SUCCESS if requested packet contains no modified blocks 1051 if(!mod) { 1052 (*ReadBytes) = PS; 1053 return STATUS_SUCCESS; 1054 } 1055 1056 // pefrorm full update cycle: prepare(optional)/read/modify/write 1057 1058 // do some preparations 1059 if(Chained || Async) { 1060 // For chained and async I/O we allocates context entry 1061 // and add it to list (chain) 1062 // We shall only read data to temporary buffer and 1063 // modify it. Write operations will be invoked later. 1064 // This is introduced in order to avoid frequent 1065 // read.write mode switching, because it significantly degrades 1066 // performance 1067 WContext = WCacheAllocAsyncEntry(Cache, FirstWContext, PrevWContext, PS); 1068 if(!WContext) { 1069 //return STATUS_INSUFFICIENT_RESOURCES; 1070 // try to recover 1071 Chained = FALSE; 1072 Async = FALSE; 1073 } else { 1074 tmp_buff = tmp_buff2 = (PCHAR)(WContext->Buffer); 1075 WContext->Lba = Lba; 1076 WContext->Cmd = ASYNC_CMD_UPDATE; 1077 WContext->State = ASYNC_STATE_NONE; 1078 } 1079 } 1080 1081 // read packet (if it necessary) 1082 if(read) { 1083 if(Async) { 1084 WContext->State = ASYNC_STATE_READ; 1085 status = Cache->ReadProcAsync(Context, WContext, tmp_buff, PS, Lba, 1086 &(WContext->TransferredBytes)); 1087 // tmp_buff2 = (PCHAR)(WContext->Buffer2); 1088 (*ReadBytes) = PS; 1089 return status; 1090 } else { 1091 status = Cache->ReadProc(Context, tmp_buff, PS, Lba, ReadBytes, PH_TMP_BUFFER); 1092 } 1093 if(!OS_SUCCESS(status)) { 1094 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff, WCACHE_R_OP, NULL); 1095 if(!OS_SUCCESS(status)) { 1096 return status; 1097 } 1098 } 1099 } else 1100 if(zero) { 1101 RtlZeroMemory(tmp_buff, PS); 1102 } 1103 1104 if(Chained) { 1105 // indicate that we prepared for writing block to disk 1106 WContext->State = ASYNC_STATE_WRITE_PRE; 1107 tmp_buff2 = tmp_buff; 1108 status = STATUS_SUCCESS; 1109 } 1110 1111 // modify packet 1112 1113 // If we didn't read packet from media, we can't 1114 // perform comparison to assure that packet was really modified. 1115 // Thus, assume that it is modified in this case. 1116 mod = !read || Cache->DoNotCompare; 1117 Lba0 = Lba - firstLba; 1118 for(i=0; i<PSs; i++, Lba0++) { 1119 if( WCacheGetModFlag(block_array, Lba0) || 1120 (!read && WCacheSectorAddr(block_array,Lba0)) ) { 1121 1122 #ifdef _NTDEF_ 1123 ASSERT((ULONG)WCacheSectorAddr(block_array,Lba0) & 0x80000000); 1124 #endif //_NTDEF_ 1125 if(!mod) { 1126 ASSERT(read); 1127 mod = (DbgCompareMemory(tmp_buff2 + (i << BSh), 1128 (PVOID)WCacheSectorAddr(block_array, Lba0), 1129 BS) != BS); 1130 } 1131 if(mod) { 1132 DbgCopyMemory(tmp_buff2 + (i << BSh), 1133 (PVOID)WCacheSectorAddr(block_array, Lba0), 1134 BS); 1135 } 1136 } 1137 } 1138 1139 if(Chained && 1140 WContext->State == ASYNC_STATE_WRITE_PRE) { 1141 // Return if block is prepared for write and we are in chained mode. 1142 if(!mod) { 1143 // Mark block as written if we have found that data in it 1144 // is not actually modified. 1145 WContext->State = ASYNC_STATE_DONE; 1146 (*ReadBytes) = PS; 1147 } 1148 return STATUS_SUCCESS; 1149 } 1150 1151 // write packet 1152 1153 // If the check above reported some changes in packet 1154 // we should write packet out to media. 1155 // Otherwise, just complete request. 1156 if(mod) { 1157 try_write: 1158 if(Async) { 1159 WContext->State = ASYNC_STATE_WRITE; 1160 status = Cache->WriteProcAsync(Context, WContext, tmp_buff2, PS, Lba, 1161 &(WContext->TransferredBytes), FALSE); 1162 (*ReadBytes) = PS; 1163 } else { 1164 status = Cache->WriteProc(Context, tmp_buff2, PS, Lba, ReadBytes, 0); 1165 if(!OS_SUCCESS(status)) { 1166 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff2, WCACHE_W_OP, NULL); 1167 } 1168 } 1169 } else { 1170 if(Async) 1171 WCacheCompleteAsync__(WContext, STATUS_SUCCESS); 1172 (*ReadBytes) = PS; 1173 return STATUS_SUCCESS; 1174 } 1175 1176 return status; 1177 } // end WCacheUpdatePacket() 1178 1179 /* 1180 WCacheFreePacket() releases storage for all Blocks in packet. 1181 'frame' describes Frame, offset - Block in Frame. offset should be 1182 aligned on Packet size. 1183 Internal routine 1184 */ 1185 VOID 1186 WCacheFreePacket( 1187 IN PW_CACHE Cache, // pointer to the Cache Control structure 1188 // IN PVOID Context, 1189 IN ULONG frame, // Frame index 1190 IN PW_CACHE_ENTRY block_array, // Frame 1191 IN ULONG offs, // offset in Frame 1192 IN ULONG PSs // Packet size (in Blocks) 1193 ) 1194 { 1195 ULONG i; 1196 // mark as non-cached & free pool 1197 for(i=0; i<PSs; i++, offs++) { 1198 if(WCacheSectorAddr(block_array,offs)) { 1199 WCacheFreeSector(frame, offs); 1200 } 1201 } 1202 } // end WCacheFreePacket() 1203 1204 /* 1205 WCacheUpdatePacketComplete() is called to continue processing of packet 1206 being updated. 1207 In async mode it waits for completion of pre-read requests, 1208 initiates writes, waits for their completion and returns control to 1209 caller. 1210 Internal routine 1211 */ 1212 VOID 1213 WCacheUpdatePacketComplete( 1214 IN PW_CACHE Cache, // pointer to the Cache Control structure 1215 IN PVOID Context, // user-supplied context for IO callbacks 1216 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context 1217 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context 1218 IN BOOLEAN FreePacket 1219 ) 1220 { 1221 PW_CACHE_ASYNC WContext = (*FirstWContext); 1222 if(!WContext) 1223 return; 1224 PW_CACHE_ASYNC NextWContext; 1225 ULONG PS = Cache->BlockSize << Cache->PacketSizeSh; // packet size (bytes) 1226 ULONG PSs = Cache->PacketSize; 1227 ULONG frame; 1228 lba_t firstLba; 1229 1230 // Walk through all chained blocks and wait 1231 // for completion of read operations. 1232 // Also invoke writes of already prepared packets. 1233 while(WContext) { 1234 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1235 WContext->State == ASYNC_STATE_READ) { 1236 // wait for async read for update 1237 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1238 1239 WContext->State = ASYNC_STATE_WRITE; 1240 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, 1241 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); 1242 } else 1243 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1244 WContext->State == ASYNC_STATE_WRITE_PRE) { 1245 // invoke physical write it the packet is prepared for writing 1246 // by previuous call to WCacheUpdatePacket() 1247 WContext->State = ASYNC_STATE_WRITE; 1248 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, 1249 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); 1250 WContext->State = ASYNC_STATE_DONE; 1251 } else 1252 if(WContext->Cmd == ASYNC_CMD_READ && 1253 WContext->State == ASYNC_STATE_READ) { 1254 // wait for async read 1255 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1256 } 1257 WContext = WContext->NextWContext; 1258 } 1259 // Walk through all chained blocks and wait 1260 // and wait for completion of async writes (if any). 1261 // Also free temporary buffers containing already written blocks. 1262 WContext = (*FirstWContext); 1263 while(WContext) { 1264 NextWContext = WContext->NextWContext; 1265 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1266 WContext->State == ASYNC_STATE_WRITE) { 1267 1268 if(!Cache->Chained) 1269 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1270 1271 frame = WContext->Lba >> Cache->BlocksPerFrameSh; 1272 firstLba = frame << Cache->BlocksPerFrameSh; 1273 1274 if(FreePacket) { 1275 WCacheFreePacket(Cache, frame, 1276 Cache->FrameList[frame].Frame, 1277 WContext->Lba - firstLba, PSs); 1278 } 1279 } 1280 WCacheFreeAsyncEntry(Cache, WContext); 1281 WContext = NextWContext; 1282 } 1283 (*FirstWContext) = NULL; 1284 (*PrevWContext) = NULL; 1285 } // end WCacheUpdatePacketComplete() 1286 1287 /* 1288 WCacheCheckLimits() checks if we've enough free Frame- & 1289 Block-entries under Frame- and Block-limit to feet 1290 requested Blocks. 1291 If there is not enough entries, WCache initiates flush & purge 1292 process to satisfy request. 1293 This is dispatch routine, which calls 1294 WCacheCheckLimitsR() or WCacheCheckLimitsRW() depending on 1295 media type. 1296 Internal routine 1297 */ 1298 OSSTATUS 1299 __fastcall 1300 WCacheCheckLimits( 1301 IN PW_CACHE Cache, // pointer to the Cache Control structure 1302 IN PVOID Context, // user-supplied context for IO callbacks 1303 IN lba_t ReqLba, // first LBA to access/cache 1304 IN ULONG BCount // number of Blocks to access/cache 1305 ) 1306 { 1307 /* if(!Cache->FrameCount || !Cache->BlockCount) { 1308 ASSERT(!Cache->FrameCount); 1309 ASSERT(!Cache->BlockCount); 1310 if(!Cache->FrameCount) 1311 return STATUS_SUCCESS; 1312 }*/ 1313 1314 // check if we have reached Frame or Block limit 1315 if(!Cache->FrameCount && !Cache->BlockCount) { 1316 return STATUS_SUCCESS; 1317 } 1318 1319 // check for empty frames 1320 if(Cache->FrameCount > (Cache->MaxFrames*3)/4) { 1321 ULONG frame; 1322 ULONG i; 1323 for(i=Cache->FrameCount; i>0; i--) { 1324 frame = Cache->CachedFramesList[i-1]; 1325 // check if frame is empty 1326 if(!(Cache->FrameList[frame].BlockCount)) { 1327 WCacheRemoveFrame(Cache, Context, frame); 1328 } else { 1329 ASSERT(Cache->FrameList[frame].Frame); 1330 } 1331 } 1332 } 1333 1334 if(!Cache->BlockCount) { 1335 return STATUS_SUCCESS; 1336 } 1337 1338 // invoke media-specific limit-checker 1339 switch(Cache->Mode) { 1340 case WCACHE_MODE_RAM: 1341 return WCacheCheckLimitsRAM(Cache, Context, ReqLba, BCount); 1342 case WCACHE_MODE_ROM: 1343 case WCACHE_MODE_RW: 1344 return WCacheCheckLimitsRW(Cache, Context, ReqLba, BCount); 1345 case WCACHE_MODE_R: 1346 return WCacheCheckLimitsR(Cache, Context, ReqLba, BCount); 1347 } 1348 return STATUS_DRIVER_INTERNAL_ERROR; 1349 } // end WCacheCheckLimits() 1350 1351 /* 1352 WCacheCheckLimitsRW() implements automatic flush and purge of 1353 unused blocks to keep enough free cache entries for newly 1354 read/written blocks for Random Access and ReWritable media 1355 using Read/Modify/Write technology. 1356 See also WCacheCheckLimits() 1357 Internal routine 1358 */ 1359 OSSTATUS 1360 __fastcall 1361 WCacheCheckLimitsRW( 1362 IN PW_CACHE Cache, // pointer to the Cache Control structure 1363 IN PVOID Context, // user-supplied context for IO callbacks 1364 IN lba_t ReqLba, // first LBA to access/cache 1365 IN ULONG BCount // number of Blocks to access/cache 1366 ) 1367 { 1368 ULONG frame; 1369 lba_t firstLba; 1370 lba_t* List = Cache->CachedBlocksList; 1371 lba_t lastLba; 1372 lba_t Lba; 1373 // PCHAR tmp_buff = Cache->tmp_buff; 1374 ULONG firstPos; 1375 ULONG lastPos; 1376 ULONG BSh = Cache->BlockSizeSh; 1377 ULONG BS = Cache->BlockSize; 1378 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1379 ULONG PSs = Cache->PacketSize; 1380 ULONG try_count = 0; 1381 PW_CACHE_ENTRY block_array; 1382 OSSTATUS status; 1383 SIZE_T ReadBytes; 1384 ULONG FreeFrameCount = 0; 1385 // PVOID addr; 1386 PW_CACHE_ASYNC FirstWContext = NULL; 1387 PW_CACHE_ASYNC PrevWContext = NULL; 1388 ULONG chain_count = 0; 1389 1390 if(Cache->FrameCount >= Cache->MaxFrames) { 1391 FreeFrameCount = Cache->FramesToKeepFree; 1392 } else 1393 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1394 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1395 // we need free space to grow WCache without flushing data 1396 // for some period of time 1397 FreeFrameCount = Cache->FramesToKeepFree; 1398 goto Try_Another_Frame; 1399 } 1400 // remove(flush) some frames 1401 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { 1402 Try_Another_Frame: 1403 if(!Cache->FrameCount || !Cache->BlockCount) { 1404 //ASSERT(!Cache->FrameCount); 1405 if(Cache->FrameCount) { 1406 UDFPrint(("ASSERT: Cache->FrameCount = %d, when 0 is expected\n", Cache->FrameCount)); 1407 } 1408 ASSERT(!Cache->BlockCount); 1409 if(!Cache->FrameCount) 1410 break; 1411 } 1412 1413 frame = WCacheFindFrameToRelease(Cache); 1414 #if 0 1415 if(Cache->FrameList[frame].WriteCount) { 1416 try_count++; 1417 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; 1418 } else { 1419 try_count = 0; 1420 } 1421 #else 1422 if(Cache->FrameList[frame].UpdateCount) { 1423 try_count = MAX_TRIES_FOR_NA; 1424 } else { 1425 try_count = 0; 1426 } 1427 #endif 1428 1429 if(FreeFrameCount) 1430 FreeFrameCount--; 1431 1432 firstLba = frame << Cache->BlocksPerFrameSh; 1433 lastLba = firstLba + Cache->BlocksPerFrame; 1434 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1435 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1436 block_array = Cache->FrameList[frame].Frame; 1437 1438 if(!block_array) { 1439 UDFPrint(("Hmm...\n")); 1440 BrutePoint(); 1441 return STATUS_DRIVER_INTERNAL_ERROR; 1442 } 1443 1444 while(firstPos < lastPos) { 1445 // flush packet 1446 Lba = List[firstPos] & ~(PSs-1); 1447 1448 // write packet out or prepare and add to chain (if chained mode enabled) 1449 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 1450 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 1451 1452 if(status != STATUS_PENDING) { 1453 // free memory 1454 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 1455 } 1456 1457 Lba += PSs; 1458 while((firstPos < lastPos) && (Lba > List[firstPos])) { 1459 firstPos++; 1460 } 1461 chain_count++; 1462 // write chained packets 1463 if(chain_count >= WCACHE_MAX_CHAIN) { 1464 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 1465 chain_count = 0; 1466 } 1467 } 1468 // remove flushed blocks from all lists 1469 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1470 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1471 1472 WCacheRemoveFrame(Cache, Context, frame); 1473 } 1474 1475 // check if we try to read too much data 1476 if(BCount > Cache->MaxBlocks) { 1477 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1478 return STATUS_INVALID_PARAMETER; 1479 } 1480 1481 // remove(flush) packet 1482 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1483 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1484 try_count = 0; 1485 Try_Another_Block: 1486 1487 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); 1488 if(Lba == WCACHE_INVALID_LBA) { 1489 ASSERT(!Cache->FrameCount); 1490 ASSERT(!Cache->BlockCount); 1491 break; 1492 } 1493 frame = Lba >> Cache->BlocksPerFrameSh; 1494 firstLba = frame << Cache->BlocksPerFrameSh; 1495 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 1496 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 1497 block_array = Cache->FrameList[frame].Frame; 1498 if(!block_array) { 1499 // write already prepared blocks to disk and return error 1500 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1501 ASSERT(FALSE); 1502 return STATUS_DRIVER_INTERNAL_ERROR; 1503 } 1504 1505 // write packet out or prepare and add to chain (if chained mode enabled) 1506 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 1507 Lba, BSh, BS, PS, PSs, &ReadBytes, (try_count >= MAX_TRIES_FOR_NA), ASYNC_STATE_NONE); 1508 1509 if(status == STATUS_RETRY) { 1510 try_count++; 1511 goto Try_Another_Block; 1512 } 1513 1514 // free memory 1515 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 1516 1517 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 1518 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 1519 // check if frame is empty 1520 if(!(Cache->FrameList[frame].BlockCount)) { 1521 WCacheRemoveFrame(Cache, Context, frame); 1522 } else { 1523 ASSERT(Cache->FrameList[frame].Frame); 1524 } 1525 chain_count++; 1526 if(chain_count >= WCACHE_MAX_CHAIN) { 1527 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 1528 chain_count = 0; 1529 } 1530 } 1531 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1532 return STATUS_SUCCESS; 1533 } // end WCacheCheckLimitsRW() 1534 1535 OSSTATUS 1536 __fastcall 1537 WCacheFlushBlocksRAM( 1538 IN PW_CACHE Cache, // pointer to the Cache Control structure 1539 IN PVOID Context, // user-supplied context for IO callbacks 1540 PW_CACHE_ENTRY block_array, 1541 lba_t* List, 1542 ULONG firstPos, 1543 ULONG lastPos, 1544 BOOLEAN Purge 1545 ) 1546 { 1547 ULONG frame; 1548 lba_t Lba; 1549 lba_t PrevLba; 1550 lba_t firstLba; 1551 PCHAR tmp_buff = NULL; 1552 ULONG n; 1553 ULONG BSh = Cache->BlockSizeSh; 1554 ULONG BS = Cache->BlockSize; 1555 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1556 ULONG PSs = Cache->PacketSize; 1557 SIZE_T _WrittenBytes; 1558 OSSTATUS status = STATUS_SUCCESS; 1559 1560 frame = List[firstPos] >> Cache->BlocksPerFrameSh; 1561 firstLba = frame << Cache->BlocksPerFrameSh; 1562 1563 while(firstPos < lastPos) { 1564 // flush blocks 1565 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1566 Lba = List[firstPos]; 1567 if(!WCacheGetModFlag(block_array, Lba - firstLba)) { 1568 // free memory 1569 if(Purge) { 1570 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, 1); 1571 } 1572 firstPos++; 1573 continue; 1574 } 1575 tmp_buff = Cache->tmp_buff; 1576 PrevLba = Lba; 1577 n=1; 1578 while((firstPos+n < lastPos) && 1579 (List[firstPos+n] == PrevLba+1)) { 1580 PrevLba++; 1581 if(!WCacheGetModFlag(block_array, PrevLba - firstLba)) 1582 break; 1583 DbgCopyMemory(tmp_buff + (n << BSh), 1584 (PVOID)WCacheSectorAddr(block_array, PrevLba - firstLba), 1585 BS); 1586 n++; 1587 if(n >= PSs) 1588 break; 1589 } 1590 if(n > 1) { 1591 DbgCopyMemory(tmp_buff, 1592 (PVOID)WCacheSectorAddr(block_array, Lba - firstLba), 1593 BS); 1594 } else { 1595 tmp_buff = (PCHAR)WCacheSectorAddr(block_array, Lba - firstLba); 1596 } 1597 // write sectors out 1598 status = Cache->WriteProc(Context, tmp_buff, n<<BSh, Lba, &_WrittenBytes, 0); 1599 if(!OS_SUCCESS(status)) { 1600 status = WCacheRaiseIoError(Cache, Context, status, Lba, n, tmp_buff, WCACHE_W_OP, NULL); 1601 if(!OS_SUCCESS(status)) { 1602 BrutePoint(); 1603 } 1604 } 1605 firstPos += n; 1606 if(Purge) { 1607 // free memory 1608 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, n); 1609 } else { 1610 // clear Modified flag 1611 ULONG i; 1612 Lba -= firstLba; 1613 for(i=0; i<n; i++) { 1614 WCacheClrModFlag(block_array, Lba+i); 1615 } 1616 } 1617 } 1618 1619 return status; 1620 } // end WCacheFlushBlocksRAM() 1621 1622 /* 1623 WCacheCheckLimitsRAM() implements automatic flush and purge of 1624 unused blocks to keep enough free cache entries for newly 1625 read/written blocks for Random Access media. 1626 See also WCacheCheckLimits() 1627 Internal routine 1628 */ 1629 OSSTATUS 1630 __fastcall 1631 WCacheCheckLimitsRAM( 1632 IN PW_CACHE Cache, // pointer to the Cache Control structure 1633 IN PVOID Context, // user-supplied context for IO callbacks 1634 IN lba_t ReqLba, // first LBA to access/cache 1635 IN ULONG BCount // number of Blocks to access/cache 1636 ) 1637 { 1638 ULONG frame; 1639 lba_t firstLba; 1640 lba_t* List = Cache->CachedBlocksList; 1641 lba_t lastLba; 1642 lba_t Lba; 1643 // PCHAR tmp_buff = Cache->tmp_buff; 1644 ULONG firstPos; 1645 ULONG lastPos; 1646 // ULONG BSh = Cache->BlockSizeSh; 1647 // ULONG BS = Cache->BlockSize; 1648 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1649 ULONG PSs = Cache->PacketSize; 1650 // ULONG try_count = 0; 1651 PW_CACHE_ENTRY block_array; 1652 // OSSTATUS status; 1653 ULONG FreeFrameCount = 0; 1654 // PVOID addr; 1655 1656 if(Cache->FrameCount >= Cache->MaxFrames) { 1657 FreeFrameCount = Cache->FramesToKeepFree; 1658 } else 1659 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1660 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1661 // we need free space to grow WCache without flushing data 1662 // for some period of time 1663 FreeFrameCount = Cache->FramesToKeepFree; 1664 goto Try_Another_Frame; 1665 } 1666 // remove(flush) some frames 1667 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { 1668 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1669 Try_Another_Frame: 1670 if(!Cache->FrameCount || !Cache->BlockCount) { 1671 ASSERT(!Cache->FrameCount); 1672 ASSERT(!Cache->BlockCount); 1673 if(!Cache->FrameCount) 1674 break; 1675 } 1676 1677 frame = WCacheFindFrameToRelease(Cache); 1678 #if 0 1679 if(Cache->FrameList[frame].WriteCount) { 1680 try_count++; 1681 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; 1682 } else { 1683 try_count = 0; 1684 } 1685 #else 1686 /* 1687 if(Cache->FrameList[frame].UpdateCount) { 1688 try_count = MAX_TRIES_FOR_NA; 1689 } else { 1690 try_count = 0; 1691 } 1692 */ 1693 #endif 1694 1695 if(FreeFrameCount) 1696 FreeFrameCount--; 1697 1698 firstLba = frame << Cache->BlocksPerFrameSh; 1699 lastLba = firstLba + Cache->BlocksPerFrame; 1700 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1701 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1702 block_array = Cache->FrameList[frame].Frame; 1703 1704 if(!block_array) { 1705 UDFPrint(("Hmm...\n")); 1706 BrutePoint(); 1707 return STATUS_DRIVER_INTERNAL_ERROR; 1708 } 1709 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1710 1711 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1712 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1713 WCacheRemoveFrame(Cache, Context, frame); 1714 } 1715 1716 // check if we try to read too much data 1717 if(BCount > Cache->MaxBlocks) { 1718 return STATUS_INVALID_PARAMETER; 1719 } 1720 1721 // remove(flush) packet 1722 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1723 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1724 // try_count = 0; 1725 //Try_Another_Block: 1726 1727 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1728 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); 1729 if(Lba == WCACHE_INVALID_LBA) { 1730 ASSERT(!Cache->FrameCount); 1731 ASSERT(!Cache->BlockCount); 1732 break; 1733 } 1734 frame = Lba >> Cache->BlocksPerFrameSh; 1735 firstLba = frame << Cache->BlocksPerFrameSh; 1736 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 1737 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 1738 block_array = Cache->FrameList[frame].Frame; 1739 if(!block_array) { 1740 ASSERT(FALSE); 1741 return STATUS_DRIVER_INTERNAL_ERROR; 1742 } 1743 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1744 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 1745 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 1746 // check if frame is empty 1747 if(!(Cache->FrameList[frame].BlockCount)) { 1748 WCacheRemoveFrame(Cache, Context, frame); 1749 } else { 1750 ASSERT(Cache->FrameList[frame].Frame); 1751 } 1752 } 1753 return STATUS_SUCCESS; 1754 } // end WCacheCheckLimitsRAM() 1755 1756 /* 1757 WCachePurgeAllRAM() 1758 Internal routine 1759 */ 1760 OSSTATUS 1761 __fastcall 1762 WCachePurgeAllRAM( 1763 IN PW_CACHE Cache, // pointer to the Cache Control structure 1764 IN PVOID Context // user-supplied context for IO callbacks 1765 ) 1766 { 1767 ULONG frame; 1768 lba_t firstLba; 1769 lba_t* List = Cache->CachedBlocksList; 1770 lba_t lastLba; 1771 ULONG firstPos; 1772 ULONG lastPos; 1773 PW_CACHE_ENTRY block_array; 1774 // OSSTATUS status; 1775 1776 // remove(flush) some frames 1777 while(Cache->FrameCount) { 1778 1779 frame = Cache->CachedFramesList[0]; 1780 1781 firstLba = frame << Cache->BlocksPerFrameSh; 1782 lastLba = firstLba + Cache->BlocksPerFrame; 1783 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1784 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1785 block_array = Cache->FrameList[frame].Frame; 1786 1787 if(!block_array) { 1788 UDFPrint(("Hmm...\n")); 1789 BrutePoint(); 1790 return STATUS_DRIVER_INTERNAL_ERROR; 1791 } 1792 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1793 1794 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1795 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1796 WCacheRemoveFrame(Cache, Context, frame); 1797 } 1798 1799 ASSERT(!Cache->FrameCount); 1800 ASSERT(!Cache->BlockCount); 1801 return STATUS_SUCCESS; 1802 } // end WCachePurgeAllRAM() 1803 1804 /* 1805 WCacheFlushAllRAM() 1806 Internal routine 1807 */ 1808 OSSTATUS 1809 __fastcall 1810 WCacheFlushAllRAM( 1811 IN PW_CACHE Cache, // pointer to the Cache Control structure 1812 IN PVOID Context // user-supplied context for IO callbacks 1813 ) 1814 { 1815 ULONG frame; 1816 lba_t firstLba; 1817 lba_t* List = Cache->CachedBlocksList; 1818 lba_t lastLba; 1819 ULONG firstPos; 1820 ULONG lastPos; 1821 PW_CACHE_ENTRY block_array; 1822 // OSSTATUS status; 1823 1824 // flush frames 1825 while(Cache->WriteCount) { 1826 1827 frame = Cache->CachedModifiedBlocksList[0] >> Cache->BlocksPerFrameSh; 1828 1829 firstLba = frame << Cache->BlocksPerFrameSh; 1830 lastLba = firstLba + Cache->BlocksPerFrame; 1831 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1832 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1833 block_array = Cache->FrameList[frame].Frame; 1834 1835 if(!block_array) { 1836 UDFPrint(("Hmm...\n")); 1837 BrutePoint(); 1838 return STATUS_DRIVER_INTERNAL_ERROR; 1839 } 1840 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, FALSE); 1841 1842 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1843 } 1844 1845 return STATUS_SUCCESS; 1846 } // end WCacheFlushAllRAM() 1847 1848 /* 1849 WCachePreReadPacket__() reads & caches the whole packet containing 1850 requested LBA. This routine just caches data, it doesn't copy anything 1851 to user buffer. 1852 In general we have no user buffer here... ;) 1853 Public routine 1854 */ 1855 OSSTATUS 1856 WCachePreReadPacket__( 1857 IN PW_CACHE Cache, // pointer to the Cache Control structure 1858 IN PVOID Context, // user-supplied context for IO callbacks 1859 IN lba_t Lba // LBA to cache together with whole packet 1860 ) 1861 { 1862 ULONG frame; 1863 OSSTATUS status = STATUS_SUCCESS; 1864 PW_CACHE_ENTRY block_array; 1865 ULONG BSh = Cache->BlockSizeSh; 1866 ULONG BS = Cache->BlockSize; 1867 PCHAR addr; 1868 SIZE_T _ReadBytes; 1869 ULONG PS = Cache->PacketSize; // (in blocks) 1870 ULONG BCount = PS; 1871 ULONG i, n, err_count; 1872 BOOLEAN sector_added = FALSE; 1873 ULONG block_type; 1874 BOOLEAN zero = FALSE;//TRUE; 1875 /* 1876 ULONG first_zero=0, last_zero=0; 1877 BOOLEAN count_first_zero = TRUE; 1878 */ 1879 1880 Lba &= ~(PS-1); 1881 frame = Lba >> Cache->BlocksPerFrameSh; 1882 i = Lba - (frame << Cache->BlocksPerFrameSh); 1883 1884 // assume successful operation 1885 block_array = Cache->FrameList[frame].Frame; 1886 if(!block_array) { 1887 ASSERT(Cache->FrameCount < Cache->MaxFrames); 1888 block_array = WCacheInitFrame(Cache, Context, frame); 1889 if(!block_array) 1890 return STATUS_INSUFFICIENT_RESOURCES; 1891 } 1892 1893 // skip cached extent (if any) 1894 n=0; 1895 while((n < BCount) && 1896 (n < Cache->BlocksPerFrame)) { 1897 1898 addr = (PCHAR)WCacheSectorAddr(block_array, i+n); 1899 block_type = Cache->CheckUsedProc(Context, Lba+n); 1900 if(/*WCacheGetBadFlag(block_array,i+n)*/ 1901 block_type & WCACHE_BLOCK_BAD) { 1902 // bad packet. no pre-read 1903 return STATUS_DEVICE_DATA_ERROR; 1904 } 1905 if(!(block_type & WCACHE_BLOCK_ZERO)) { 1906 zero = FALSE; 1907 //count_first_zero = FALSE; 1908 //last_zero = 0; 1909 if(!addr) { 1910 // sector is not cached, stop search 1911 break; 1912 } 1913 } else { 1914 /* 1915 if(count_first_zero) { 1916 first_zero++; 1917 } 1918 last_zero++; 1919 */ 1920 } 1921 n++; 1922 } 1923 // do nothing if all sectors are already cached 1924 if(n < BCount) { 1925 1926 // read whole packet 1927 if(!zero) { 1928 status = Cache->ReadProc(Context, Cache->tmp_buff_r, PS<<BSh, Lba, &_ReadBytes, PH_TMP_BUFFER); 1929 if(!OS_SUCCESS(status)) { 1930 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Cache->tmp_buff_r, WCACHE_R_OP, NULL); 1931 } 1932 } else { 1933 status = STATUS_SUCCESS; 1934 //RtlZeroMemory(Cache->tmp_buff_r, PS<<BSh); 1935 _ReadBytes = PS<<BSh; 1936 } 1937 if(OS_SUCCESS(status)) { 1938 // and now we'll copy them to cache 1939 for(n=0; n<BCount; n++, i++) { 1940 if(WCacheSectorAddr(block_array,i)) { 1941 continue; 1942 } 1943 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 1944 if(!addr) { 1945 BrutePoint(); 1946 break; 1947 } 1948 sector_added = TRUE; 1949 if(!zero) { 1950 DbgCopyMemory(addr, Cache->tmp_buff_r+(n<<BSh), BS); 1951 } else { 1952 RtlZeroMemory(addr, BS); 1953 } 1954 Cache->FrameList[frame].BlockCount++; 1955 } 1956 } else { 1957 // read sectors one by one and copy them to cache 1958 // unreadable sectors will be treated as zero-filled 1959 err_count = 0; 1960 for(n=0; n<BCount; n++, i++) { 1961 if(WCacheSectorAddr(block_array,i)) { 1962 continue; 1963 } 1964 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 1965 if(!addr) { 1966 BrutePoint(); 1967 break; 1968 } 1969 sector_added = TRUE; 1970 status = Cache->ReadProc(Context, Cache->tmp_buff_r, BS, Lba+n, &_ReadBytes, PH_TMP_BUFFER); 1971 if(!OS_SUCCESS(status)) { 1972 status = WCacheRaiseIoError(Cache, Context, status, Lba+n, 1, Cache->tmp_buff_r, WCACHE_R_OP, NULL); 1973 if(!OS_SUCCESS(status)) { 1974 err_count++; 1975 } 1976 } 1977 if(!zero && OS_SUCCESS(status)) { 1978 DbgCopyMemory(addr, Cache->tmp_buff_r, BS); 1979 } else 1980 if(Cache->RememberBB) { 1981 RtlZeroMemory(addr, BS); 1982 /* 1983 if(!OS_SUCCESS(status)) { 1984 WCacheSetBadFlag(block_array,i); 1985 } 1986 */ 1987 } 1988 Cache->FrameList[frame].BlockCount++; 1989 if(err_count >= 2) { 1990 break; 1991 } 1992 } 1993 // _ReadBytes = n<<BSh; 1994 } 1995 } 1996 1997 // we know the number of unread sectors if an error occured 1998 // so we can need to update BlockCount 1999 // return number of read bytes 2000 if(sector_added) 2001 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, n); 2002 2003 return status; 2004 } // end WCachePreReadPacket__() 2005 2006 /* 2007 WCacheReadBlocks__() reads data from cache or 2008 read it form media and store in cache. 2009 Public routine 2010 */ 2011 OSSTATUS 2012 WCacheReadBlocks__( 2013 IN PW_CACHE Cache, // pointer to the Cache Control structure 2014 IN PVOID Context, // user-supplied context for IO callbacks 2015 IN PCHAR Buffer, // user-supplied buffer for read blocks 2016 IN lba_t Lba, // LBA to start read from 2017 IN ULONG BCount, // number of blocks to be read 2018 OUT PSIZE_T ReadBytes, // user-supplied pointer to ULONG that will 2019 // recieve number of actually read bytes 2020 IN BOOLEAN CachedOnly // specifies that cache is already locked 2021 ) 2022 { 2023 ULONG frame; 2024 ULONG i, saved_i, saved_BC = BCount, n; 2025 OSSTATUS status = STATUS_SUCCESS; 2026 PW_CACHE_ENTRY block_array; 2027 ULONG BSh = Cache->BlockSizeSh; 2028 SIZE_T BS = Cache->BlockSize; 2029 PCHAR addr; 2030 ULONG to_read, saved_to_read; 2031 // PCHAR saved_buff = Buffer; 2032 SIZE_T _ReadBytes; 2033 ULONG PS = Cache->PacketSize; 2034 ULONG MaxR = Cache->MaxBytesToRead; 2035 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n 2036 ULONG d; 2037 ULONG block_type; 2038 2039 WcPrint(("WC:R %x (%x)\n", Lba, BCount)); 2040 2041 (*ReadBytes) = 0; 2042 // check if we try to read too much data 2043 if(BCount >= Cache->MaxBlocks) { 2044 i = 0; 2045 if(CachedOnly) { 2046 status = STATUS_INVALID_PARAMETER; 2047 goto EO_WCache_R2; 2048 } 2049 while(TRUE) { 2050 status = WCacheReadBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, PS, &_ReadBytes, FALSE); 2051 (*ReadBytes) += _ReadBytes; 2052 if(!OS_SUCCESS(status) || (BCount <= PS)) break; 2053 BCount -= PS; 2054 Lba += PS; 2055 i += PS; 2056 } 2057 return status; 2058 } 2059 // check if we try to access beyond cached area 2060 if((Lba < Cache->FirstLba) || 2061 (Lba + BCount - 1 > Cache->LastLba)) { 2062 status = Cache->ReadProc(Context, Buffer, BCount, Lba, ReadBytes, 0); 2063 if(!OS_SUCCESS(status)) { 2064 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_R_OP, NULL); 2065 } 2066 return status; 2067 } 2068 if(!CachedOnly) { 2069 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2070 } 2071 2072 frame = Lba >> Cache->BlocksPerFrameSh; 2073 i = Lba - (frame << Cache->BlocksPerFrameSh); 2074 2075 if(Cache->CacheWholePacket && (BCount < PS)) { 2076 if(!CachedOnly && 2077 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba & ~(PS-1), PS*2)) ) { 2078 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2079 return status; 2080 } 2081 } else { 2082 if(!CachedOnly && 2083 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { 2084 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2085 return status; 2086 } 2087 } 2088 if(!CachedOnly) { 2089 // convert to shared 2090 // ExConvertExclusiveToSharedLite(&(Cache->WCacheLock)); 2091 } 2092 2093 // pre-read packet. It is very useful for 2094 // highly fragmented files 2095 if(Cache->CacheWholePacket && (BCount < PS)) { 2096 // status = WCacheReadBlocks__(Cache, Context, Cache->tmp_buff_r, Lba & (~PacketMask), PS, &_ReadBytes, TRUE); 2097 // we should not perform IO if user requested CachedOnly data 2098 if(!CachedOnly) { 2099 status = WCachePreReadPacket__(Cache, Context, Lba); 2100 } 2101 status = STATUS_SUCCESS; 2102 } 2103 2104 // assume successful operation 2105 block_array = Cache->FrameList[frame].Frame; 2106 if(!block_array) { 2107 ASSERT(!CachedOnly); 2108 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2109 block_array = WCacheInitFrame(Cache, Context, frame); 2110 if(!block_array) { 2111 status = STATUS_INSUFFICIENT_RESOURCES; 2112 goto EO_WCache_R; 2113 } 2114 } 2115 2116 Cache->FrameList[frame].AccessCount++; 2117 while(BCount) { 2118 if(i >= Cache->BlocksPerFrame) { 2119 frame++; 2120 block_array = Cache->FrameList[frame].Frame; 2121 i -= Cache->BlocksPerFrame; 2122 } 2123 if(!block_array) { 2124 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2125 block_array = WCacheInitFrame(Cache, Context, frame); 2126 if(!block_array) { 2127 status = STATUS_INSUFFICIENT_RESOURCES; 2128 goto EO_WCache_R; 2129 } 2130 } 2131 // 'read' cached extent (if any) 2132 // it is just copying 2133 while(BCount && 2134 (i < Cache->BlocksPerFrame) && 2135 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 2136 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); 2137 if(block_type & WCACHE_BLOCK_BAD) { 2138 //if(WCacheGetBadFlag(block_array,i)) { 2139 status = STATUS_DEVICE_DATA_ERROR; 2140 goto EO_WCache_R; 2141 } 2142 DbgCopyMemory(Buffer, addr, BS); 2143 Buffer += BS; 2144 *ReadBytes += BS; 2145 i++; 2146 BCount--; 2147 } 2148 // read non-cached packet-size-aligned extent (if any) 2149 // now we'll calculate total length & decide if it has enough size 2150 if(!((d = Lba+saved_BC-BCount) & PacketMask) && d ) { 2151 n = 0; 2152 while(BCount && 2153 (i < Cache->BlocksPerFrame) && 2154 (!WCacheSectorAddr(block_array, i)) ) { 2155 n++; 2156 BCount--; 2157 } 2158 BCount += n; 2159 n &= ~PacketMask; 2160 if(n>PS) { 2161 if(!OS_SUCCESS(status = Cache->ReadProc(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_ReadBytes, 0))) { 2162 status = WCacheRaiseIoError(Cache, Context, status, Lba+saved_BC-BCount, n, Buffer, WCACHE_R_OP, NULL); 2163 if(!OS_SUCCESS(status)) { 2164 goto EO_WCache_R; 2165 } 2166 } 2167 // WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2168 BCount -= n; 2169 Lba += saved_BC - BCount; 2170 saved_BC = BCount; 2171 i += n; 2172 Buffer += BS*n; 2173 *ReadBytes += BS*n; 2174 } 2175 // } else { 2176 // UDFPrint(("Unaligned\n")); 2177 } 2178 // read non-cached extent (if any) 2179 // firstable, we'll get total number of sectors to read 2180 to_read = 0; 2181 saved_i = i; 2182 d = BCount; 2183 while(d && 2184 (i < Cache->BlocksPerFrame) && 2185 (!WCacheSectorAddr(block_array, i)) ) { 2186 i++; 2187 to_read += BS; 2188 d--; 2189 } 2190 // read some not cached sectors 2191 if(to_read) { 2192 i = saved_i; 2193 saved_to_read = to_read; 2194 d = BCount - d; 2195 // split request if necessary 2196 if(saved_to_read > MaxR) { 2197 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2198 n = MaxR >> BSh; 2199 do { 2200 status = Cache->ReadProc(Context, Buffer, MaxR, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); 2201 *ReadBytes += _ReadBytes; 2202 if(!OS_SUCCESS(status)) { 2203 _ReadBytes &= ~(BS-1); 2204 BCount -= _ReadBytes >> BSh; 2205 saved_to_read -= _ReadBytes; 2206 Buffer += _ReadBytes; 2207 saved_BC = BCount; 2208 goto store_read_data_1; 2209 } 2210 Buffer += MaxR; 2211 saved_to_read -= MaxR; 2212 i += n; 2213 BCount -= n; 2214 d -= n; 2215 } while(saved_to_read > MaxR); 2216 saved_BC = BCount; 2217 } 2218 if(saved_to_read) { 2219 status = Cache->ReadProc(Context, Buffer, saved_to_read, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); 2220 *ReadBytes += _ReadBytes; 2221 if(!OS_SUCCESS(status)) { 2222 _ReadBytes &= ~(BS-1); 2223 BCount -= _ReadBytes >> BSh; 2224 saved_to_read -= _ReadBytes; 2225 Buffer += _ReadBytes; 2226 goto store_read_data_1; 2227 } 2228 Buffer += saved_to_read; 2229 saved_to_read = 0; 2230 BCount -= d; 2231 } 2232 2233 store_read_data_1: 2234 // and now we'll copy them to cache 2235 2236 // 2237 Buffer -= (to_read - saved_to_read); 2238 i = saved_i; 2239 while(to_read - saved_to_read) { 2240 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2241 if(!block_array[i].Sector) { 2242 BCount += to_read >> BSh; 2243 status = STATUS_INSUFFICIENT_RESOURCES; 2244 goto EO_WCache_R; 2245 } 2246 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2247 Cache->FrameList[frame].BlockCount++; 2248 i++; 2249 Buffer += BS; 2250 to_read -= BS; 2251 } 2252 if(!OS_SUCCESS(status)) 2253 goto EO_WCache_R; 2254 to_read = 0; 2255 } 2256 } 2257 2258 EO_WCache_R: 2259 2260 // we know the number of unread sectors if an error occured 2261 // so we can need to update BlockCount 2262 // return number of read bytes 2263 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2264 // Cache->FrameList[frame].BlockCount -= BCount; 2265 EO_WCache_R2: 2266 if(!CachedOnly) { 2267 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2268 } 2269 2270 return status; 2271 } // end WCacheReadBlocks__() 2272 2273 /* 2274 WCacheWriteBlocks__() writes data to cache. 2275 Data is written directly to media if: 2276 1) requested block is Packet-aligned 2277 2) requested Lba(s) lays beyond cached area 2278 Public routine 2279 */ 2280 OSSTATUS 2281 WCacheWriteBlocks__( 2282 IN PW_CACHE Cache, // pointer to the Cache Control structure 2283 IN PVOID Context, // user-supplied context for IO callbacks 2284 IN PCHAR Buffer, // user-supplied buffer containing data to be written 2285 IN lba_t Lba, // LBA to start write from 2286 IN ULONG BCount, // number of blocks to be written 2287 OUT PSIZE_T WrittenBytes, // user-supplied pointer to ULONG that will 2288 // recieve number of actually written bytes 2289 IN BOOLEAN CachedOnly // specifies that cache is already locked 2290 ) 2291 { 2292 ULONG frame; 2293 ULONG i, saved_BC = BCount, n, d; 2294 OSSTATUS status = STATUS_SUCCESS; 2295 PW_CACHE_ENTRY block_array; 2296 ULONG BSh = Cache->BlockSizeSh; 2297 ULONG BS = Cache->BlockSize; 2298 PCHAR addr; 2299 // PCHAR saved_buff = Buffer; 2300 SIZE_T _WrittenBytes; 2301 ULONG PS = Cache->PacketSize; 2302 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n 2303 ULONG block_type; 2304 // BOOLEAN Aligned = FALSE; 2305 2306 BOOLEAN WriteThrough = FALSE; 2307 lba_t WTh_Lba; 2308 ULONG WTh_BCount; 2309 2310 WcPrint(("WC:W %x (%x)\n", Lba, BCount)); 2311 2312 *WrittenBytes = 0; 2313 // UDFPrint(("BCount:%x\n",BCount)); 2314 // check if we try to read too much data 2315 if(BCount >= Cache->MaxBlocks) { 2316 i = 0; 2317 if(CachedOnly) { 2318 status = STATUS_INVALID_PARAMETER; 2319 goto EO_WCache_W2; 2320 } 2321 while(TRUE) { 2322 // UDFPrint((" BCount:%x\n",BCount)); 2323 status = WCacheWriteBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, min(PS,BCount), &_WrittenBytes, FALSE); 2324 (*WrittenBytes) += _WrittenBytes; 2325 BCount -= PS; 2326 Lba += PS; 2327 i += PS; 2328 if(!OS_SUCCESS(status) || (BCount < PS)) 2329 return status; 2330 } 2331 } 2332 // check if we try to access beyond cached area 2333 if((Lba < Cache->FirstLba) || 2334 (Lba + BCount - 1 > Cache->LastLba)) { 2335 return STATUS_INVALID_PARAMETER; 2336 } 2337 if(!CachedOnly) { 2338 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2339 } 2340 2341 frame = Lba >> Cache->BlocksPerFrameSh; 2342 i = Lba - (frame << Cache->BlocksPerFrameSh); 2343 2344 if(!CachedOnly && 2345 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { 2346 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2347 return status; 2348 } 2349 2350 // assume successful operation 2351 block_array = Cache->FrameList[frame].Frame; 2352 if(!block_array) { 2353 2354 if(BCount && !(BCount & (PS-1)) && !(Lba & (PS-1)) && 2355 (Cache->Mode != WCACHE_MODE_R) && 2356 (i+BCount <= Cache->BlocksPerFrame) && 2357 !Cache->NoWriteThrough) { 2358 status = Cache->WriteProc(Context, Buffer, BCount<<BSh, Lba, WrittenBytes, 0); 2359 if(!OS_SUCCESS(status)) { 2360 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_W_OP, NULL); 2361 } 2362 goto EO_WCache_W2; 2363 } 2364 2365 ASSERT(!CachedOnly); 2366 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2367 block_array = WCacheInitFrame(Cache, Context, frame); 2368 if(!block_array) { 2369 status = STATUS_INSUFFICIENT_RESOURCES; 2370 goto EO_WCache_W; 2371 } 2372 } 2373 2374 if(Cache->Mode == WCACHE_MODE_RAM && 2375 BCount && 2376 // !(Lba & (PS-1)) && 2377 (!(BCount & (PS-1)) || (BCount > PS)) ) { 2378 WriteThrough = TRUE; 2379 WTh_Lba = Lba; 2380 WTh_BCount = BCount; 2381 } else 2382 if(Cache->Mode == WCACHE_MODE_RAM && 2383 ((Lba & ~PacketMask) != ((Lba+BCount-1) & ~PacketMask)) 2384 ) { 2385 WriteThrough = TRUE; 2386 WTh_Lba = Lba & ~PacketMask; 2387 WTh_BCount = PS; 2388 } 2389 2390 Cache->FrameList[frame].UpdateCount++; 2391 // UDFPrint((" BCount:%x\n",BCount)); 2392 while(BCount) { 2393 if(i >= Cache->BlocksPerFrame) { 2394 frame++; 2395 block_array = Cache->FrameList[frame].Frame; 2396 i -= Cache->BlocksPerFrame; 2397 } 2398 if(!block_array) { 2399 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2400 block_array = WCacheInitFrame(Cache, Context, frame); 2401 if(!block_array) { 2402 status = STATUS_INSUFFICIENT_RESOURCES; 2403 goto EO_WCache_W; 2404 } 2405 } 2406 // 'write' cached extent (if any) 2407 // it is just copying 2408 while(BCount && 2409 (i < Cache->BlocksPerFrame) && 2410 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 2411 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",addr, Buffer, BS, BCount)); 2412 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); 2413 if(Cache->NoWriteBB && 2414 /*WCacheGetBadFlag(block_array,i)*/ 2415 (block_type & WCACHE_BLOCK_BAD)) { 2416 // bad packet. no cached write 2417 status = STATUS_DEVICE_DATA_ERROR; 2418 goto EO_WCache_W; 2419 } 2420 DbgCopyMemory(addr, Buffer, BS); 2421 WCacheSetModFlag(block_array, i); 2422 Buffer += BS; 2423 *WrittenBytes += BS; 2424 i++; 2425 BCount--; 2426 } 2427 // write non-cached not-aligned extent (if any) till aligned one 2428 while(BCount && 2429 (i & PacketMask) && 2430 (Cache->Mode != WCACHE_MODE_R) && 2431 (i < Cache->BlocksPerFrame) && 2432 (!WCacheSectorAddr(block_array, i)) ) { 2433 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2434 if(!block_array[i].Sector) { 2435 status = STATUS_INSUFFICIENT_RESOURCES; 2436 goto EO_WCache_W; 2437 } 2438 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); 2439 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2440 WCacheSetModFlag(block_array, i); 2441 i++; 2442 Buffer += BS; 2443 *WrittenBytes += BS; 2444 BCount--; 2445 Cache->FrameList[frame].BlockCount ++; 2446 } 2447 // write non-cached packet-size-aligned extent (if any) 2448 // now we'll calculate total length & decide if has enough size 2449 if(!Cache->NoWriteThrough 2450 && 2451 ( !(i & PacketMask) || 2452 ((Cache->Mode == WCACHE_MODE_R) && (BCount >= PS)) )) { 2453 n = 0; 2454 while(BCount && 2455 (i < Cache->BlocksPerFrame) && 2456 (!WCacheSectorAddr(block_array, i)) ) { 2457 n++; 2458 BCount--; 2459 } 2460 BCount += n; 2461 n &= ~PacketMask; 2462 // if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE))) 2463 if(n) { 2464 // add previously written data to list 2465 d = saved_BC - BCount; 2466 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, d); 2467 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); 2468 Lba += d; 2469 saved_BC = BCount; 2470 2471 while(n) { 2472 if(Cache->Mode == WCACHE_MODE_R) 2473 Cache->UpdateRelocProc(Context, Lba, NULL, PS); 2474 if(!OS_SUCCESS(status = Cache->WriteProc(Context, Buffer, PS<<BSh, Lba, &_WrittenBytes, 0))) { 2475 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Buffer, WCACHE_W_OP, NULL); 2476 if(!OS_SUCCESS(status)) { 2477 goto EO_WCache_W; 2478 } 2479 } 2480 BCount -= PS; 2481 Lba += PS; 2482 saved_BC = BCount; 2483 i += PS; 2484 Buffer += PS<<BSh; 2485 *WrittenBytes += PS<<BSh; 2486 n-=PS; 2487 } 2488 } 2489 } 2490 // write non-cached not-aligned extent (if any) 2491 while(BCount && 2492 (i < Cache->BlocksPerFrame) && 2493 (!WCacheSectorAddr(block_array, i)) ) { 2494 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2495 if(!block_array[i].Sector) { 2496 status = STATUS_INSUFFICIENT_RESOURCES; 2497 goto EO_WCache_W; 2498 } 2499 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); 2500 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2501 WCacheSetModFlag(block_array, i); 2502 i++; 2503 Buffer += BS; 2504 *WrittenBytes += BS; 2505 BCount--; 2506 Cache->FrameList[frame].BlockCount ++; 2507 } 2508 } 2509 2510 EO_WCache_W: 2511 2512 // we know the number of unread sectors if an error occured 2513 // so we can need to update BlockCount 2514 // return number of read bytes 2515 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2516 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, saved_BC - BCount); 2517 2518 if(WriteThrough && !BCount) { 2519 ULONG d; 2520 // lba_t lastLba; 2521 ULONG firstPos; 2522 ULONG lastPos; 2523 2524 BCount = WTh_BCount; 2525 Lba = WTh_Lba; 2526 while(BCount) { 2527 frame = Lba >> Cache->BlocksPerFrameSh; 2528 // firstLba = frame << Cache->BlocksPerFrameSh; 2529 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba); 2530 d = min(Lba+BCount, (frame+1) << Cache->BlocksPerFrameSh) - Lba; 2531 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba+d); 2532 block_array = Cache->FrameList[frame].Frame; 2533 if(!block_array) { 2534 ASSERT(FALSE); 2535 BCount -= d; 2536 Lba += d; 2537 continue; 2538 } 2539 status = WCacheFlushBlocksRAM(Cache, Context, block_array, Cache->CachedBlocksList, firstPos, lastPos, FALSE); 2540 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); 2541 BCount -= d; 2542 Lba += d; 2543 } 2544 } 2545 2546 EO_WCache_W2: 2547 2548 if(!CachedOnly) { 2549 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2550 } 2551 return status; 2552 } // end WCacheWriteBlocks__() 2553 2554 /* 2555 WCacheFlushAll__() copies all data stored in cache to media. 2556 Flushed blocks are kept in cache. 2557 Public routine 2558 */ 2559 VOID 2560 WCacheFlushAll__( 2561 IN PW_CACHE Cache, // pointer to the Cache Control structure 2562 IN PVOID Context) // user-supplied context for IO callbacks 2563 { 2564 if(!(Cache->ReadProc)) return; 2565 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2566 2567 switch(Cache->Mode) { 2568 case WCACHE_MODE_RAM: 2569 WCacheFlushAllRAM(Cache, Context); 2570 break; 2571 case WCACHE_MODE_ROM: 2572 case WCACHE_MODE_RW: 2573 WCacheFlushAllRW(Cache, Context); 2574 break; 2575 case WCACHE_MODE_R: 2576 WCachePurgeAllR(Cache, Context); 2577 break; 2578 } 2579 2580 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2581 return; 2582 } // end WCacheFlushAll__() 2583 2584 /* 2585 WCachePurgeAll__() copies all data stored in cache to media. 2586 Flushed blocks are removed cache. 2587 Public routine 2588 */ 2589 VOID 2590 WCachePurgeAll__( 2591 IN PW_CACHE Cache, // pointer to the Cache Control structure 2592 IN PVOID Context) // user-supplied context for IO callbacks 2593 { 2594 if(!(Cache->ReadProc)) return; 2595 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2596 2597 switch(Cache->Mode) { 2598 case WCACHE_MODE_RAM: 2599 WCachePurgeAllRAM(Cache, Context); 2600 break; 2601 case WCACHE_MODE_ROM: 2602 case WCACHE_MODE_RW: 2603 WCachePurgeAllRW(Cache, Context); 2604 break; 2605 case WCACHE_MODE_R: 2606 WCachePurgeAllR(Cache, Context); 2607 break; 2608 } 2609 2610 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2611 return; 2612 } // end WCachePurgeAll__() 2613 /* 2614 WCachePurgeAllRW() copies modified blocks from cache to media 2615 and removes them from cache 2616 This routine can be used for RAM, RW and ROM media. 2617 For ROM media blocks are just removed. 2618 Internal routine 2619 */ 2620 VOID 2621 __fastcall 2622 WCachePurgeAllRW( 2623 IN PW_CACHE Cache, // pointer to the Cache Control structure 2624 IN PVOID Context) // user-supplied context for IO callbacks 2625 { 2626 ULONG frame; 2627 lba_t firstLba; 2628 lba_t* List = Cache->CachedBlocksList; 2629 lba_t Lba; 2630 // ULONG firstPos; 2631 // ULONG lastPos; 2632 ULONG BSh = Cache->BlockSizeSh; 2633 ULONG BS = Cache->BlockSize; 2634 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2635 ULONG PSs = Cache->PacketSize; 2636 PW_CACHE_ENTRY block_array; 2637 // OSSTATUS status; 2638 SIZE_T ReadBytes; 2639 PW_CACHE_ASYNC FirstWContext = NULL; 2640 PW_CACHE_ASYNC PrevWContext = NULL; 2641 ULONG chain_count = 0; 2642 2643 if(!(Cache->ReadProc)) return; 2644 2645 while(Cache->BlockCount) { 2646 Lba = List[0] & ~(PSs-1); 2647 frame = Lba >> Cache->BlocksPerFrameSh; 2648 firstLba = frame << Cache->BlocksPerFrameSh; 2649 // firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 2650 // lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 2651 block_array = Cache->FrameList[frame].Frame; 2652 if(!block_array) { 2653 BrutePoint(); 2654 return; 2655 } 2656 2657 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2658 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2659 2660 // free memory 2661 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 2662 2663 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 2664 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 2665 // check if frame is empty 2666 if(!(Cache->FrameList[frame].BlockCount)) { 2667 WCacheRemoveFrame(Cache, Context, frame); 2668 } else { 2669 ASSERT(Cache->FrameList[frame].Frame); 2670 } 2671 chain_count++; 2672 if(chain_count >= WCACHE_MAX_CHAIN) { 2673 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2674 chain_count = 0; 2675 } 2676 } 2677 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 2678 return; 2679 } // end WCachePurgeAllRW() 2680 2681 /* 2682 WCacheFlushAllRW() copies modified blocks from cache to media. 2683 All blocks are not removed from cache. 2684 This routine can be used for RAM, RW and ROM media. 2685 Internal routine 2686 */ 2687 VOID 2688 __fastcall 2689 WCacheFlushAllRW( 2690 IN PW_CACHE Cache, // pointer to the Cache Control structure 2691 IN PVOID Context) // user-supplied context for IO callbacks 2692 { 2693 ULONG frame; 2694 lba_t firstLba; 2695 lba_t* List = Cache->CachedModifiedBlocksList; 2696 lba_t Lba; 2697 // ULONG firstPos; 2698 // ULONG lastPos; 2699 ULONG BSh = Cache->BlockSizeSh; 2700 ULONG BS = Cache->BlockSize; 2701 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2702 ULONG PSs = Cache->PacketSize; 2703 ULONG BFs = Cache->BlocksPerFrameSh; 2704 PW_CACHE_ENTRY block_array; 2705 // OSSTATUS status; 2706 SIZE_T ReadBytes; 2707 PW_CACHE_ASYNC FirstWContext = NULL; 2708 PW_CACHE_ASYNC PrevWContext = NULL; 2709 ULONG i; 2710 ULONG chain_count = 0; 2711 2712 if(!(Cache->ReadProc)) return; 2713 2714 // walk through modified blocks 2715 while(Cache->WriteCount) { 2716 Lba = List[0] & ~(PSs-1); 2717 frame = Lba >> BFs; 2718 firstLba = frame << BFs; 2719 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); 2720 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); 2721 block_array = Cache->FrameList[frame].Frame; 2722 if(!block_array) { 2723 BrutePoint(); 2724 continue;; 2725 } 2726 // queue modify request 2727 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2728 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2729 // clear MODIFIED flag for queued blocks 2730 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); 2731 Lba -= firstLba; 2732 for(i=0; i<PSs; i++) { 2733 WCacheClrModFlag(block_array, Lba+i); 2734 } 2735 chain_count++; 2736 // check queue size 2737 if(chain_count >= WCACHE_MAX_CHAIN) { 2738 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2739 chain_count = 0; 2740 } 2741 } 2742 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2743 #ifdef DBG 2744 #if 1 2745 // check consistency 2746 List = Cache->CachedBlocksList; 2747 for(i=0; i<Cache->BlockCount; i++) { 2748 Lba = List[i] /*& ~(PSs-1)*/; 2749 frame = Lba >> Cache->BlocksPerFrameSh; 2750 firstLba = frame << Cache->BlocksPerFrameSh; 2751 block_array = Cache->FrameList[frame].Frame; 2752 if(!block_array) { 2753 BrutePoint(); 2754 } 2755 ASSERT(!WCacheGetModFlag(block_array, Lba-firstLba)); 2756 } 2757 #endif // 1 2758 #endif // DBG 2759 return; 2760 } // end WCacheFlushAllRW() 2761 2762 /* 2763 WCacheRelease__() frees all allocated memory blocks and 2764 deletes synchronization resources 2765 Public routine 2766 */ 2767 VOID 2768 WCacheRelease__( 2769 IN PW_CACHE Cache // pointer to the Cache Control structure 2770 ) 2771 { 2772 ULONG i, j, k; 2773 PW_CACHE_ENTRY block_array; 2774 2775 Cache->Tag = 0xDEADCACE; 2776 if(!(Cache->ReadProc)) return; 2777 // ASSERT(Cache->Tag == 0xCAC11E00); 2778 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2779 for(i=0; i<Cache->FrameCount; i++) { 2780 j = Cache->CachedFramesList[i]; 2781 block_array = Cache->FrameList[j].Frame; 2782 if(block_array) { 2783 for(k=0; k<Cache->BlocksPerFrame; k++) { 2784 if(WCacheSectorAddr(block_array, k)) { 2785 WCacheFreeSector(j, k); 2786 } 2787 } 2788 MyFreePool__(block_array); 2789 } 2790 } 2791 if(Cache->FrameList) 2792 MyFreePool__(Cache->FrameList); 2793 if(Cache->CachedBlocksList) 2794 MyFreePool__(Cache->CachedBlocksList); 2795 if(Cache->CachedModifiedBlocksList) 2796 MyFreePool__(Cache->CachedModifiedBlocksList); 2797 if(Cache->CachedFramesList) 2798 MyFreePool__(Cache->CachedFramesList); 2799 if(Cache->tmp_buff_r) 2800 MyFreePool__(Cache->tmp_buff_r); 2801 if(Cache->CachedFramesList) 2802 MyFreePool__(Cache->tmp_buff); 2803 if(Cache->CachedFramesList) 2804 MyFreePool__(Cache->reloc_tab); 2805 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2806 ExDeleteResourceLite(&(Cache->WCacheLock)); 2807 RtlZeroMemory(Cache, sizeof(W_CACHE)); 2808 return; 2809 } // end WCacheRelease__() 2810 2811 /* 2812 WCacheIsInitialized__() checks if the pointer supplied points 2813 to initialized cache structure. 2814 Public routine 2815 */ 2816 BOOLEAN 2817 WCacheIsInitialized__( 2818 IN PW_CACHE Cache 2819 ) 2820 { 2821 return (Cache->ReadProc != NULL); 2822 } // end WCacheIsInitialized__() 2823 2824 OSSTATUS 2825 WCacheFlushBlocksRW( 2826 IN PW_CACHE Cache, // pointer to the Cache Control structure 2827 IN PVOID Context, // user-supplied context for IO callbacks 2828 IN lba_t _Lba, // LBA to start flush from 2829 IN ULONG BCount // number of blocks to be flushed 2830 ) 2831 { 2832 ULONG frame; 2833 lba_t firstLba; 2834 lba_t* List = Cache->CachedModifiedBlocksList; 2835 lba_t Lba; 2836 // ULONG firstPos; 2837 // ULONG lastPos; 2838 ULONG BSh = Cache->BlockSizeSh; 2839 ULONG BS = Cache->BlockSize; 2840 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2841 ULONG PSs = Cache->PacketSize; 2842 ULONG BFs = Cache->BlocksPerFrameSh; 2843 PW_CACHE_ENTRY block_array; 2844 // OSSTATUS status; 2845 SIZE_T ReadBytes; 2846 PW_CACHE_ASYNC FirstWContext = NULL; 2847 PW_CACHE_ASYNC PrevWContext = NULL; 2848 ULONG i; 2849 ULONG chain_count = 0; 2850 lba_t lim; 2851 2852 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; 2853 2854 // walk through modified blocks 2855 lim = (_Lba+BCount+PSs-1) & ~(PSs-1); 2856 for(Lba = _Lba & ~(PSs-1);Lba < lim ; Lba += PSs) { 2857 frame = Lba >> BFs; 2858 firstLba = frame << BFs; 2859 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); 2860 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); 2861 block_array = Cache->FrameList[frame].Frame; 2862 if(!block_array) { 2863 // not cached block may be requested for flush 2864 Lba += (1 << BFs) - PSs; 2865 continue; 2866 } 2867 // queue modify request 2868 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2869 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2870 // clear MODIFIED flag for queued blocks 2871 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); 2872 Lba -= firstLba; 2873 for(i=0; i<PSs; i++) { 2874 WCacheClrModFlag(block_array, Lba+i); 2875 } 2876 Lba += firstLba; 2877 chain_count++; 2878 // check queue size 2879 if(chain_count >= WCACHE_MAX_CHAIN) { 2880 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2881 chain_count = 0; 2882 } 2883 } 2884 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2885 /* 2886 if(Cache->Mode != WCACHE_MODE_RAM) 2887 return STATUS_SUCCESS; 2888 */ 2889 2890 return STATUS_SUCCESS; 2891 } // end WCacheFlushBlocksRW() 2892 2893 /* 2894 WCacheFlushBlocks__() copies specified blocks stored in cache to media. 2895 Flushed blocks are kept in cache. 2896 Public routine 2897 */ 2898 OSSTATUS 2899 WCacheFlushBlocks__( 2900 IN PW_CACHE Cache, // pointer to the Cache Control structure 2901 IN PVOID Context, // user-supplied context for IO callbacks 2902 IN lba_t Lba, // LBA to start flush from 2903 IN ULONG BCount // number of blocks to be flushed 2904 ) 2905 { 2906 OSSTATUS status; 2907 2908 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; 2909 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2910 2911 // check if we try to access beyond cached area 2912 if((Lba < Cache->FirstLba) || 2913 (Lba+BCount-1 > Cache->LastLba)) { 2914 UDFPrint(("LBA %#x (%x) is beyond cacheable area\n", Lba, BCount)); 2915 BrutePoint(); 2916 status = STATUS_INVALID_PARAMETER; 2917 goto EO_WCache_F; 2918 } 2919 2920 switch(Cache->Mode) { 2921 case WCACHE_MODE_RAM: 2922 // WCacheFlushBlocksRW(Cache, Context); 2923 // break; 2924 case WCACHE_MODE_ROM: 2925 case WCACHE_MODE_RW: 2926 status = WCacheFlushBlocksRW(Cache, Context, Lba, BCount); 2927 break; 2928 case WCACHE_MODE_R: 2929 status = STATUS_SUCCESS; 2930 break; 2931 } 2932 EO_WCache_F: 2933 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2934 return status; 2935 } // end WCacheFlushBlocks__() 2936 2937 /* 2938 WCacheDirect__() returns pointer to memory block where 2939 requested block is stored in. 2940 If no #CachedOnly flag specified this routine locks cache, 2941 otherwise it assumes that cache is already locked by previous call 2942 to WCacheStartDirect__(). 2943 Cache can be unlocked by WCacheEODirect__(). 2944 Using this routine caller can access cached block directly in memory 2945 without Read_to_Tmp and Modify/Write steps. 2946 Public routine 2947 */ 2948 OSSTATUS 2949 WCacheDirect__( 2950 IN PW_CACHE Cache, // pointer to the Cache Control structure 2951 IN PVOID Context, // user-supplied context for IO callbacks 2952 IN lba_t Lba, // LBA of block to get pointer to 2953 IN BOOLEAN Modified, // indicates that block will be modified 2954 OUT PCHAR* CachedBlock, // address for pointer to cached block to be stored in 2955 IN BOOLEAN CachedOnly // specifies that cache is already locked 2956 ) 2957 { 2958 ULONG frame; 2959 ULONG i; 2960 OSSTATUS status = STATUS_SUCCESS; 2961 PW_CACHE_ENTRY block_array; 2962 ULONG BS = Cache->BlockSize; 2963 PCHAR addr; 2964 SIZE_T _ReadBytes; 2965 ULONG block_type; 2966 2967 WcPrint(("WC:%sD %x (1)\n", Modified ? "W" : "R", Lba)); 2968 2969 // lock cache if nececcary 2970 if(!CachedOnly) { 2971 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2972 } 2973 // check if we try to access beyond cached area 2974 if((Lba < Cache->FirstLba) || 2975 (Lba > Cache->LastLba)) { 2976 UDFPrint(("LBA %#x is beyond cacheable area\n", Lba)); 2977 BrutePoint(); 2978 status = STATUS_INVALID_PARAMETER; 2979 goto EO_WCache_D; 2980 } 2981 2982 frame = Lba >> Cache->BlocksPerFrameSh; 2983 i = Lba - (frame << Cache->BlocksPerFrameSh); 2984 // check if we have enough space to store requested block 2985 if(!CachedOnly && 2986 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, 1))) { 2987 BrutePoint(); 2988 goto EO_WCache_D; 2989 } 2990 2991 // small updates are more important 2992 block_array = Cache->FrameList[frame].Frame; 2993 if(Modified) { 2994 Cache->FrameList[frame].UpdateCount+=8; 2995 } else { 2996 Cache->FrameList[frame].AccessCount+=8; 2997 } 2998 if(!block_array) { 2999 ASSERT(Cache->FrameCount < Cache->MaxFrames); 3000 block_array = WCacheInitFrame(Cache, Context, frame); 3001 if(!block_array) { 3002 status = STATUS_INSUFFICIENT_RESOURCES; 3003 goto EO_WCache_D; 3004 } 3005 } 3006 // check if requested block is already cached 3007 if( !(addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 3008 // block is not cached 3009 // allocate memory and read block from media 3010 // do not set block_array[i].Sector here, because if media access fails and recursive access to cache 3011 // comes, this block should not be marked as 'cached' 3012 addr = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 3013 if(!addr) { 3014 status = STATUS_INSUFFICIENT_RESOURCES; 3015 goto EO_WCache_D; 3016 } 3017 block_type = Cache->CheckUsedProc(Context, Lba); 3018 if(block_type == WCACHE_BLOCK_USED) { 3019 status = Cache->ReadProc(Context, addr, BS, Lba, &_ReadBytes, PH_TMP_BUFFER); 3020 if(Cache->RememberBB) { 3021 if(!OS_SUCCESS(status)) { 3022 RtlZeroMemory(addr, BS); 3023 //WCacheSetBadFlag(block_array,i); 3024 } 3025 } 3026 } else { 3027 if(block_type & WCACHE_BLOCK_BAD) { 3028 DbgFreePool(addr); 3029 addr = NULL; 3030 status = STATUS_DEVICE_DATA_ERROR; 3031 goto EO_WCache_D; 3032 } 3033 if(!(block_type & WCACHE_BLOCK_ZERO)) { 3034 BrutePoint(); 3035 } 3036 status = STATUS_SUCCESS; 3037 RtlZeroMemory(addr, BS); 3038 } 3039 // now add pointer to buffer to common storage 3040 block_array[i].Sector = addr; 3041 WCacheInsertItemToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba); 3042 if(Modified) { 3043 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3044 WCacheSetModFlag(block_array, i); 3045 } 3046 Cache->FrameList[frame].BlockCount ++; 3047 } else { 3048 // block is not cached 3049 // just return pointer 3050 block_type = Cache->CheckUsedProc(Context, Lba); 3051 if(block_type & WCACHE_BLOCK_BAD) { 3052 //if(WCacheGetBadFlag(block_array,i)) { 3053 // bad packet. no pre-read 3054 status = STATUS_DEVICE_DATA_ERROR; 3055 goto EO_WCache_D; 3056 } 3057 #ifndef UDF_CHECK_UTIL 3058 ASSERT(block_type & WCACHE_BLOCK_USED); 3059 #else 3060 if(!(block_type & WCACHE_BLOCK_USED)) { 3061 UDFPrint(("LBA %#x is not marked as used\n", Lba)); 3062 } 3063 #endif 3064 if(Modified && 3065 !WCacheGetModFlag(block_array, i)) { 3066 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3067 WCacheSetModFlag(block_array, i); 3068 } 3069 } 3070 (*CachedBlock) = addr; 3071 3072 EO_WCache_D: 3073 3074 return status; 3075 } // end WCacheDirect__() 3076 3077 /* 3078 WCacheEODirect__() must be used to unlock cache after calls to 3079 to WCacheStartDirect__(). 3080 Public routine 3081 */ 3082 OSSTATUS 3083 WCacheEODirect__( 3084 IN PW_CACHE Cache, // pointer to the Cache Control structure 3085 IN PVOID Context // user-supplied context for IO callbacks 3086 ) 3087 { 3088 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3089 return STATUS_SUCCESS; 3090 } // end WCacheEODirect__() 3091 3092 /* 3093 WCacheStartDirect__() locks cache for exclusive use. 3094 Using this routine caller can access cached block directly in memory 3095 without Read_to_Tmp and Modify/Write steps. 3096 See also WCacheDirect__() 3097 Cache can be unlocked by WCacheEODirect__(). 3098 Public routine 3099 */ 3100 OSSTATUS 3101 WCacheStartDirect__( 3102 IN PW_CACHE Cache, // pointer to the Cache Control structure 3103 IN PVOID Context, // user-supplied context for IO callbacks 3104 IN BOOLEAN Exclusive // lock cache for exclusive use, 3105 // currently must be TRUE. 3106 ) 3107 { 3108 if(Exclusive) { 3109 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 3110 } else { 3111 BrutePoint(); 3112 ExAcquireResourceSharedLite(&(Cache->WCacheLock), TRUE); 3113 } 3114 return STATUS_SUCCESS; 3115 } // end WCacheStartDirect__() 3116 3117 /* 3118 WCacheIsCached__() checks if requested blocks are immediately available. 3119 Cache must be previously locked for exclusive use with WCacheStartDirect__(). 3120 Using this routine caller can access cached block directly in memory 3121 without Read_to_Tmp and Modify/Write steps. 3122 See also WCacheDirect__(). 3123 Cache can be unlocked by WCacheEODirect__(). 3124 Public routine 3125 */ 3126 BOOLEAN 3127 WCacheIsCached__( 3128 IN PW_CACHE Cache, // pointer to the Cache Control structure 3129 IN lba_t Lba, // LBA to start check from 3130 IN ULONG BCount // number of blocks to be checked 3131 ) 3132 { 3133 ULONG frame; 3134 ULONG i; 3135 PW_CACHE_ENTRY block_array; 3136 3137 // check if we try to access beyond cached area 3138 if((Lba < Cache->FirstLba) || 3139 (Lba + BCount - 1 > Cache->LastLba)) { 3140 return FALSE; 3141 } 3142 3143 frame = Lba >> Cache->BlocksPerFrameSh; 3144 i = Lba - (frame << Cache->BlocksPerFrameSh); 3145 3146 block_array = Cache->FrameList[frame].Frame; 3147 if(!block_array) { 3148 return FALSE; 3149 } 3150 3151 while(BCount) { 3152 if(i >= Cache->BlocksPerFrame) { 3153 frame++; 3154 block_array = Cache->FrameList[frame].Frame; 3155 i -= Cache->BlocksPerFrame; 3156 } 3157 if(!block_array) { 3158 return FALSE; 3159 } 3160 // 'read' cached extent (if any) 3161 while(BCount && 3162 (i < Cache->BlocksPerFrame) && 3163 WCacheSectorAddr(block_array, i) && 3164 /*!WCacheGetBadFlag(block_array, i)*/ 3165 /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/ 3166 TRUE ) { 3167 i++; 3168 BCount--; 3169 Lba++; 3170 } 3171 if(BCount && 3172 (i < Cache->BlocksPerFrame) /*&& 3173 (!WCacheSectorAddr(block_array, i))*/ ) { 3174 return FALSE; 3175 } 3176 } 3177 return TRUE; 3178 } // end WCacheIsCached__() 3179 3180 /* 3181 WCacheCheckLimitsR() implements automatic flush and purge of 3182 unused blocks to keep enough free cache entries for newly 3183 read/written blocks for WORM media. 3184 See also WCacheCheckLimits() 3185 Internal routine 3186 */ 3187 OSSTATUS 3188 __fastcall 3189 WCacheCheckLimitsR( 3190 IN PW_CACHE Cache, // pointer to the Cache Control structure 3191 IN PVOID Context, // user-supplied context for IO callbacks 3192 IN lba_t ReqLba, // first LBA to access/cache 3193 IN ULONG BCount // number of Blocks to access/cache 3194 ) 3195 { 3196 ULONG frame; 3197 lba_t firstLba; 3198 lba_t* List = Cache->CachedBlocksList; 3199 lba_t Lba; 3200 PCHAR tmp_buff = Cache->tmp_buff; 3201 ULONG firstPos; 3202 ULONG BSh = Cache->BlockSizeSh; 3203 ULONG BS = Cache->BlockSize; 3204 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3205 ULONG PSs = Cache->PacketSize; 3206 ULONG i; 3207 PW_CACHE_ENTRY block_array; 3208 BOOLEAN mod; 3209 OSSTATUS status; 3210 SIZE_T ReadBytes; 3211 ULONG MaxReloc = Cache->PacketSize; 3212 PULONG reloc_tab = Cache->reloc_tab; 3213 3214 // check if we try to read too much data 3215 if(BCount > Cache->MaxBlocks) { 3216 return STATUS_INVALID_PARAMETER; 3217 } 3218 3219 // remove(flush) packets from entire frame(s) 3220 while( ((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 3221 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) || 3222 (Cache->FrameCount >= Cache->MaxFrames) ) { 3223 3224 WCCL_retry_1: 3225 3226 Lba = WCacheFindLbaToRelease(Cache); 3227 if(Lba == WCACHE_INVALID_LBA) { 3228 ASSERT(!Cache->FrameCount); 3229 ASSERT(!Cache->BlockCount); 3230 break; 3231 } 3232 frame = Lba >> Cache->BlocksPerFrameSh; 3233 firstLba = frame << Cache->BlocksPerFrameSh; 3234 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 3235 block_array = Cache->FrameList[frame].Frame; 3236 if(!block_array) { 3237 return STATUS_DRIVER_INTERNAL_ERROR; 3238 } 3239 // check if modified 3240 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3241 // read/modify/write 3242 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3243 if(Cache->WriteCount < MaxReloc) goto WCCL_retry_1; 3244 firstPos = WCacheGetSortedListIndex(Cache->WriteCount, Cache->CachedModifiedBlocksList, Lba); 3245 if(!block_array) { 3246 return STATUS_DRIVER_INTERNAL_ERROR; 3247 } 3248 // prepare packet & reloc table 3249 for(i=0; i<MaxReloc; i++) { 3250 Lba = Cache->CachedModifiedBlocksList[firstPos]; 3251 frame = Lba >> Cache->BlocksPerFrameSh; 3252 firstLba = frame << Cache->BlocksPerFrameSh; 3253 block_array = Cache->FrameList[frame].Frame; 3254 DbgCopyMemory(tmp_buff + (i << BSh), 3255 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), 3256 BS); 3257 reloc_tab[i] = Lba; 3258 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3259 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3260 // mark as non-cached & free pool 3261 WCacheFreeSector(frame, Lba-firstLba); 3262 // check if frame is empty 3263 if(!Cache->FrameList[frame].BlockCount) { 3264 WCacheRemoveFrame(Cache, Context, frame); 3265 } 3266 if(firstPos >= Cache->WriteCount) firstPos=0; 3267 } 3268 // write packet 3269 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); 3270 Cache->UpdateRelocProc(Context, NULL, reloc_tab, MaxReloc); 3271 status = Cache->WriteProc(Context, tmp_buff, PS, NULL, &ReadBytes, 0); 3272 if(!OS_SUCCESS(status)) { 3273 status = WCacheRaiseIoError(Cache, Context, status, NULL, PSs, tmp_buff, WCACHE_W_OP, NULL); 3274 } 3275 } else { 3276 3277 if((i = Cache->BlockCount - Cache->WriteCount) > MaxReloc) i = MaxReloc; 3278 // discard blocks 3279 for(; i; i--) { 3280 Lba = List[firstPos]; 3281 frame = Lba >> Cache->BlocksPerFrameSh; 3282 firstLba = frame << Cache->BlocksPerFrameSh; 3283 block_array = Cache->FrameList[frame].Frame; 3284 3285 if( (mod = WCacheGetModFlag(block_array, Lba - firstLba)) && 3286 (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED) ) 3287 continue; 3288 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3289 if(mod) 3290 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3291 // mark as non-cached & free pool 3292 WCacheFreeSector(frame, Lba-firstLba); 3293 // check if frame is empty 3294 if(!Cache->FrameList[frame].BlockCount) { 3295 WCacheRemoveFrame(Cache, Context, frame); 3296 } 3297 if(firstPos >= Cache->WriteCount) firstPos=0; 3298 } 3299 } 3300 } 3301 return STATUS_SUCCESS; 3302 } // end WCacheCheckLimitsR() 3303 3304 /* 3305 WCachePurgeAllR() copies modified blocks from cache to media 3306 and removes them from cache 3307 This routine can be used for R media only. 3308 Internal routine 3309 */ 3310 VOID 3311 __fastcall 3312 WCachePurgeAllR( 3313 IN PW_CACHE Cache, // pointer to the Cache Control structure 3314 IN PVOID Context) // user-supplied context for IO callbacks 3315 { 3316 ULONG frame; 3317 lba_t firstLba; 3318 lba_t* List = Cache->CachedBlocksList; 3319 lba_t Lba; 3320 PCHAR tmp_buff = Cache->tmp_buff; 3321 ULONG BSh = Cache->BlockSizeSh; 3322 ULONG BS = Cache->BlockSize; 3323 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3324 // ULONG PSs = Cache->PacketSize; 3325 PW_CACHE_ENTRY block_array; 3326 BOOLEAN mod; 3327 OSSTATUS status; 3328 SIZE_T ReadBytes; 3329 ULONG MaxReloc = Cache->PacketSize; 3330 PULONG reloc_tab = Cache->reloc_tab; 3331 ULONG RelocCount = 0; 3332 BOOLEAN IncompletePacket; 3333 ULONG i=0; 3334 ULONG PacketTail; 3335 3336 while(Cache->WriteCount < Cache->BlockCount) { 3337 3338 Lba = List[i]; 3339 frame = Lba >> Cache->BlocksPerFrameSh; 3340 firstLba = frame << Cache->BlocksPerFrameSh; 3341 block_array = Cache->FrameList[frame].Frame; 3342 if(!block_array) { 3343 BrutePoint(); 3344 return; 3345 } 3346 // check if modified 3347 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3348 // just discard 3349 if(!mod || !(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3350 // mark as non-cached & free pool 3351 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3352 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3353 if(mod) 3354 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3355 // mark as non-cached & free pool 3356 WCacheFreeSector(frame, Lba-firstLba); 3357 // check if frame is empty 3358 if(!Cache->FrameList[frame].BlockCount) { 3359 WCacheRemoveFrame(Cache, Context, frame); 3360 } 3361 } else { 3362 BrutePoint(); 3363 } 3364 } else { 3365 i++; 3366 } 3367 } 3368 3369 PacketTail = Cache->WriteCount & (MaxReloc-1); 3370 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; 3371 3372 // remove(flush) packet 3373 while((Cache->WriteCount > PacketTail) || (Cache->WriteCount && IncompletePacket)) { 3374 3375 Lba = List[0]; 3376 frame = Lba >> Cache->BlocksPerFrameSh; 3377 firstLba = frame << Cache->BlocksPerFrameSh; 3378 block_array = Cache->FrameList[frame].Frame; 3379 if(!block_array) { 3380 BrutePoint(); 3381 return; 3382 } 3383 // check if modified 3384 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3385 // pack/reloc/write 3386 if(mod) { 3387 DbgCopyMemory(tmp_buff + (RelocCount << BSh), 3388 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), 3389 BS); 3390 reloc_tab[RelocCount] = Lba; 3391 RelocCount++; 3392 // write packet 3393 if((RelocCount >= MaxReloc) || (Cache->BlockCount == 1)) { 3394 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); 3395 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); 3396 status = Cache->WriteProc(Context, tmp_buff, RelocCount<<BSh, NULL, &ReadBytes, 0); 3397 if(!OS_SUCCESS(status)) { 3398 status = WCacheRaiseIoError(Cache, Context, status, NULL, RelocCount, tmp_buff, WCACHE_W_OP, NULL); 3399 } 3400 RelocCount = 0; 3401 } 3402 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3403 } else { 3404 BrutePoint(); 3405 } 3406 // mark as non-cached & free pool 3407 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3408 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3409 // mark as non-cached & free pool 3410 WCacheFreeSector(frame, Lba-firstLba); 3411 // check if frame is empty 3412 if(!Cache->FrameList[frame].BlockCount) { 3413 WCacheRemoveFrame(Cache, Context, frame); 3414 } 3415 } else { 3416 BrutePoint(); 3417 } 3418 } 3419 } // end WCachePurgeAllR() 3420 3421 /* 3422 WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM). 3423 Public routine 3424 */ 3425 OSSTATUS 3426 WCacheSetMode__( 3427 IN PW_CACHE Cache, // pointer to the Cache Control structure 3428 IN ULONG Mode // cache mode/media type to be used 3429 ) 3430 { 3431 if(Mode > WCACHE_MODE_MAX) return STATUS_INVALID_PARAMETER; 3432 Cache->Mode = Mode; 3433 return STATUS_SUCCESS; 3434 } // end WCacheSetMode__() 3435 3436 /* 3437 WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM). 3438 Public routine 3439 */ 3440 ULONG 3441 WCacheGetMode__( 3442 IN PW_CACHE Cache 3443 ) 3444 { 3445 return Cache->Mode; 3446 } // end WCacheGetMode__() 3447 3448 /* 3449 WCacheGetWriteBlockCount__() returns number of modified blocks, those are 3450 not flushed to media. Is usually used to preallocate blocks for 3451 relocation table on WORM (R) media. 3452 Public routine 3453 */ 3454 ULONG 3455 WCacheGetWriteBlockCount__( 3456 IN PW_CACHE Cache 3457 ) 3458 { 3459 return Cache->WriteCount; 3460 } // end WCacheGetWriteBlockCount__() 3461 3462 /* 3463 WCacheSyncReloc__() builds list of all modified blocks, currently 3464 stored in cache. For each modified block WCacheSyncReloc__() calls 3465 user-supplied callback routine in order to update relocation table 3466 on WORM (R) media. 3467 Public routine 3468 */ 3469 VOID 3470 WCacheSyncReloc__( 3471 IN PW_CACHE Cache, 3472 IN PVOID Context) 3473 { 3474 ULONG frame; 3475 lba_t firstLba; 3476 lba_t* List = Cache->CachedBlocksList; 3477 lba_t Lba; 3478 // ULONG BSh = Cache->BlockSizeSh; 3479 // ULONG BS = Cache->BlockSize; 3480 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3481 // ULONG PSs = Cache->PacketSize; 3482 PW_CACHE_ENTRY block_array; 3483 BOOLEAN mod; 3484 ULONG MaxReloc = Cache->PacketSize; 3485 PULONG reloc_tab = Cache->reloc_tab; 3486 ULONG RelocCount = 0; 3487 BOOLEAN IncompletePacket; 3488 3489 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; 3490 // enumerate modified blocks 3491 for(ULONG i=0; IncompletePacket && (i<Cache->BlockCount); i++) { 3492 3493 Lba = List[i]; 3494 frame = Lba >> Cache->BlocksPerFrameSh; 3495 firstLba = frame << Cache->BlocksPerFrameSh; 3496 block_array = Cache->FrameList[frame].Frame; 3497 if(!block_array) { 3498 return; 3499 } 3500 // check if modified 3501 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3502 // update relocation table for modified sectors 3503 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3504 reloc_tab[RelocCount] = Lba; 3505 RelocCount++; 3506 if(RelocCount >= Cache->WriteCount) { 3507 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); 3508 break; 3509 } 3510 } 3511 } 3512 } // end WCacheSyncReloc__() 3513 3514 /* 3515 WCacheDiscardBlocks__() removes specified blocks from cache. 3516 Blocks are not flushed to media. 3517 Public routine 3518 */ 3519 VOID 3520 WCacheDiscardBlocks__( 3521 IN PW_CACHE Cache, 3522 IN PVOID Context, 3523 IN lba_t ReqLba, 3524 IN ULONG BCount 3525 ) 3526 { 3527 ULONG frame; 3528 lba_t firstLba; 3529 lba_t* List; 3530 lba_t Lba; 3531 PW_CACHE_ENTRY block_array; 3532 BOOLEAN mod; 3533 ULONG i; 3534 3535 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 3536 3537 UDFPrint((" Discard req: %x@%x\n",BCount, ReqLba)); 3538 3539 List = Cache->CachedBlocksList; 3540 if(!List) { 3541 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3542 return; 3543 } 3544 i = WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba); 3545 3546 // enumerate requested blocks 3547 while((List[i] < (ReqLba+BCount)) && (i < Cache->BlockCount)) { 3548 3549 Lba = List[i]; 3550 frame = Lba >> Cache->BlocksPerFrameSh; 3551 firstLba = frame << Cache->BlocksPerFrameSh; 3552 block_array = Cache->FrameList[frame].Frame; 3553 if(!block_array) { 3554 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3555 BrutePoint(); 3556 return; 3557 } 3558 // check if modified 3559 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3560 // just discard 3561 3562 // mark as non-cached & free pool 3563 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3564 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3565 if(mod) 3566 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3567 // mark as non-cached & free pool 3568 WCacheFreeSector(frame, Lba-firstLba); 3569 // check if frame is empty 3570 if(!Cache->FrameList[frame].BlockCount) { 3571 WCacheRemoveFrame(Cache, Context, frame); 3572 } else { 3573 ASSERT(Cache->FrameList[frame].Frame); 3574 } 3575 } else { 3576 // we should never get here !!! 3577 // getting this part of code means that we have 3578 // placed non-cached block in CachedBlocksList 3579 BrutePoint(); 3580 } 3581 } 3582 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3583 } // end WCacheDiscardBlocks__() 3584 3585 OSSTATUS 3586 WCacheCompleteAsync__( 3587 IN PVOID WContext, 3588 IN OSSTATUS Status 3589 ) 3590 { 3591 PW_CACHE_ASYNC AsyncCtx = (PW_CACHE_ASYNC)WContext; 3592 // PW_CACHE Cache = AsyncCtx->Cache; 3593 3594 AsyncCtx->PhContext.IosbToUse.Status = Status; 3595 KeSetEvent(&(AsyncCtx->PhContext.event), 0, FALSE); 3596 3597 return STATUS_SUCCESS; 3598 } // end WCacheSetMode__() 3599 3600 /* 3601 WCacheDecodeFlags() updates internal BOOLEANs according to Flags 3602 Internal routine 3603 */ 3604 OSSTATUS 3605 __fastcall 3606 WCacheDecodeFlags( 3607 IN PW_CACHE Cache, // pointer to the Cache Control structure 3608 IN ULONG Flags // cache mode flags 3609 ) 3610 { 3611 //ULONG OldFlags; 3612 if(Flags & ~WCACHE_VALID_FLAGS) { 3613 UDFPrint(("Invalid flags: %x\n", Flags & ~WCACHE_VALID_FLAGS)); 3614 return STATUS_INVALID_PARAMETER; 3615 } 3616 Cache->CacheWholePacket = (Flags & WCACHE_CACHE_WHOLE_PACKET) ? TRUE : FALSE; 3617 Cache->DoNotCompare = (Flags & WCACHE_DO_NOT_COMPARE) ? TRUE : FALSE; 3618 Cache->Chained = (Flags & WCACHE_CHAINED_IO) ? TRUE : FALSE; 3619 Cache->RememberBB = (Flags & WCACHE_MARK_BAD_BLOCKS) ? TRUE : FALSE; 3620 if(Cache->RememberBB) { 3621 Cache->NoWriteBB = (Flags & WCACHE_RO_BAD_BLOCKS) ? TRUE : FALSE; 3622 } 3623 Cache->NoWriteThrough = (Flags & WCACHE_NO_WRITE_THROUGH) ? TRUE : FALSE; 3624 3625 Cache->Flags = Flags; 3626 3627 return STATUS_SUCCESS; 3628 } 3629 3630 /* 3631 WCacheChFlags__() changes cache flags. 3632 Public routine 3633 */ 3634 ULONG 3635 WCacheChFlags__( 3636 IN PW_CACHE Cache, // pointer to the Cache Control structure 3637 IN ULONG SetFlags, // cache mode/media type to be set 3638 IN ULONG ClrFlags // cache mode/media type to be cleared 3639 ) 3640 { 3641 ULONG Flags; 3642 3643 if(SetFlags || ClrFlags) { 3644 Flags = (Cache->Flags & ~ClrFlags) | SetFlags; 3645 3646 if(!OS_SUCCESS(WCacheDecodeFlags(Cache, Flags))) { 3647 return -1; 3648 } 3649 } else { 3650 return Cache->Flags; 3651 } 3652 return Flags; 3653 } // end WCacheSetMode__() 3654