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 if(Chained && 1139 WContext->State == ASYNC_STATE_WRITE_PRE) { 1140 // Return if block is prepared for write and we are in chained mode. 1141 if(!mod) { 1142 // Mark block as written if we have found that data in it 1143 // is not actually modified. 1144 WContext->State = ASYNC_STATE_DONE; 1145 (*ReadBytes) = PS; 1146 } 1147 return STATUS_SUCCESS; 1148 } 1149 1150 // write packet 1151 1152 // If the check above reported some changes in packet 1153 // we should write packet out to media. 1154 // Otherwise, just complete request. 1155 if(mod) { 1156 try_write: 1157 if(Async) { 1158 WContext->State = ASYNC_STATE_WRITE; 1159 status = Cache->WriteProcAsync(Context, WContext, tmp_buff2, PS, Lba, 1160 &(WContext->TransferredBytes), FALSE); 1161 (*ReadBytes) = PS; 1162 } else { 1163 status = Cache->WriteProc(Context, tmp_buff2, PS, Lba, ReadBytes, 0); 1164 if(!OS_SUCCESS(status)) { 1165 status = WCacheRaiseIoError(Cache, Context, status, Lba, PSs, tmp_buff2, WCACHE_W_OP, NULL); 1166 } 1167 } 1168 } else { 1169 if(Async) 1170 WCacheCompleteAsync__(WContext, STATUS_SUCCESS); 1171 (*ReadBytes) = PS; 1172 return STATUS_SUCCESS; 1173 } 1174 1175 return status; 1176 } // end WCacheUpdatePacket() 1177 1178 /* 1179 WCacheFreePacket() releases storage for all Blocks in packet. 1180 'frame' describes Frame, offset - Block in Frame. offset should be 1181 aligned on Packet size. 1182 Internal routine 1183 */ 1184 VOID 1185 WCacheFreePacket( 1186 IN PW_CACHE Cache, // pointer to the Cache Control structure 1187 // IN PVOID Context, 1188 IN ULONG frame, // Frame index 1189 IN PW_CACHE_ENTRY block_array, // Frame 1190 IN ULONG offs, // offset in Frame 1191 IN ULONG PSs // Packet size (in Blocks) 1192 ) 1193 { 1194 ULONG i; 1195 // mark as non-cached & free pool 1196 for(i=0; i<PSs; i++, offs++) { 1197 if(WCacheSectorAddr(block_array,offs)) { 1198 WCacheFreeSector(frame, offs); 1199 } 1200 } 1201 } // end WCacheFreePacket() 1202 1203 /* 1204 WCacheUpdatePacketComplete() is called to continue processing of packet 1205 being updated. 1206 In async mode it waits for completion of pre-read requests, 1207 initiates writes, waits for their completion and returns control to 1208 caller. 1209 Internal routine 1210 */ 1211 VOID 1212 WCacheUpdatePacketComplete( 1213 IN PW_CACHE Cache, // pointer to the Cache Control structure 1214 IN PVOID Context, // user-supplied context for IO callbacks 1215 IN OUT PW_CACHE_ASYNC* FirstWContext, // pointer to head async IO context 1216 IN OUT PW_CACHE_ASYNC* PrevWContext, // pointer to tail async IO context 1217 IN BOOLEAN FreePacket 1218 ) 1219 { 1220 PW_CACHE_ASYNC WContext = (*FirstWContext); 1221 if(!WContext) 1222 return; 1223 PW_CACHE_ASYNC NextWContext; 1224 ULONG PS = Cache->BlockSize << Cache->PacketSizeSh; // packet size (bytes) 1225 ULONG PSs = Cache->PacketSize; 1226 ULONG frame; 1227 lba_t firstLba; 1228 1229 // Walk through all chained blocks and wait 1230 // for completion of read operations. 1231 // Also invoke writes of already prepared packets. 1232 while(WContext) { 1233 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1234 WContext->State == ASYNC_STATE_READ) { 1235 // wait for async read for update 1236 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1237 1238 WContext->State = ASYNC_STATE_WRITE; 1239 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, 1240 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); 1241 } else 1242 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1243 WContext->State == ASYNC_STATE_WRITE_PRE) { 1244 // invoke physical write it the packet is prepared for writing 1245 // by previuous call to WCacheUpdatePacket() 1246 WContext->State = ASYNC_STATE_WRITE; 1247 WCacheUpdatePacket(Cache, Context, NULL, &WContext, NULL, -1, WContext->Lba, -1, -1, 1248 PS, -1, &(WContext->TransferredBytes), TRUE, ASYNC_STATE_WRITE); 1249 WContext->State = ASYNC_STATE_DONE; 1250 } else 1251 if(WContext->Cmd == ASYNC_CMD_READ && 1252 WContext->State == ASYNC_STATE_READ) { 1253 // wait for async read 1254 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1255 } 1256 WContext = WContext->NextWContext; 1257 } 1258 // Walk through all chained blocks and wait 1259 // and wait for completion of async writes (if any). 1260 // Also free temporary buffers containing already written blocks. 1261 WContext = (*FirstWContext); 1262 while(WContext) { 1263 NextWContext = WContext->NextWContext; 1264 if(WContext->Cmd == ASYNC_CMD_UPDATE && 1265 WContext->State == ASYNC_STATE_WRITE) { 1266 1267 if(!Cache->Chained) 1268 DbgWaitForSingleObject(&(WContext->PhContext.event), NULL); 1269 1270 frame = WContext->Lba >> Cache->BlocksPerFrameSh; 1271 firstLba = frame << Cache->BlocksPerFrameSh; 1272 1273 if(FreePacket) { 1274 WCacheFreePacket(Cache, frame, 1275 Cache->FrameList[frame].Frame, 1276 WContext->Lba - firstLba, PSs); 1277 } 1278 } 1279 WCacheFreeAsyncEntry(Cache, WContext); 1280 WContext = NextWContext; 1281 } 1282 (*FirstWContext) = NULL; 1283 (*PrevWContext) = NULL; 1284 } // end WCacheUpdatePacketComplete() 1285 1286 /* 1287 WCacheCheckLimits() checks if we've enough free Frame- & 1288 Block-entries under Frame- and Block-limit to feet 1289 requested Blocks. 1290 If there is not enough entries, WCache initiates flush & purge 1291 process to satisfy request. 1292 This is dispatch routine, which calls 1293 WCacheCheckLimitsR() or WCacheCheckLimitsRW() depending on 1294 media type. 1295 Internal routine 1296 */ 1297 OSSTATUS 1298 __fastcall 1299 WCacheCheckLimits( 1300 IN PW_CACHE Cache, // pointer to the Cache Control structure 1301 IN PVOID Context, // user-supplied context for IO callbacks 1302 IN lba_t ReqLba, // first LBA to access/cache 1303 IN ULONG BCount // number of Blocks to access/cache 1304 ) 1305 { 1306 /* if(!Cache->FrameCount || !Cache->BlockCount) { 1307 ASSERT(!Cache->FrameCount); 1308 ASSERT(!Cache->BlockCount); 1309 if(!Cache->FrameCount) 1310 return STATUS_SUCCESS; 1311 }*/ 1312 1313 // check if we have reached Frame or Block limit 1314 if(!Cache->FrameCount && !Cache->BlockCount) { 1315 return STATUS_SUCCESS; 1316 } 1317 1318 // check for empty frames 1319 if(Cache->FrameCount > (Cache->MaxFrames*3)/4) { 1320 ULONG frame; 1321 ULONG i; 1322 for(i=Cache->FrameCount; i>0; i--) { 1323 frame = Cache->CachedFramesList[i-1]; 1324 // check if frame is empty 1325 if(!(Cache->FrameList[frame].BlockCount)) { 1326 WCacheRemoveFrame(Cache, Context, frame); 1327 } else { 1328 ASSERT(Cache->FrameList[frame].Frame); 1329 } 1330 } 1331 } 1332 1333 if(!Cache->BlockCount) { 1334 return STATUS_SUCCESS; 1335 } 1336 1337 // invoke media-specific limit-checker 1338 switch(Cache->Mode) { 1339 case WCACHE_MODE_RAM: 1340 return WCacheCheckLimitsRAM(Cache, Context, ReqLba, BCount); 1341 case WCACHE_MODE_ROM: 1342 case WCACHE_MODE_RW: 1343 return WCacheCheckLimitsRW(Cache, Context, ReqLba, BCount); 1344 case WCACHE_MODE_R: 1345 return WCacheCheckLimitsR(Cache, Context, ReqLba, BCount); 1346 } 1347 return STATUS_DRIVER_INTERNAL_ERROR; 1348 } // end WCacheCheckLimits() 1349 1350 /* 1351 WCacheCheckLimitsRW() implements automatic flush and purge of 1352 unused blocks to keep enough free cache entries for newly 1353 read/written blocks for Random Access and ReWritable media 1354 using Read/Modify/Write technology. 1355 See also WCacheCheckLimits() 1356 Internal routine 1357 */ 1358 OSSTATUS 1359 __fastcall 1360 WCacheCheckLimitsRW( 1361 IN PW_CACHE Cache, // pointer to the Cache Control structure 1362 IN PVOID Context, // user-supplied context for IO callbacks 1363 IN lba_t ReqLba, // first LBA to access/cache 1364 IN ULONG BCount // number of Blocks to access/cache 1365 ) 1366 { 1367 ULONG frame; 1368 lba_t firstLba; 1369 lba_t* List = Cache->CachedBlocksList; 1370 lba_t lastLba; 1371 lba_t Lba; 1372 // PCHAR tmp_buff = Cache->tmp_buff; 1373 ULONG firstPos; 1374 ULONG lastPos; 1375 ULONG BSh = Cache->BlockSizeSh; 1376 ULONG BS = Cache->BlockSize; 1377 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1378 ULONG PSs = Cache->PacketSize; 1379 ULONG try_count = 0; 1380 PW_CACHE_ENTRY block_array; 1381 OSSTATUS status; 1382 SIZE_T ReadBytes; 1383 ULONG FreeFrameCount = 0; 1384 // PVOID addr; 1385 PW_CACHE_ASYNC FirstWContext = NULL; 1386 PW_CACHE_ASYNC PrevWContext = NULL; 1387 ULONG chain_count = 0; 1388 1389 if(Cache->FrameCount >= Cache->MaxFrames) { 1390 FreeFrameCount = Cache->FramesToKeepFree; 1391 } else 1392 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1393 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1394 // we need free space to grow WCache without flushing data 1395 // for some period of time 1396 FreeFrameCount = Cache->FramesToKeepFree; 1397 goto Try_Another_Frame; 1398 } 1399 // remove(flush) some frames 1400 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { 1401 Try_Another_Frame: 1402 if(!Cache->FrameCount || !Cache->BlockCount) { 1403 //ASSERT(!Cache->FrameCount); 1404 if(Cache->FrameCount) { 1405 UDFPrint(("ASSERT: Cache->FrameCount = %d, when 0 is expected\n", Cache->FrameCount)); 1406 } 1407 ASSERT(!Cache->BlockCount); 1408 if(!Cache->FrameCount) 1409 break; 1410 } 1411 1412 frame = WCacheFindFrameToRelease(Cache); 1413 #if 0 1414 if(Cache->FrameList[frame].WriteCount) { 1415 try_count++; 1416 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; 1417 } else { 1418 try_count = 0; 1419 } 1420 #else 1421 if(Cache->FrameList[frame].UpdateCount) { 1422 try_count = MAX_TRIES_FOR_NA; 1423 } else { 1424 try_count = 0; 1425 } 1426 #endif 1427 1428 if(FreeFrameCount) 1429 FreeFrameCount--; 1430 1431 firstLba = frame << Cache->BlocksPerFrameSh; 1432 lastLba = firstLba + Cache->BlocksPerFrame; 1433 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1434 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1435 block_array = Cache->FrameList[frame].Frame; 1436 1437 if(!block_array) { 1438 UDFPrint(("Hmm...\n")); 1439 BrutePoint(); 1440 return STATUS_DRIVER_INTERNAL_ERROR; 1441 } 1442 1443 while(firstPos < lastPos) { 1444 // flush packet 1445 Lba = List[firstPos] & ~(PSs-1); 1446 1447 // write packet out or prepare and add to chain (if chained mode enabled) 1448 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 1449 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 1450 1451 if(status != STATUS_PENDING) { 1452 // free memory 1453 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 1454 } 1455 1456 Lba += PSs; 1457 while((firstPos < lastPos) && (Lba > List[firstPos])) { 1458 firstPos++; 1459 } 1460 chain_count++; 1461 // write chained packets 1462 if(chain_count >= WCACHE_MAX_CHAIN) { 1463 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 1464 chain_count = 0; 1465 } 1466 } 1467 // remove flushed blocks from all lists 1468 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1469 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1470 1471 WCacheRemoveFrame(Cache, Context, frame); 1472 } 1473 1474 // check if we try to read too much data 1475 if(BCount > Cache->MaxBlocks) { 1476 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1477 return STATUS_INVALID_PARAMETER; 1478 } 1479 1480 // remove(flush) packet 1481 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1482 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1483 try_count = 0; 1484 Try_Another_Block: 1485 1486 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); 1487 if(Lba == WCACHE_INVALID_LBA) { 1488 ASSERT(!Cache->FrameCount); 1489 ASSERT(!Cache->BlockCount); 1490 break; 1491 } 1492 frame = Lba >> Cache->BlocksPerFrameSh; 1493 firstLba = frame << Cache->BlocksPerFrameSh; 1494 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 1495 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 1496 block_array = Cache->FrameList[frame].Frame; 1497 if(!block_array) { 1498 // write already prepared blocks to disk and return error 1499 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1500 ASSERT(FALSE); 1501 return STATUS_DRIVER_INTERNAL_ERROR; 1502 } 1503 1504 // write packet out or prepare and add to chain (if chained mode enabled) 1505 status = WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 1506 Lba, BSh, BS, PS, PSs, &ReadBytes, (try_count >= MAX_TRIES_FOR_NA), ASYNC_STATE_NONE); 1507 1508 if(status == STATUS_RETRY) { 1509 try_count++; 1510 goto Try_Another_Block; 1511 } 1512 1513 // free memory 1514 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 1515 1516 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 1517 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 1518 // check if frame is empty 1519 if(!(Cache->FrameList[frame].BlockCount)) { 1520 WCacheRemoveFrame(Cache, Context, frame); 1521 } else { 1522 ASSERT(Cache->FrameList[frame].Frame); 1523 } 1524 chain_count++; 1525 if(chain_count >= WCACHE_MAX_CHAIN) { 1526 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 1527 chain_count = 0; 1528 } 1529 } 1530 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 1531 return STATUS_SUCCESS; 1532 } // end WCacheCheckLimitsRW() 1533 1534 OSSTATUS 1535 __fastcall 1536 WCacheFlushBlocksRAM( 1537 IN PW_CACHE Cache, // pointer to the Cache Control structure 1538 IN PVOID Context, // user-supplied context for IO callbacks 1539 PW_CACHE_ENTRY block_array, 1540 lba_t* List, 1541 ULONG firstPos, 1542 ULONG lastPos, 1543 BOOLEAN Purge 1544 ) 1545 { 1546 ULONG frame; 1547 lba_t Lba; 1548 lba_t PrevLba; 1549 lba_t firstLba; 1550 PCHAR tmp_buff = NULL; 1551 ULONG n; 1552 ULONG BSh = Cache->BlockSizeSh; 1553 ULONG BS = Cache->BlockSize; 1554 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1555 ULONG PSs = Cache->PacketSize; 1556 SIZE_T _WrittenBytes; 1557 OSSTATUS status = STATUS_SUCCESS; 1558 1559 frame = List[firstPos] >> Cache->BlocksPerFrameSh; 1560 firstLba = frame << Cache->BlocksPerFrameSh; 1561 1562 while(firstPos < lastPos) { 1563 // flush blocks 1564 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1565 Lba = List[firstPos]; 1566 if(!WCacheGetModFlag(block_array, Lba - firstLba)) { 1567 // free memory 1568 if(Purge) { 1569 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, 1); 1570 } 1571 firstPos++; 1572 continue; 1573 } 1574 tmp_buff = Cache->tmp_buff; 1575 PrevLba = Lba; 1576 n=1; 1577 while((firstPos+n < lastPos) && 1578 (List[firstPos+n] == PrevLba+1)) { 1579 PrevLba++; 1580 if(!WCacheGetModFlag(block_array, PrevLba - firstLba)) 1581 break; 1582 DbgCopyMemory(tmp_buff + (n << BSh), 1583 (PVOID)WCacheSectorAddr(block_array, PrevLba - firstLba), 1584 BS); 1585 n++; 1586 if(n >= PSs) 1587 break; 1588 } 1589 if(n > 1) { 1590 DbgCopyMemory(tmp_buff, 1591 (PVOID)WCacheSectorAddr(block_array, Lba - firstLba), 1592 BS); 1593 } else { 1594 tmp_buff = (PCHAR)WCacheSectorAddr(block_array, Lba - firstLba); 1595 } 1596 // write sectors out 1597 status = Cache->WriteProc(Context, tmp_buff, n<<BSh, Lba, &_WrittenBytes, 0); 1598 if(!OS_SUCCESS(status)) { 1599 status = WCacheRaiseIoError(Cache, Context, status, Lba, n, tmp_buff, WCACHE_W_OP, NULL); 1600 if(!OS_SUCCESS(status)) { 1601 BrutePoint(); 1602 } 1603 } 1604 firstPos += n; 1605 if(Purge) { 1606 // free memory 1607 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, n); 1608 } else { 1609 // clear Modified flag 1610 ULONG i; 1611 Lba -= firstLba; 1612 for(i=0; i<n; i++) { 1613 WCacheClrModFlag(block_array, Lba+i); 1614 } 1615 } 1616 } 1617 1618 return status; 1619 } // end WCacheFlushBlocksRAM() 1620 1621 /* 1622 WCacheCheckLimitsRAM() implements automatic flush and purge of 1623 unused blocks to keep enough free cache entries for newly 1624 read/written blocks for Random Access media. 1625 See also WCacheCheckLimits() 1626 Internal routine 1627 */ 1628 OSSTATUS 1629 __fastcall 1630 WCacheCheckLimitsRAM( 1631 IN PW_CACHE Cache, // pointer to the Cache Control structure 1632 IN PVOID Context, // user-supplied context for IO callbacks 1633 IN lba_t ReqLba, // first LBA to access/cache 1634 IN ULONG BCount // number of Blocks to access/cache 1635 ) 1636 { 1637 ULONG frame; 1638 lba_t firstLba; 1639 lba_t* List = Cache->CachedBlocksList; 1640 lba_t lastLba; 1641 lba_t Lba; 1642 // PCHAR tmp_buff = Cache->tmp_buff; 1643 ULONG firstPos; 1644 ULONG lastPos; 1645 // ULONG BSh = Cache->BlockSizeSh; 1646 // ULONG BS = Cache->BlockSize; 1647 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 1648 ULONG PSs = Cache->PacketSize; 1649 // ULONG try_count = 0; 1650 PW_CACHE_ENTRY block_array; 1651 // OSSTATUS status; 1652 ULONG FreeFrameCount = 0; 1653 // PVOID addr; 1654 1655 if(Cache->FrameCount >= Cache->MaxFrames) { 1656 FreeFrameCount = Cache->FramesToKeepFree; 1657 } else 1658 if((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1659 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1660 // we need free space to grow WCache without flushing data 1661 // for some period of time 1662 FreeFrameCount = Cache->FramesToKeepFree; 1663 goto Try_Another_Frame; 1664 } 1665 // remove(flush) some frames 1666 while((Cache->FrameCount >= Cache->MaxFrames) || FreeFrameCount) { 1667 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1668 Try_Another_Frame: 1669 if(!Cache->FrameCount || !Cache->BlockCount) { 1670 ASSERT(!Cache->FrameCount); 1671 ASSERT(!Cache->BlockCount); 1672 if(!Cache->FrameCount) 1673 break; 1674 } 1675 1676 frame = WCacheFindFrameToRelease(Cache); 1677 #if 0 1678 if(Cache->FrameList[frame].WriteCount) { 1679 try_count++; 1680 if(try_count < MAX_TRIES_FOR_NA) goto Try_Another_Frame; 1681 } else { 1682 try_count = 0; 1683 } 1684 #else 1685 /* 1686 if(Cache->FrameList[frame].UpdateCount) { 1687 try_count = MAX_TRIES_FOR_NA; 1688 } else { 1689 try_count = 0; 1690 } 1691 */ 1692 #endif 1693 1694 if(FreeFrameCount) 1695 FreeFrameCount--; 1696 1697 firstLba = frame << Cache->BlocksPerFrameSh; 1698 lastLba = firstLba + Cache->BlocksPerFrame; 1699 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1700 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1701 block_array = Cache->FrameList[frame].Frame; 1702 1703 if(!block_array) { 1704 UDFPrint(("Hmm...\n")); 1705 BrutePoint(); 1706 return STATUS_DRIVER_INTERNAL_ERROR; 1707 } 1708 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1709 1710 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1711 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1712 WCacheRemoveFrame(Cache, Context, frame); 1713 } 1714 1715 // check if we try to read too much data 1716 if(BCount > Cache->MaxBlocks) { 1717 return STATUS_INVALID_PARAMETER; 1718 } 1719 1720 // remove(flush) packet 1721 while((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 1722 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) { 1723 // try_count = 0; 1724 //Try_Another_Block: 1725 1726 ASSERT(Cache->FrameCount <= Cache->MaxFrames); 1727 Lba = WCacheFindLbaToRelease(Cache) & ~(PSs-1); 1728 if(Lba == WCACHE_INVALID_LBA) { 1729 ASSERT(!Cache->FrameCount); 1730 ASSERT(!Cache->BlockCount); 1731 break; 1732 } 1733 frame = Lba >> Cache->BlocksPerFrameSh; 1734 firstLba = frame << Cache->BlocksPerFrameSh; 1735 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 1736 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 1737 block_array = Cache->FrameList[frame].Frame; 1738 if(!block_array) { 1739 ASSERT(FALSE); 1740 return STATUS_DRIVER_INTERNAL_ERROR; 1741 } 1742 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1743 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 1744 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 1745 // check if frame is empty 1746 if(!(Cache->FrameList[frame].BlockCount)) { 1747 WCacheRemoveFrame(Cache, Context, frame); 1748 } else { 1749 ASSERT(Cache->FrameList[frame].Frame); 1750 } 1751 } 1752 return STATUS_SUCCESS; 1753 } // end WCacheCheckLimitsRAM() 1754 1755 /* 1756 WCachePurgeAllRAM() 1757 Internal routine 1758 */ 1759 OSSTATUS 1760 __fastcall 1761 WCachePurgeAllRAM( 1762 IN PW_CACHE Cache, // pointer to the Cache Control structure 1763 IN PVOID Context // user-supplied context for IO callbacks 1764 ) 1765 { 1766 ULONG frame; 1767 lba_t firstLba; 1768 lba_t* List = Cache->CachedBlocksList; 1769 lba_t lastLba; 1770 ULONG firstPos; 1771 ULONG lastPos; 1772 PW_CACHE_ENTRY block_array; 1773 // OSSTATUS status; 1774 1775 // remove(flush) some frames 1776 while(Cache->FrameCount) { 1777 1778 frame = Cache->CachedFramesList[0]; 1779 1780 firstLba = frame << Cache->BlocksPerFrameSh; 1781 lastLba = firstLba + Cache->BlocksPerFrame; 1782 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1783 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1784 block_array = Cache->FrameList[frame].Frame; 1785 1786 if(!block_array) { 1787 UDFPrint(("Hmm...\n")); 1788 BrutePoint(); 1789 return STATUS_DRIVER_INTERNAL_ERROR; 1790 } 1791 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, TRUE); 1792 1793 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), firstLba, Cache->BlocksPerFrame); 1794 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1795 WCacheRemoveFrame(Cache, Context, frame); 1796 } 1797 1798 ASSERT(!Cache->FrameCount); 1799 ASSERT(!Cache->BlockCount); 1800 return STATUS_SUCCESS; 1801 } // end WCachePurgeAllRAM() 1802 1803 /* 1804 WCacheFlushAllRAM() 1805 Internal routine 1806 */ 1807 OSSTATUS 1808 __fastcall 1809 WCacheFlushAllRAM( 1810 IN PW_CACHE Cache, // pointer to the Cache Control structure 1811 IN PVOID Context // user-supplied context for IO callbacks 1812 ) 1813 { 1814 ULONG frame; 1815 lba_t firstLba; 1816 lba_t* List = Cache->CachedBlocksList; 1817 lba_t lastLba; 1818 ULONG firstPos; 1819 ULONG lastPos; 1820 PW_CACHE_ENTRY block_array; 1821 // OSSTATUS status; 1822 1823 // flush frames 1824 while(Cache->WriteCount) { 1825 1826 frame = Cache->CachedModifiedBlocksList[0] >> Cache->BlocksPerFrameSh; 1827 1828 firstLba = frame << Cache->BlocksPerFrameSh; 1829 lastLba = firstLba + Cache->BlocksPerFrame; 1830 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, firstLba); 1831 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, lastLba); 1832 block_array = Cache->FrameList[frame].Frame; 1833 1834 if(!block_array) { 1835 UDFPrint(("Hmm...\n")); 1836 BrutePoint(); 1837 return STATUS_DRIVER_INTERNAL_ERROR; 1838 } 1839 WCacheFlushBlocksRAM(Cache, Context, block_array, List, firstPos, lastPos, FALSE); 1840 1841 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), firstLba, Cache->BlocksPerFrame); 1842 } 1843 1844 return STATUS_SUCCESS; 1845 } // end WCacheFlushAllRAM() 1846 1847 /* 1848 WCachePreReadPacket__() reads & caches the whole packet containing 1849 requested LBA. This routine just caches data, it doesn't copy anything 1850 to user buffer. 1851 In general we have no user buffer here... ;) 1852 Public routine 1853 */ 1854 OSSTATUS 1855 WCachePreReadPacket__( 1856 IN PW_CACHE Cache, // pointer to the Cache Control structure 1857 IN PVOID Context, // user-supplied context for IO callbacks 1858 IN lba_t Lba // LBA to cache together with whole packet 1859 ) 1860 { 1861 ULONG frame; 1862 OSSTATUS status = STATUS_SUCCESS; 1863 PW_CACHE_ENTRY block_array; 1864 ULONG BSh = Cache->BlockSizeSh; 1865 ULONG BS = Cache->BlockSize; 1866 PCHAR addr; 1867 SIZE_T _ReadBytes; 1868 ULONG PS = Cache->PacketSize; // (in blocks) 1869 ULONG BCount = PS; 1870 ULONG i, n, err_count; 1871 BOOLEAN sector_added = FALSE; 1872 ULONG block_type; 1873 BOOLEAN zero = FALSE;//TRUE; 1874 /* 1875 ULONG first_zero=0, last_zero=0; 1876 BOOLEAN count_first_zero = TRUE; 1877 */ 1878 1879 Lba &= ~(PS-1); 1880 frame = Lba >> Cache->BlocksPerFrameSh; 1881 i = Lba - (frame << Cache->BlocksPerFrameSh); 1882 1883 // assume successful operation 1884 block_array = Cache->FrameList[frame].Frame; 1885 if(!block_array) { 1886 ASSERT(Cache->FrameCount < Cache->MaxFrames); 1887 block_array = WCacheInitFrame(Cache, Context, frame); 1888 if(!block_array) 1889 return STATUS_INSUFFICIENT_RESOURCES; 1890 } 1891 1892 // skip cached extent (if any) 1893 n=0; 1894 while((n < BCount) && 1895 (n < Cache->BlocksPerFrame)) { 1896 1897 addr = (PCHAR)WCacheSectorAddr(block_array, i+n); 1898 block_type = Cache->CheckUsedProc(Context, Lba+n); 1899 if(/*WCacheGetBadFlag(block_array,i+n)*/ 1900 block_type & WCACHE_BLOCK_BAD) { 1901 // bad packet. no pre-read 1902 return STATUS_DEVICE_DATA_ERROR; 1903 } 1904 if(!(block_type & WCACHE_BLOCK_ZERO)) { 1905 zero = FALSE; 1906 //count_first_zero = FALSE; 1907 //last_zero = 0; 1908 if(!addr) { 1909 // sector is not cached, stop search 1910 break; 1911 } 1912 } else { 1913 /* 1914 if(count_first_zero) { 1915 first_zero++; 1916 } 1917 last_zero++; 1918 */ 1919 } 1920 n++; 1921 } 1922 // do nothing if all sectors are already cached 1923 if(n < BCount) { 1924 1925 // read whole packet 1926 if(!zero) { 1927 status = Cache->ReadProc(Context, Cache->tmp_buff_r, PS<<BSh, Lba, &_ReadBytes, PH_TMP_BUFFER); 1928 if(!OS_SUCCESS(status)) { 1929 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Cache->tmp_buff_r, WCACHE_R_OP, NULL); 1930 } 1931 } else { 1932 status = STATUS_SUCCESS; 1933 //RtlZeroMemory(Cache->tmp_buff_r, PS<<BSh); 1934 _ReadBytes = PS<<BSh; 1935 } 1936 if(OS_SUCCESS(status)) { 1937 // and now we'll copy them to cache 1938 for(n=0; n<BCount; n++, i++) { 1939 if(WCacheSectorAddr(block_array,i)) { 1940 continue; 1941 } 1942 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 1943 if(!addr) { 1944 BrutePoint(); 1945 break; 1946 } 1947 sector_added = TRUE; 1948 if(!zero) { 1949 DbgCopyMemory(addr, Cache->tmp_buff_r+(n<<BSh), BS); 1950 } else { 1951 RtlZeroMemory(addr, BS); 1952 } 1953 Cache->FrameList[frame].BlockCount++; 1954 } 1955 } else { 1956 // read sectors one by one and copy them to cache 1957 // unreadable sectors will be treated as zero-filled 1958 err_count = 0; 1959 for(n=0; n<BCount; n++, i++) { 1960 if(WCacheSectorAddr(block_array,i)) { 1961 continue; 1962 } 1963 addr = block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 1964 if(!addr) { 1965 BrutePoint(); 1966 break; 1967 } 1968 sector_added = TRUE; 1969 status = Cache->ReadProc(Context, Cache->tmp_buff_r, BS, Lba+n, &_ReadBytes, PH_TMP_BUFFER); 1970 if(!OS_SUCCESS(status)) { 1971 status = WCacheRaiseIoError(Cache, Context, status, Lba+n, 1, Cache->tmp_buff_r, WCACHE_R_OP, NULL); 1972 if(!OS_SUCCESS(status)) { 1973 err_count++; 1974 } 1975 } 1976 if(!zero && OS_SUCCESS(status)) { 1977 DbgCopyMemory(addr, Cache->tmp_buff_r, BS); 1978 } else 1979 if(Cache->RememberBB) { 1980 RtlZeroMemory(addr, BS); 1981 /* 1982 if(!OS_SUCCESS(status)) { 1983 WCacheSetBadFlag(block_array,i); 1984 } 1985 */ 1986 } 1987 Cache->FrameList[frame].BlockCount++; 1988 if(err_count >= 2) { 1989 break; 1990 } 1991 } 1992 // _ReadBytes = n<<BSh; 1993 } 1994 } 1995 1996 // we know the number of unread sectors if an error occured 1997 // so we can need to update BlockCount 1998 // return number of read bytes 1999 if(sector_added) 2000 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, n); 2001 2002 return status; 2003 } // end WCachePreReadPacket__() 2004 2005 /* 2006 WCacheReadBlocks__() reads data from cache or 2007 read it form media and store in cache. 2008 Public routine 2009 */ 2010 OSSTATUS 2011 WCacheReadBlocks__( 2012 IN PW_CACHE Cache, // pointer to the Cache Control structure 2013 IN PVOID Context, // user-supplied context for IO callbacks 2014 IN PCHAR Buffer, // user-supplied buffer for read blocks 2015 IN lba_t Lba, // LBA to start read from 2016 IN ULONG BCount, // number of blocks to be read 2017 OUT PSIZE_T ReadBytes, // user-supplied pointer to ULONG that will 2018 // recieve number of actually read bytes 2019 IN BOOLEAN CachedOnly // specifies that cache is already locked 2020 ) 2021 { 2022 ULONG frame; 2023 ULONG i, saved_i, saved_BC = BCount, n; 2024 OSSTATUS status = STATUS_SUCCESS; 2025 PW_CACHE_ENTRY block_array; 2026 ULONG BSh = Cache->BlockSizeSh; 2027 SIZE_T BS = Cache->BlockSize; 2028 PCHAR addr; 2029 ULONG to_read, saved_to_read; 2030 // PCHAR saved_buff = Buffer; 2031 SIZE_T _ReadBytes; 2032 ULONG PS = Cache->PacketSize; 2033 ULONG MaxR = Cache->MaxBytesToRead; 2034 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n 2035 ULONG d; 2036 ULONG block_type; 2037 2038 WcPrint(("WC:R %x (%x)\n", Lba, BCount)); 2039 2040 (*ReadBytes) = 0; 2041 // check if we try to read too much data 2042 if(BCount >= Cache->MaxBlocks) { 2043 i = 0; 2044 if(CachedOnly) { 2045 status = STATUS_INVALID_PARAMETER; 2046 goto EO_WCache_R2; 2047 } 2048 while(TRUE) { 2049 status = WCacheReadBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, PS, &_ReadBytes, FALSE); 2050 (*ReadBytes) += _ReadBytes; 2051 if(!OS_SUCCESS(status) || (BCount <= PS)) break; 2052 BCount -= PS; 2053 Lba += PS; 2054 i += PS; 2055 } 2056 return status; 2057 } 2058 // check if we try to access beyond cached area 2059 if((Lba < Cache->FirstLba) || 2060 (Lba + BCount - 1 > Cache->LastLba)) { 2061 status = Cache->ReadProc(Context, Buffer, BCount, Lba, ReadBytes, 0); 2062 if(!OS_SUCCESS(status)) { 2063 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_R_OP, NULL); 2064 } 2065 return status; 2066 } 2067 if(!CachedOnly) { 2068 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2069 } 2070 2071 frame = Lba >> Cache->BlocksPerFrameSh; 2072 i = Lba - (frame << Cache->BlocksPerFrameSh); 2073 2074 if(Cache->CacheWholePacket && (BCount < PS)) { 2075 if(!CachedOnly && 2076 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba & ~(PS-1), PS*2)) ) { 2077 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2078 return status; 2079 } 2080 } else { 2081 if(!CachedOnly && 2082 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { 2083 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2084 return status; 2085 } 2086 } 2087 if(!CachedOnly) { 2088 // convert to shared 2089 // ExConvertExclusiveToSharedLite(&(Cache->WCacheLock)); 2090 } 2091 2092 // pre-read packet. It is very useful for 2093 // highly fragmented files 2094 if(Cache->CacheWholePacket && (BCount < PS)) { 2095 // status = WCacheReadBlocks__(Cache, Context, Cache->tmp_buff_r, Lba & (~PacketMask), PS, &_ReadBytes, TRUE); 2096 // we should not perform IO if user requested CachedOnly data 2097 if(!CachedOnly) { 2098 status = WCachePreReadPacket__(Cache, Context, Lba); 2099 } 2100 status = STATUS_SUCCESS; 2101 } 2102 2103 // assume successful operation 2104 block_array = Cache->FrameList[frame].Frame; 2105 if(!block_array) { 2106 ASSERT(!CachedOnly); 2107 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2108 block_array = WCacheInitFrame(Cache, Context, frame); 2109 if(!block_array) { 2110 status = STATUS_INSUFFICIENT_RESOURCES; 2111 goto EO_WCache_R; 2112 } 2113 } 2114 2115 Cache->FrameList[frame].AccessCount++; 2116 while(BCount) { 2117 if(i >= Cache->BlocksPerFrame) { 2118 frame++; 2119 block_array = Cache->FrameList[frame].Frame; 2120 i -= Cache->BlocksPerFrame; 2121 } 2122 if(!block_array) { 2123 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2124 block_array = WCacheInitFrame(Cache, Context, frame); 2125 if(!block_array) { 2126 status = STATUS_INSUFFICIENT_RESOURCES; 2127 goto EO_WCache_R; 2128 } 2129 } 2130 // 'read' cached extent (if any) 2131 // it is just copying 2132 while(BCount && 2133 (i < Cache->BlocksPerFrame) && 2134 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 2135 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); 2136 if(block_type & WCACHE_BLOCK_BAD) { 2137 //if(WCacheGetBadFlag(block_array,i)) { 2138 status = STATUS_DEVICE_DATA_ERROR; 2139 goto EO_WCache_R; 2140 } 2141 DbgCopyMemory(Buffer, addr, BS); 2142 Buffer += BS; 2143 *ReadBytes += BS; 2144 i++; 2145 BCount--; 2146 } 2147 // read non-cached packet-size-aligned extent (if any) 2148 // now we'll calculate total length & decide if it has enough size 2149 if(!((d = Lba+saved_BC-BCount) & PacketMask) && d ) { 2150 n = 0; 2151 while(BCount && 2152 (i < Cache->BlocksPerFrame) && 2153 (!WCacheSectorAddr(block_array, i)) ) { 2154 n++; 2155 BCount--; 2156 } 2157 BCount += n; 2158 n &= ~PacketMask; 2159 if(n>PS) { 2160 if(!OS_SUCCESS(status = Cache->ReadProc(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_ReadBytes, 0))) { 2161 status = WCacheRaiseIoError(Cache, Context, status, Lba+saved_BC-BCount, n, Buffer, WCACHE_R_OP, NULL); 2162 if(!OS_SUCCESS(status)) { 2163 goto EO_WCache_R; 2164 } 2165 } 2166 // WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2167 BCount -= n; 2168 Lba += saved_BC - BCount; 2169 saved_BC = BCount; 2170 i += n; 2171 Buffer += BS*n; 2172 *ReadBytes += BS*n; 2173 } 2174 // } else { 2175 // UDFPrint(("Unaligned\n")); 2176 } 2177 // read non-cached extent (if any) 2178 // firstable, we'll get total number of sectors to read 2179 to_read = 0; 2180 saved_i = i; 2181 d = BCount; 2182 while(d && 2183 (i < Cache->BlocksPerFrame) && 2184 (!WCacheSectorAddr(block_array, i)) ) { 2185 i++; 2186 to_read += BS; 2187 d--; 2188 } 2189 // read some not cached sectors 2190 if(to_read) { 2191 i = saved_i; 2192 saved_to_read = to_read; 2193 d = BCount - d; 2194 // split request if necessary 2195 if(saved_to_read > MaxR) { 2196 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2197 n = MaxR >> BSh; 2198 do { 2199 status = Cache->ReadProc(Context, Buffer, MaxR, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); 2200 *ReadBytes += _ReadBytes; 2201 if(!OS_SUCCESS(status)) { 2202 _ReadBytes &= ~(BS-1); 2203 BCount -= _ReadBytes >> BSh; 2204 saved_to_read -= _ReadBytes; 2205 Buffer += _ReadBytes; 2206 saved_BC = BCount; 2207 goto store_read_data_1; 2208 } 2209 Buffer += MaxR; 2210 saved_to_read -= MaxR; 2211 i += n; 2212 BCount -= n; 2213 d -= n; 2214 } while(saved_to_read > MaxR); 2215 saved_BC = BCount; 2216 } 2217 if(saved_to_read) { 2218 status = Cache->ReadProc(Context, Buffer, saved_to_read, i + (frame << Cache->BlocksPerFrameSh), &_ReadBytes, 0); 2219 *ReadBytes += _ReadBytes; 2220 if(!OS_SUCCESS(status)) { 2221 _ReadBytes &= ~(BS-1); 2222 BCount -= _ReadBytes >> BSh; 2223 saved_to_read -= _ReadBytes; 2224 Buffer += _ReadBytes; 2225 goto store_read_data_1; 2226 } 2227 Buffer += saved_to_read; 2228 saved_to_read = 0; 2229 BCount -= d; 2230 } 2231 2232 store_read_data_1: 2233 // and now we'll copy them to cache 2234 2235 // 2236 Buffer -= (to_read - saved_to_read); 2237 i = saved_i; 2238 while(to_read - saved_to_read) { 2239 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2240 if(!block_array[i].Sector) { 2241 BCount += to_read >> BSh; 2242 status = STATUS_INSUFFICIENT_RESOURCES; 2243 goto EO_WCache_R; 2244 } 2245 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2246 Cache->FrameList[frame].BlockCount++; 2247 i++; 2248 Buffer += BS; 2249 to_read -= BS; 2250 } 2251 if(!OS_SUCCESS(status)) 2252 goto EO_WCache_R; 2253 to_read = 0; 2254 } 2255 } 2256 2257 EO_WCache_R: 2258 2259 // we know the number of unread sectors if an error occured 2260 // so we can need to update BlockCount 2261 // return number of read bytes 2262 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2263 // Cache->FrameList[frame].BlockCount -= BCount; 2264 EO_WCache_R2: 2265 if(!CachedOnly) { 2266 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2267 } 2268 2269 return status; 2270 } // end WCacheReadBlocks__() 2271 2272 /* 2273 WCacheWriteBlocks__() writes data to cache. 2274 Data is written directly to media if: 2275 1) requested block is Packet-aligned 2276 2) requested Lba(s) lays beyond cached area 2277 Public routine 2278 */ 2279 OSSTATUS 2280 WCacheWriteBlocks__( 2281 IN PW_CACHE Cache, // pointer to the Cache Control structure 2282 IN PVOID Context, // user-supplied context for IO callbacks 2283 IN PCHAR Buffer, // user-supplied buffer containing data to be written 2284 IN lba_t Lba, // LBA to start write from 2285 IN ULONG BCount, // number of blocks to be written 2286 OUT PSIZE_T WrittenBytes, // user-supplied pointer to ULONG that will 2287 // recieve number of actually written bytes 2288 IN BOOLEAN CachedOnly // specifies that cache is already locked 2289 ) 2290 { 2291 ULONG frame; 2292 ULONG i, saved_BC = BCount, n, d; 2293 OSSTATUS status = STATUS_SUCCESS; 2294 PW_CACHE_ENTRY block_array; 2295 ULONG BSh = Cache->BlockSizeSh; 2296 ULONG BS = Cache->BlockSize; 2297 PCHAR addr; 2298 // PCHAR saved_buff = Buffer; 2299 SIZE_T _WrittenBytes; 2300 ULONG PS = Cache->PacketSize; 2301 ULONG PacketMask = PS-1; // here we assume that Packet Size value is 2^n 2302 ULONG block_type; 2303 // BOOLEAN Aligned = FALSE; 2304 2305 BOOLEAN WriteThrough = FALSE; 2306 lba_t WTh_Lba; 2307 ULONG WTh_BCount; 2308 2309 WcPrint(("WC:W %x (%x)\n", Lba, BCount)); 2310 2311 *WrittenBytes = 0; 2312 // UDFPrint(("BCount:%x\n",BCount)); 2313 // check if we try to read too much data 2314 if(BCount >= Cache->MaxBlocks) { 2315 i = 0; 2316 if(CachedOnly) { 2317 status = STATUS_INVALID_PARAMETER; 2318 goto EO_WCache_W2; 2319 } 2320 while(TRUE) { 2321 // UDFPrint((" BCount:%x\n",BCount)); 2322 status = WCacheWriteBlocks__(Cache, Context, Buffer + (i<<BSh), Lba, min(PS,BCount), &_WrittenBytes, FALSE); 2323 (*WrittenBytes) += _WrittenBytes; 2324 BCount -= PS; 2325 Lba += PS; 2326 i += PS; 2327 if(!OS_SUCCESS(status) || (BCount < PS)) 2328 return status; 2329 } 2330 } 2331 // check if we try to access beyond cached area 2332 if((Lba < Cache->FirstLba) || 2333 (Lba + BCount - 1 > Cache->LastLba)) { 2334 return STATUS_INVALID_PARAMETER; 2335 } 2336 if(!CachedOnly) { 2337 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2338 } 2339 2340 frame = Lba >> Cache->BlocksPerFrameSh; 2341 i = Lba - (frame << Cache->BlocksPerFrameSh); 2342 2343 if(!CachedOnly && 2344 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, BCount))) { 2345 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2346 return status; 2347 } 2348 2349 // assume successful operation 2350 block_array = Cache->FrameList[frame].Frame; 2351 if(!block_array) { 2352 2353 if(BCount && !(BCount & (PS-1)) && !(Lba & (PS-1)) && 2354 (Cache->Mode != WCACHE_MODE_R) && 2355 (i+BCount <= Cache->BlocksPerFrame) && 2356 !Cache->NoWriteThrough) { 2357 status = Cache->WriteProc(Context, Buffer, BCount<<BSh, Lba, WrittenBytes, 0); 2358 if(!OS_SUCCESS(status)) { 2359 status = WCacheRaiseIoError(Cache, Context, status, Lba, BCount, Buffer, WCACHE_W_OP, NULL); 2360 } 2361 goto EO_WCache_W2; 2362 } 2363 2364 ASSERT(!CachedOnly); 2365 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2366 block_array = WCacheInitFrame(Cache, Context, frame); 2367 if(!block_array) { 2368 status = STATUS_INSUFFICIENT_RESOURCES; 2369 goto EO_WCache_W; 2370 } 2371 } 2372 2373 if(Cache->Mode == WCACHE_MODE_RAM && 2374 BCount && 2375 // !(Lba & (PS-1)) && 2376 (!(BCount & (PS-1)) || (BCount > PS)) ) { 2377 WriteThrough = TRUE; 2378 WTh_Lba = Lba; 2379 WTh_BCount = BCount; 2380 } else 2381 if(Cache->Mode == WCACHE_MODE_RAM && 2382 ((Lba & ~PacketMask) != ((Lba+BCount-1) & ~PacketMask)) 2383 ) { 2384 WriteThrough = TRUE; 2385 WTh_Lba = Lba & ~PacketMask; 2386 WTh_BCount = PS; 2387 } 2388 2389 Cache->FrameList[frame].UpdateCount++; 2390 // UDFPrint((" BCount:%x\n",BCount)); 2391 while(BCount) { 2392 if(i >= Cache->BlocksPerFrame) { 2393 frame++; 2394 block_array = Cache->FrameList[frame].Frame; 2395 i -= Cache->BlocksPerFrame; 2396 } 2397 if(!block_array) { 2398 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2399 block_array = WCacheInitFrame(Cache, Context, frame); 2400 if(!block_array) { 2401 status = STATUS_INSUFFICIENT_RESOURCES; 2402 goto EO_WCache_W; 2403 } 2404 } 2405 // 'write' cached extent (if any) 2406 // it is just copying 2407 while(BCount && 2408 (i < Cache->BlocksPerFrame) && 2409 (addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 2410 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",addr, Buffer, BS, BCount)); 2411 block_type = Cache->CheckUsedProc(Context, Lba+saved_BC-BCount); 2412 if(Cache->NoWriteBB && 2413 /*WCacheGetBadFlag(block_array,i)*/ 2414 (block_type & WCACHE_BLOCK_BAD)) { 2415 // bad packet. no cached write 2416 status = STATUS_DEVICE_DATA_ERROR; 2417 goto EO_WCache_W; 2418 } 2419 DbgCopyMemory(addr, Buffer, BS); 2420 WCacheSetModFlag(block_array, i); 2421 Buffer += BS; 2422 *WrittenBytes += BS; 2423 i++; 2424 BCount--; 2425 } 2426 // write non-cached not-aligned extent (if any) till aligned one 2427 while(BCount && 2428 (i & PacketMask) && 2429 (Cache->Mode != WCACHE_MODE_R) && 2430 (i < Cache->BlocksPerFrame) && 2431 (!WCacheSectorAddr(block_array, i)) ) { 2432 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2433 if(!block_array[i].Sector) { 2434 status = STATUS_INSUFFICIENT_RESOURCES; 2435 goto EO_WCache_W; 2436 } 2437 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); 2438 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2439 WCacheSetModFlag(block_array, i); 2440 i++; 2441 Buffer += BS; 2442 *WrittenBytes += BS; 2443 BCount--; 2444 Cache->FrameList[frame].BlockCount ++; 2445 } 2446 // write non-cached packet-size-aligned extent (if any) 2447 // now we'll calculate total length & decide if has enough size 2448 if(!Cache->NoWriteThrough 2449 && 2450 ( !(i & PacketMask) || 2451 ((Cache->Mode == WCACHE_MODE_R) && (BCount >= PS)) )) { 2452 n = 0; 2453 while(BCount && 2454 (i < Cache->BlocksPerFrame) && 2455 (!WCacheSectorAddr(block_array, i)) ) { 2456 n++; 2457 BCount--; 2458 } 2459 BCount += n; 2460 n &= ~PacketMask; 2461 // if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE))) 2462 if(n) { 2463 // add previously written data to list 2464 d = saved_BC - BCount; 2465 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, d); 2466 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); 2467 Lba += d; 2468 saved_BC = BCount; 2469 2470 while(n) { 2471 if(Cache->Mode == WCACHE_MODE_R) 2472 Cache->UpdateRelocProc(Context, Lba, NULL, PS); 2473 if(!OS_SUCCESS(status = Cache->WriteProc(Context, Buffer, PS<<BSh, Lba, &_WrittenBytes, 0))) { 2474 status = WCacheRaiseIoError(Cache, Context, status, Lba, PS, Buffer, WCACHE_W_OP, NULL); 2475 if(!OS_SUCCESS(status)) { 2476 goto EO_WCache_W; 2477 } 2478 } 2479 BCount -= PS; 2480 Lba += PS; 2481 saved_BC = BCount; 2482 i += PS; 2483 Buffer += PS<<BSh; 2484 *WrittenBytes += PS<<BSh; 2485 n-=PS; 2486 } 2487 } 2488 } 2489 // write non-cached not-aligned extent (if any) 2490 while(BCount && 2491 (i < Cache->BlocksPerFrame) && 2492 (!WCacheSectorAddr(block_array, i)) ) { 2493 block_array[i].Sector = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 2494 if(!block_array[i].Sector) { 2495 status = STATUS_INSUFFICIENT_RESOURCES; 2496 goto EO_WCache_W; 2497 } 2498 // UDFPrint(("addr:%x:Buffer:%x:BS:%x:BCount:%x\n",block_array[i].Sector, Buffer, BS, BCount)); 2499 DbgCopyMemory(block_array[i].Sector, Buffer, BS); 2500 WCacheSetModFlag(block_array, i); 2501 i++; 2502 Buffer += BS; 2503 *WrittenBytes += BS; 2504 BCount--; 2505 Cache->FrameList[frame].BlockCount ++; 2506 } 2507 } 2508 2509 EO_WCache_W: 2510 2511 // we know the number of unread sectors if an error occured 2512 // so we can need to update BlockCount 2513 // return number of read bytes 2514 WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount); 2515 WCacheInsertRangeToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, saved_BC - BCount); 2516 2517 if(WriteThrough && !BCount) { 2518 ULONG d; 2519 // lba_t lastLba; 2520 ULONG firstPos; 2521 ULONG lastPos; 2522 2523 BCount = WTh_BCount; 2524 Lba = WTh_Lba; 2525 while(BCount) { 2526 frame = Lba >> Cache->BlocksPerFrameSh; 2527 // firstLba = frame << Cache->BlocksPerFrameSh; 2528 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba); 2529 d = min(Lba+BCount, (frame+1) << Cache->BlocksPerFrameSh) - Lba; 2530 lastPos = WCacheGetSortedListIndex(Cache->BlockCount, Cache->CachedBlocksList, Lba+d); 2531 block_array = Cache->FrameList[frame].Frame; 2532 if(!block_array) { 2533 ASSERT(FALSE); 2534 BCount -= d; 2535 Lba += d; 2536 continue; 2537 } 2538 status = WCacheFlushBlocksRAM(Cache, Context, block_array, Cache->CachedBlocksList, firstPos, lastPos, FALSE); 2539 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, d); 2540 BCount -= d; 2541 Lba += d; 2542 } 2543 } 2544 2545 EO_WCache_W2: 2546 2547 if(!CachedOnly) { 2548 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2549 } 2550 return status; 2551 } // end WCacheWriteBlocks__() 2552 2553 /* 2554 WCacheFlushAll__() copies all data stored in cache to media. 2555 Flushed blocks are kept in cache. 2556 Public routine 2557 */ 2558 VOID 2559 WCacheFlushAll__( 2560 IN PW_CACHE Cache, // pointer to the Cache Control structure 2561 IN PVOID Context) // user-supplied context for IO callbacks 2562 { 2563 if(!(Cache->ReadProc)) return; 2564 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2565 2566 switch(Cache->Mode) { 2567 case WCACHE_MODE_RAM: 2568 WCacheFlushAllRAM(Cache, Context); 2569 break; 2570 case WCACHE_MODE_ROM: 2571 case WCACHE_MODE_RW: 2572 WCacheFlushAllRW(Cache, Context); 2573 break; 2574 case WCACHE_MODE_R: 2575 WCachePurgeAllR(Cache, Context); 2576 break; 2577 } 2578 2579 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2580 return; 2581 } // end WCacheFlushAll__() 2582 2583 /* 2584 WCachePurgeAll__() copies all data stored in cache to media. 2585 Flushed blocks are removed cache. 2586 Public routine 2587 */ 2588 VOID 2589 WCachePurgeAll__( 2590 IN PW_CACHE Cache, // pointer to the Cache Control structure 2591 IN PVOID Context) // user-supplied context for IO callbacks 2592 { 2593 if(!(Cache->ReadProc)) return; 2594 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2595 2596 switch(Cache->Mode) { 2597 case WCACHE_MODE_RAM: 2598 WCachePurgeAllRAM(Cache, Context); 2599 break; 2600 case WCACHE_MODE_ROM: 2601 case WCACHE_MODE_RW: 2602 WCachePurgeAllRW(Cache, Context); 2603 break; 2604 case WCACHE_MODE_R: 2605 WCachePurgeAllR(Cache, Context); 2606 break; 2607 } 2608 2609 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2610 return; 2611 } // end WCachePurgeAll__() 2612 /* 2613 WCachePurgeAllRW() copies modified blocks from cache to media 2614 and removes them from cache 2615 This routine can be used for RAM, RW and ROM media. 2616 For ROM media blocks are just removed. 2617 Internal routine 2618 */ 2619 VOID 2620 __fastcall 2621 WCachePurgeAllRW( 2622 IN PW_CACHE Cache, // pointer to the Cache Control structure 2623 IN PVOID Context) // user-supplied context for IO callbacks 2624 { 2625 ULONG frame; 2626 lba_t firstLba; 2627 lba_t* List = Cache->CachedBlocksList; 2628 lba_t Lba; 2629 // ULONG firstPos; 2630 // ULONG lastPos; 2631 ULONG BSh = Cache->BlockSizeSh; 2632 ULONG BS = Cache->BlockSize; 2633 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2634 ULONG PSs = Cache->PacketSize; 2635 PW_CACHE_ENTRY block_array; 2636 // OSSTATUS status; 2637 SIZE_T ReadBytes; 2638 PW_CACHE_ASYNC FirstWContext = NULL; 2639 PW_CACHE_ASYNC PrevWContext = NULL; 2640 ULONG chain_count = 0; 2641 2642 if(!(Cache->ReadProc)) return; 2643 2644 while(Cache->BlockCount) { 2645 Lba = List[0] & ~(PSs-1); 2646 frame = Lba >> Cache->BlocksPerFrameSh; 2647 firstLba = frame << Cache->BlocksPerFrameSh; 2648 // firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 2649 // lastPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba+PSs); 2650 block_array = Cache->FrameList[frame].Frame; 2651 if(!block_array) { 2652 BrutePoint(); 2653 return; 2654 } 2655 2656 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2657 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2658 2659 // free memory 2660 WCacheFreePacket(Cache, frame, block_array, Lba-firstLba, PSs); 2661 2662 WCacheRemoveRangeFromList(List, &(Cache->BlockCount), Lba, PSs); 2663 WCacheRemoveRangeFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba, PSs); 2664 // check if frame is empty 2665 if(!(Cache->FrameList[frame].BlockCount)) { 2666 WCacheRemoveFrame(Cache, Context, frame); 2667 } else { 2668 ASSERT(Cache->FrameList[frame].Frame); 2669 } 2670 chain_count++; 2671 if(chain_count >= WCACHE_MAX_CHAIN) { 2672 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2673 chain_count = 0; 2674 } 2675 } 2676 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext); 2677 return; 2678 } // end WCachePurgeAllRW() 2679 2680 /* 2681 WCacheFlushAllRW() copies modified blocks from cache to media. 2682 All blocks are not removed from cache. 2683 This routine can be used for RAM, RW and ROM media. 2684 Internal routine 2685 */ 2686 VOID 2687 __fastcall 2688 WCacheFlushAllRW( 2689 IN PW_CACHE Cache, // pointer to the Cache Control structure 2690 IN PVOID Context) // user-supplied context for IO callbacks 2691 { 2692 ULONG frame; 2693 lba_t firstLba; 2694 lba_t* List = Cache->CachedModifiedBlocksList; 2695 lba_t Lba; 2696 // ULONG firstPos; 2697 // ULONG lastPos; 2698 ULONG BSh = Cache->BlockSizeSh; 2699 ULONG BS = Cache->BlockSize; 2700 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2701 ULONG PSs = Cache->PacketSize; 2702 ULONG BFs = Cache->BlocksPerFrameSh; 2703 PW_CACHE_ENTRY block_array; 2704 // OSSTATUS status; 2705 SIZE_T ReadBytes; 2706 PW_CACHE_ASYNC FirstWContext = NULL; 2707 PW_CACHE_ASYNC PrevWContext = NULL; 2708 ULONG i; 2709 ULONG chain_count = 0; 2710 2711 if(!(Cache->ReadProc)) return; 2712 2713 // walk through modified blocks 2714 while(Cache->WriteCount) { 2715 Lba = List[0] & ~(PSs-1); 2716 frame = Lba >> BFs; 2717 firstLba = frame << BFs; 2718 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); 2719 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); 2720 block_array = Cache->FrameList[frame].Frame; 2721 if(!block_array) { 2722 BrutePoint(); 2723 continue;; 2724 } 2725 // queue modify request 2726 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2727 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2728 // clear MODIFIED flag for queued blocks 2729 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); 2730 Lba -= firstLba; 2731 for(i=0; i<PSs; i++) { 2732 WCacheClrModFlag(block_array, Lba+i); 2733 } 2734 chain_count++; 2735 // check queue size 2736 if(chain_count >= WCACHE_MAX_CHAIN) { 2737 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2738 chain_count = 0; 2739 } 2740 } 2741 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2742 #ifdef DBG 2743 #if 1 2744 // check consistency 2745 List = Cache->CachedBlocksList; 2746 for(i=0; i<Cache->BlockCount; i++) { 2747 Lba = List[i] /*& ~(PSs-1)*/; 2748 frame = Lba >> Cache->BlocksPerFrameSh; 2749 firstLba = frame << Cache->BlocksPerFrameSh; 2750 block_array = Cache->FrameList[frame].Frame; 2751 if(!block_array) { 2752 BrutePoint(); 2753 } 2754 ASSERT(!WCacheGetModFlag(block_array, Lba-firstLba)); 2755 } 2756 #endif // 1 2757 #endif // DBG 2758 return; 2759 } // end WCacheFlushAllRW() 2760 2761 /* 2762 WCacheRelease__() frees all allocated memory blocks and 2763 deletes synchronization resources 2764 Public routine 2765 */ 2766 VOID 2767 WCacheRelease__( 2768 IN PW_CACHE Cache // pointer to the Cache Control structure 2769 ) 2770 { 2771 ULONG i, j, k; 2772 PW_CACHE_ENTRY block_array; 2773 2774 Cache->Tag = 0xDEADCACE; 2775 if(!(Cache->ReadProc)) return; 2776 // ASSERT(Cache->Tag == 0xCAC11E00); 2777 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2778 for(i=0; i<Cache->FrameCount; i++) { 2779 j = Cache->CachedFramesList[i]; 2780 block_array = Cache->FrameList[j].Frame; 2781 if(block_array) { 2782 for(k=0; k<Cache->BlocksPerFrame; k++) { 2783 if(WCacheSectorAddr(block_array, k)) { 2784 WCacheFreeSector(j, k); 2785 } 2786 } 2787 MyFreePool__(block_array); 2788 } 2789 } 2790 if(Cache->FrameList) 2791 MyFreePool__(Cache->FrameList); 2792 if(Cache->CachedBlocksList) 2793 MyFreePool__(Cache->CachedBlocksList); 2794 if(Cache->CachedModifiedBlocksList) 2795 MyFreePool__(Cache->CachedModifiedBlocksList); 2796 if(Cache->CachedFramesList) 2797 MyFreePool__(Cache->CachedFramesList); 2798 if(Cache->tmp_buff_r) 2799 MyFreePool__(Cache->tmp_buff_r); 2800 if(Cache->CachedFramesList) 2801 MyFreePool__(Cache->tmp_buff); 2802 if(Cache->CachedFramesList) 2803 MyFreePool__(Cache->reloc_tab); 2804 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2805 ExDeleteResourceLite(&(Cache->WCacheLock)); 2806 RtlZeroMemory(Cache, sizeof(W_CACHE)); 2807 return; 2808 } // end WCacheRelease__() 2809 2810 /* 2811 WCacheIsInitialized__() checks if the pointer supplied points 2812 to initialized cache structure. 2813 Public routine 2814 */ 2815 BOOLEAN 2816 WCacheIsInitialized__( 2817 IN PW_CACHE Cache 2818 ) 2819 { 2820 return (Cache->ReadProc != NULL); 2821 } // end WCacheIsInitialized__() 2822 2823 OSSTATUS 2824 WCacheFlushBlocksRW( 2825 IN PW_CACHE Cache, // pointer to the Cache Control structure 2826 IN PVOID Context, // user-supplied context for IO callbacks 2827 IN lba_t _Lba, // LBA to start flush from 2828 IN ULONG BCount // number of blocks to be flushed 2829 ) 2830 { 2831 ULONG frame; 2832 lba_t firstLba; 2833 lba_t* List = Cache->CachedModifiedBlocksList; 2834 lba_t Lba; 2835 // ULONG firstPos; 2836 // ULONG lastPos; 2837 ULONG BSh = Cache->BlockSizeSh; 2838 ULONG BS = Cache->BlockSize; 2839 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 2840 ULONG PSs = Cache->PacketSize; 2841 ULONG BFs = Cache->BlocksPerFrameSh; 2842 PW_CACHE_ENTRY block_array; 2843 // OSSTATUS status; 2844 SIZE_T ReadBytes; 2845 PW_CACHE_ASYNC FirstWContext = NULL; 2846 PW_CACHE_ASYNC PrevWContext = NULL; 2847 ULONG i; 2848 ULONG chain_count = 0; 2849 lba_t lim; 2850 2851 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; 2852 2853 // walk through modified blocks 2854 lim = (_Lba+BCount+PSs-1) & ~(PSs-1); 2855 for(Lba = _Lba & ~(PSs-1);Lba < lim ; Lba += PSs) { 2856 frame = Lba >> BFs; 2857 firstLba = frame << BFs; 2858 // firstPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba); 2859 // lastPos = WCacheGetSortedListIndex(Cache->WriteCount, List, Lba+PSs); 2860 block_array = Cache->FrameList[frame].Frame; 2861 if(!block_array) { 2862 // not cached block may be requested for flush 2863 Lba += (1 << BFs) - PSs; 2864 continue; 2865 } 2866 // queue modify request 2867 WCacheUpdatePacket(Cache, Context, &FirstWContext, &PrevWContext, block_array, firstLba, 2868 Lba, BSh, BS, PS, PSs, &ReadBytes, TRUE, ASYNC_STATE_NONE); 2869 // clear MODIFIED flag for queued blocks 2870 WCacheRemoveRangeFromList(List, &(Cache->WriteCount), Lba, PSs); 2871 Lba -= firstLba; 2872 for(i=0; i<PSs; i++) { 2873 WCacheClrModFlag(block_array, Lba+i); 2874 } 2875 Lba += firstLba; 2876 chain_count++; 2877 // check queue size 2878 if(chain_count >= WCACHE_MAX_CHAIN) { 2879 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2880 chain_count = 0; 2881 } 2882 } 2883 WCacheUpdatePacketComplete(Cache, Context, &FirstWContext, &PrevWContext, FALSE); 2884 /* 2885 if(Cache->Mode != WCACHE_MODE_RAM) 2886 return STATUS_SUCCESS; 2887 */ 2888 2889 return STATUS_SUCCESS; 2890 } // end WCacheFlushBlocksRW() 2891 2892 /* 2893 WCacheFlushBlocks__() copies specified blocks stored in cache to media. 2894 Flushed blocks are kept in cache. 2895 Public routine 2896 */ 2897 OSSTATUS 2898 WCacheFlushBlocks__( 2899 IN PW_CACHE Cache, // pointer to the Cache Control structure 2900 IN PVOID Context, // user-supplied context for IO callbacks 2901 IN lba_t Lba, // LBA to start flush from 2902 IN ULONG BCount // number of blocks to be flushed 2903 ) 2904 { 2905 OSSTATUS status; 2906 2907 if(!(Cache->ReadProc)) return STATUS_INVALID_PARAMETER; 2908 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2909 2910 // check if we try to access beyond cached area 2911 if((Lba < Cache->FirstLba) || 2912 (Lba+BCount-1 > Cache->LastLba)) { 2913 UDFPrint(("LBA %#x (%x) is beyond cacheable area\n", Lba, BCount)); 2914 BrutePoint(); 2915 status = STATUS_INVALID_PARAMETER; 2916 goto EO_WCache_F; 2917 } 2918 2919 switch(Cache->Mode) { 2920 case WCACHE_MODE_RAM: 2921 // WCacheFlushBlocksRW(Cache, Context); 2922 // break; 2923 case WCACHE_MODE_ROM: 2924 case WCACHE_MODE_RW: 2925 status = WCacheFlushBlocksRW(Cache, Context, Lba, BCount); 2926 break; 2927 case WCACHE_MODE_R: 2928 status = STATUS_SUCCESS; 2929 break; 2930 } 2931 EO_WCache_F: 2932 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 2933 return status; 2934 } // end WCacheFlushBlocks__() 2935 2936 /* 2937 WCacheDirect__() returns pointer to memory block where 2938 requested block is stored in. 2939 If no #CachedOnly flag specified this routine locks cache, 2940 otherwise it assumes that cache is already locked by previous call 2941 to WCacheStartDirect__(). 2942 Cache can be unlocked by WCacheEODirect__(). 2943 Using this routine caller can access cached block directly in memory 2944 without Read_to_Tmp and Modify/Write steps. 2945 Public routine 2946 */ 2947 OSSTATUS 2948 WCacheDirect__( 2949 IN PW_CACHE Cache, // pointer to the Cache Control structure 2950 IN PVOID Context, // user-supplied context for IO callbacks 2951 IN lba_t Lba, // LBA of block to get pointer to 2952 IN BOOLEAN Modified, // indicates that block will be modified 2953 OUT PCHAR* CachedBlock, // address for pointer to cached block to be stored in 2954 IN BOOLEAN CachedOnly // specifies that cache is already locked 2955 ) 2956 { 2957 ULONG frame; 2958 ULONG i; 2959 OSSTATUS status = STATUS_SUCCESS; 2960 PW_CACHE_ENTRY block_array; 2961 ULONG BS = Cache->BlockSize; 2962 PCHAR addr; 2963 SIZE_T _ReadBytes; 2964 ULONG block_type; 2965 2966 WcPrint(("WC:%sD %x (1)\n", Modified ? "W" : "R", Lba)); 2967 2968 // lock cache if nececcary 2969 if(!CachedOnly) { 2970 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 2971 } 2972 // check if we try to access beyond cached area 2973 if((Lba < Cache->FirstLba) || 2974 (Lba > Cache->LastLba)) { 2975 UDFPrint(("LBA %#x is beyond cacheable area\n", Lba)); 2976 BrutePoint(); 2977 status = STATUS_INVALID_PARAMETER; 2978 goto EO_WCache_D; 2979 } 2980 2981 frame = Lba >> Cache->BlocksPerFrameSh; 2982 i = Lba - (frame << Cache->BlocksPerFrameSh); 2983 // check if we have enough space to store requested block 2984 if(!CachedOnly && 2985 !OS_SUCCESS(status = WCacheCheckLimits(Cache, Context, Lba, 1))) { 2986 BrutePoint(); 2987 goto EO_WCache_D; 2988 } 2989 2990 // small updates are more important 2991 block_array = Cache->FrameList[frame].Frame; 2992 if(Modified) { 2993 Cache->FrameList[frame].UpdateCount+=8; 2994 } else { 2995 Cache->FrameList[frame].AccessCount+=8; 2996 } 2997 if(!block_array) { 2998 ASSERT(Cache->FrameCount < Cache->MaxFrames); 2999 block_array = WCacheInitFrame(Cache, Context, frame); 3000 if(!block_array) { 3001 status = STATUS_INSUFFICIENT_RESOURCES; 3002 goto EO_WCache_D; 3003 } 3004 } 3005 // check if requested block is already cached 3006 if( !(addr = (PCHAR)WCacheSectorAddr(block_array, i)) ) { 3007 // block is not cached 3008 // allocate memory and read block from media 3009 // do not set block_array[i].Sector here, because if media access fails and recursive access to cache 3010 // comes, this block should not be marked as 'cached' 3011 addr = (PCHAR)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE, BS, MEM_WCBUF_TAG); 3012 if(!addr) { 3013 status = STATUS_INSUFFICIENT_RESOURCES; 3014 goto EO_WCache_D; 3015 } 3016 block_type = Cache->CheckUsedProc(Context, Lba); 3017 if(block_type == WCACHE_BLOCK_USED) { 3018 status = Cache->ReadProc(Context, addr, BS, Lba, &_ReadBytes, PH_TMP_BUFFER); 3019 if(Cache->RememberBB) { 3020 if(!OS_SUCCESS(status)) { 3021 RtlZeroMemory(addr, BS); 3022 //WCacheSetBadFlag(block_array,i); 3023 } 3024 } 3025 } else { 3026 if(block_type & WCACHE_BLOCK_BAD) { 3027 DbgFreePool(addr); 3028 addr = NULL; 3029 status = STATUS_DEVICE_DATA_ERROR; 3030 goto EO_WCache_D; 3031 } 3032 if(!(block_type & WCACHE_BLOCK_ZERO)) { 3033 BrutePoint(); 3034 } 3035 status = STATUS_SUCCESS; 3036 RtlZeroMemory(addr, BS); 3037 } 3038 // now add pointer to buffer to common storage 3039 block_array[i].Sector = addr; 3040 WCacheInsertItemToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba); 3041 if(Modified) { 3042 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3043 WCacheSetModFlag(block_array, i); 3044 } 3045 Cache->FrameList[frame].BlockCount ++; 3046 } else { 3047 // block is not cached 3048 // just return pointer 3049 block_type = Cache->CheckUsedProc(Context, Lba); 3050 if(block_type & WCACHE_BLOCK_BAD) { 3051 //if(WCacheGetBadFlag(block_array,i)) { 3052 // bad packet. no pre-read 3053 status = STATUS_DEVICE_DATA_ERROR; 3054 goto EO_WCache_D; 3055 } 3056 #ifndef UDF_CHECK_UTIL 3057 ASSERT(block_type & WCACHE_BLOCK_USED); 3058 #else 3059 if(!(block_type & WCACHE_BLOCK_USED)) { 3060 UDFPrint(("LBA %#x is not marked as used\n", Lba)); 3061 } 3062 #endif 3063 if(Modified && 3064 !WCacheGetModFlag(block_array, i)) { 3065 WCacheInsertItemToList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3066 WCacheSetModFlag(block_array, i); 3067 } 3068 } 3069 (*CachedBlock) = addr; 3070 3071 EO_WCache_D: 3072 3073 return status; 3074 } // end WCacheDirect__() 3075 3076 /* 3077 WCacheEODirect__() must be used to unlock cache after calls to 3078 to WCacheStartDirect__(). 3079 Public routine 3080 */ 3081 OSSTATUS 3082 WCacheEODirect__( 3083 IN PW_CACHE Cache, // pointer to the Cache Control structure 3084 IN PVOID Context // user-supplied context for IO callbacks 3085 ) 3086 { 3087 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3088 return STATUS_SUCCESS; 3089 } // end WCacheEODirect__() 3090 3091 /* 3092 WCacheStartDirect__() locks cache for exclusive use. 3093 Using this routine caller can access cached block directly in memory 3094 without Read_to_Tmp and Modify/Write steps. 3095 See also WCacheDirect__() 3096 Cache can be unlocked by WCacheEODirect__(). 3097 Public routine 3098 */ 3099 OSSTATUS 3100 WCacheStartDirect__( 3101 IN PW_CACHE Cache, // pointer to the Cache Control structure 3102 IN PVOID Context, // user-supplied context for IO callbacks 3103 IN BOOLEAN Exclusive // lock cache for exclusive use, 3104 // currently must be TRUE. 3105 ) 3106 { 3107 if(Exclusive) { 3108 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 3109 } else { 3110 BrutePoint(); 3111 ExAcquireResourceSharedLite(&(Cache->WCacheLock), TRUE); 3112 } 3113 return STATUS_SUCCESS; 3114 } // end WCacheStartDirect__() 3115 3116 /* 3117 WCacheIsCached__() checks if requested blocks are immediately available. 3118 Cache must be previously locked for exclusive use with WCacheStartDirect__(). 3119 Using this routine caller can access cached block directly in memory 3120 without Read_to_Tmp and Modify/Write steps. 3121 See also WCacheDirect__(). 3122 Cache can be unlocked by WCacheEODirect__(). 3123 Public routine 3124 */ 3125 BOOLEAN 3126 WCacheIsCached__( 3127 IN PW_CACHE Cache, // pointer to the Cache Control structure 3128 IN lba_t Lba, // LBA to start check from 3129 IN ULONG BCount // number of blocks to be checked 3130 ) 3131 { 3132 ULONG frame; 3133 ULONG i; 3134 PW_CACHE_ENTRY block_array; 3135 3136 // check if we try to access beyond cached area 3137 if((Lba < Cache->FirstLba) || 3138 (Lba + BCount - 1 > Cache->LastLba)) { 3139 return FALSE; 3140 } 3141 3142 frame = Lba >> Cache->BlocksPerFrameSh; 3143 i = Lba - (frame << Cache->BlocksPerFrameSh); 3144 3145 block_array = Cache->FrameList[frame].Frame; 3146 if(!block_array) { 3147 return FALSE; 3148 } 3149 3150 while(BCount) { 3151 if(i >= Cache->BlocksPerFrame) { 3152 frame++; 3153 block_array = Cache->FrameList[frame].Frame; 3154 i -= Cache->BlocksPerFrame; 3155 } 3156 if(!block_array) { 3157 return FALSE; 3158 } 3159 // 'read' cached extent (if any) 3160 while(BCount && 3161 (i < Cache->BlocksPerFrame) && 3162 WCacheSectorAddr(block_array, i) && 3163 /*!WCacheGetBadFlag(block_array, i)*/ 3164 /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/ 3165 TRUE ) { 3166 i++; 3167 BCount--; 3168 Lba++; 3169 } 3170 if(BCount && 3171 (i < Cache->BlocksPerFrame) /*&& 3172 (!WCacheSectorAddr(block_array, i))*/ ) { 3173 return FALSE; 3174 } 3175 } 3176 return TRUE; 3177 } // end WCacheIsCached__() 3178 3179 /* 3180 WCacheCheckLimitsR() implements automatic flush and purge of 3181 unused blocks to keep enough free cache entries for newly 3182 read/written blocks for WORM media. 3183 See also WCacheCheckLimits() 3184 Internal routine 3185 */ 3186 OSSTATUS 3187 __fastcall 3188 WCacheCheckLimitsR( 3189 IN PW_CACHE Cache, // pointer to the Cache Control structure 3190 IN PVOID Context, // user-supplied context for IO callbacks 3191 IN lba_t ReqLba, // first LBA to access/cache 3192 IN ULONG BCount // number of Blocks to access/cache 3193 ) 3194 { 3195 ULONG frame; 3196 lba_t firstLba; 3197 lba_t* List = Cache->CachedBlocksList; 3198 lba_t Lba; 3199 PCHAR tmp_buff = Cache->tmp_buff; 3200 ULONG firstPos; 3201 ULONG BSh = Cache->BlockSizeSh; 3202 ULONG BS = Cache->BlockSize; 3203 ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3204 ULONG PSs = Cache->PacketSize; 3205 ULONG i; 3206 PW_CACHE_ENTRY block_array; 3207 BOOLEAN mod; 3208 OSSTATUS status; 3209 SIZE_T ReadBytes; 3210 ULONG MaxReloc = Cache->PacketSize; 3211 PULONG reloc_tab = Cache->reloc_tab; 3212 3213 // check if we try to read too much data 3214 if(BCount > Cache->MaxBlocks) { 3215 return STATUS_INVALID_PARAMETER; 3216 } 3217 3218 // remove(flush) packets from entire frame(s) 3219 while( ((Cache->BlockCount + WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba) + 3220 BCount - WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba+BCount)) > Cache->MaxBlocks) || 3221 (Cache->FrameCount >= Cache->MaxFrames) ) { 3222 3223 WCCL_retry_1: 3224 3225 Lba = WCacheFindLbaToRelease(Cache); 3226 if(Lba == WCACHE_INVALID_LBA) { 3227 ASSERT(!Cache->FrameCount); 3228 ASSERT(!Cache->BlockCount); 3229 break; 3230 } 3231 frame = Lba >> Cache->BlocksPerFrameSh; 3232 firstLba = frame << Cache->BlocksPerFrameSh; 3233 firstPos = WCacheGetSortedListIndex(Cache->BlockCount, List, Lba); 3234 block_array = Cache->FrameList[frame].Frame; 3235 if(!block_array) { 3236 return STATUS_DRIVER_INTERNAL_ERROR; 3237 } 3238 // check if modified 3239 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3240 // read/modify/write 3241 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3242 if(Cache->WriteCount < MaxReloc) goto WCCL_retry_1; 3243 firstPos = WCacheGetSortedListIndex(Cache->WriteCount, Cache->CachedModifiedBlocksList, Lba); 3244 if(!block_array) { 3245 return STATUS_DRIVER_INTERNAL_ERROR; 3246 } 3247 // prepare packet & reloc table 3248 for(i=0; i<MaxReloc; i++) { 3249 Lba = Cache->CachedModifiedBlocksList[firstPos]; 3250 frame = Lba >> Cache->BlocksPerFrameSh; 3251 firstLba = frame << Cache->BlocksPerFrameSh; 3252 block_array = Cache->FrameList[frame].Frame; 3253 DbgCopyMemory(tmp_buff + (i << BSh), 3254 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), 3255 BS); 3256 reloc_tab[i] = Lba; 3257 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3258 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3259 // mark as non-cached & free pool 3260 WCacheFreeSector(frame, Lba-firstLba); 3261 // check if frame is empty 3262 if(!Cache->FrameList[frame].BlockCount) { 3263 WCacheRemoveFrame(Cache, Context, frame); 3264 } 3265 if(firstPos >= Cache->WriteCount) firstPos=0; 3266 } 3267 // write packet 3268 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); 3269 Cache->UpdateRelocProc(Context, NULL, reloc_tab, MaxReloc); 3270 status = Cache->WriteProc(Context, tmp_buff, PS, NULL, &ReadBytes, 0); 3271 if(!OS_SUCCESS(status)) { 3272 status = WCacheRaiseIoError(Cache, Context, status, NULL, PSs, tmp_buff, WCACHE_W_OP, NULL); 3273 } 3274 } else { 3275 3276 if((i = Cache->BlockCount - Cache->WriteCount) > MaxReloc) i = MaxReloc; 3277 // discard blocks 3278 for(; i; i--) { 3279 Lba = List[firstPos]; 3280 frame = Lba >> Cache->BlocksPerFrameSh; 3281 firstLba = frame << Cache->BlocksPerFrameSh; 3282 block_array = Cache->FrameList[frame].Frame; 3283 3284 if( (mod = WCacheGetModFlag(block_array, Lba - firstLba)) && 3285 (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED) ) 3286 continue; 3287 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3288 if(mod) 3289 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3290 // mark as non-cached & free pool 3291 WCacheFreeSector(frame, Lba-firstLba); 3292 // check if frame is empty 3293 if(!Cache->FrameList[frame].BlockCount) { 3294 WCacheRemoveFrame(Cache, Context, frame); 3295 } 3296 if(firstPos >= Cache->WriteCount) firstPos=0; 3297 } 3298 } 3299 } 3300 return STATUS_SUCCESS; 3301 } // end WCacheCheckLimitsR() 3302 3303 /* 3304 WCachePurgeAllR() copies modified blocks from cache to media 3305 and removes them from cache 3306 This routine can be used for R media only. 3307 Internal routine 3308 */ 3309 VOID 3310 __fastcall 3311 WCachePurgeAllR( 3312 IN PW_CACHE Cache, // pointer to the Cache Control structure 3313 IN PVOID Context) // user-supplied context for IO callbacks 3314 { 3315 ULONG frame; 3316 lba_t firstLba; 3317 lba_t* List = Cache->CachedBlocksList; 3318 lba_t Lba; 3319 PCHAR tmp_buff = Cache->tmp_buff; 3320 ULONG BSh = Cache->BlockSizeSh; 3321 ULONG BS = Cache->BlockSize; 3322 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3323 // ULONG PSs = Cache->PacketSize; 3324 PW_CACHE_ENTRY block_array; 3325 BOOLEAN mod; 3326 OSSTATUS status; 3327 SIZE_T ReadBytes; 3328 ULONG MaxReloc = Cache->PacketSize; 3329 PULONG reloc_tab = Cache->reloc_tab; 3330 ULONG RelocCount = 0; 3331 BOOLEAN IncompletePacket; 3332 ULONG i=0; 3333 ULONG PacketTail; 3334 3335 while(Cache->WriteCount < Cache->BlockCount) { 3336 3337 Lba = List[i]; 3338 frame = Lba >> Cache->BlocksPerFrameSh; 3339 firstLba = frame << Cache->BlocksPerFrameSh; 3340 block_array = Cache->FrameList[frame].Frame; 3341 if(!block_array) { 3342 BrutePoint(); 3343 return; 3344 } 3345 // check if modified 3346 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3347 // just discard 3348 if(!mod || !(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3349 // mark as non-cached & free pool 3350 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3351 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3352 if(mod) 3353 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3354 // mark as non-cached & free pool 3355 WCacheFreeSector(frame, Lba-firstLba); 3356 // check if frame is empty 3357 if(!Cache->FrameList[frame].BlockCount) { 3358 WCacheRemoveFrame(Cache, Context, frame); 3359 } 3360 } else { 3361 BrutePoint(); 3362 } 3363 } else { 3364 i++; 3365 } 3366 } 3367 3368 PacketTail = Cache->WriteCount & (MaxReloc-1); 3369 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; 3370 3371 // remove(flush) packet 3372 while((Cache->WriteCount > PacketTail) || (Cache->WriteCount && IncompletePacket)) { 3373 3374 Lba = List[0]; 3375 frame = Lba >> Cache->BlocksPerFrameSh; 3376 firstLba = frame << Cache->BlocksPerFrameSh; 3377 block_array = Cache->FrameList[frame].Frame; 3378 if(!block_array) { 3379 BrutePoint(); 3380 return; 3381 } 3382 // check if modified 3383 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3384 // pack/reloc/write 3385 if(mod) { 3386 DbgCopyMemory(tmp_buff + (RelocCount << BSh), 3387 (PVOID)WCacheSectorAddr(block_array, Lba-firstLba), 3388 BS); 3389 reloc_tab[RelocCount] = Lba; 3390 RelocCount++; 3391 // write packet 3392 if((RelocCount >= MaxReloc) || (Cache->BlockCount == 1)) { 3393 // status = Cache->WriteProcAsync(Context, tmp_buff, PS, Lba, &ReadBytes, FALSE); 3394 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); 3395 status = Cache->WriteProc(Context, tmp_buff, RelocCount<<BSh, NULL, &ReadBytes, 0); 3396 if(!OS_SUCCESS(status)) { 3397 status = WCacheRaiseIoError(Cache, Context, status, NULL, RelocCount, tmp_buff, WCACHE_W_OP, NULL); 3398 } 3399 RelocCount = 0; 3400 } 3401 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3402 } else { 3403 BrutePoint(); 3404 } 3405 // mark as non-cached & free pool 3406 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3407 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3408 // mark as non-cached & free pool 3409 WCacheFreeSector(frame, Lba-firstLba); 3410 // check if frame is empty 3411 if(!Cache->FrameList[frame].BlockCount) { 3412 WCacheRemoveFrame(Cache, Context, frame); 3413 } 3414 } else { 3415 BrutePoint(); 3416 } 3417 } 3418 } // end WCachePurgeAllR() 3419 3420 /* 3421 WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM). 3422 Public routine 3423 */ 3424 OSSTATUS 3425 WCacheSetMode__( 3426 IN PW_CACHE Cache, // pointer to the Cache Control structure 3427 IN ULONG Mode // cache mode/media type to be used 3428 ) 3429 { 3430 if(Mode > WCACHE_MODE_MAX) return STATUS_INVALID_PARAMETER; 3431 Cache->Mode = Mode; 3432 return STATUS_SUCCESS; 3433 } // end WCacheSetMode__() 3434 3435 /* 3436 WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM). 3437 Public routine 3438 */ 3439 ULONG 3440 WCacheGetMode__( 3441 IN PW_CACHE Cache 3442 ) 3443 { 3444 return Cache->Mode; 3445 } // end WCacheGetMode__() 3446 3447 /* 3448 WCacheGetWriteBlockCount__() returns number of modified blocks, those are 3449 not flushed to media. Is usually used to preallocate blocks for 3450 relocation table on WORM (R) media. 3451 Public routine 3452 */ 3453 ULONG 3454 WCacheGetWriteBlockCount__( 3455 IN PW_CACHE Cache 3456 ) 3457 { 3458 return Cache->WriteCount; 3459 } // end WCacheGetWriteBlockCount__() 3460 3461 /* 3462 WCacheSyncReloc__() builds list of all modified blocks, currently 3463 stored in cache. For each modified block WCacheSyncReloc__() calls 3464 user-supplied callback routine in order to update relocation table 3465 on WORM (R) media. 3466 Public routine 3467 */ 3468 VOID 3469 WCacheSyncReloc__( 3470 IN PW_CACHE Cache, 3471 IN PVOID Context) 3472 { 3473 ULONG frame; 3474 lba_t firstLba; 3475 lba_t* List = Cache->CachedBlocksList; 3476 lba_t Lba; 3477 // ULONG BSh = Cache->BlockSizeSh; 3478 // ULONG BS = Cache->BlockSize; 3479 // ULONG PS = BS << Cache->PacketSizeSh; // packet size (bytes) 3480 // ULONG PSs = Cache->PacketSize; 3481 PW_CACHE_ENTRY block_array; 3482 BOOLEAN mod; 3483 ULONG MaxReloc = Cache->PacketSize; 3484 PULONG reloc_tab = Cache->reloc_tab; 3485 ULONG RelocCount = 0; 3486 BOOLEAN IncompletePacket; 3487 3488 IncompletePacket = (Cache->WriteCount >= MaxReloc) ? FALSE : TRUE; 3489 // enumerate modified blocks 3490 for(ULONG i=0; IncompletePacket && (i<Cache->BlockCount); i++) { 3491 3492 Lba = List[i]; 3493 frame = Lba >> Cache->BlocksPerFrameSh; 3494 firstLba = frame << Cache->BlocksPerFrameSh; 3495 block_array = Cache->FrameList[frame].Frame; 3496 if(!block_array) { 3497 return; 3498 } 3499 // check if modified 3500 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3501 // update relocation table for modified sectors 3502 if(mod && (Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_USED)) { 3503 reloc_tab[RelocCount] = Lba; 3504 RelocCount++; 3505 if(RelocCount >= Cache->WriteCount) { 3506 Cache->UpdateRelocProc(Context, NULL, reloc_tab, RelocCount); 3507 break; 3508 } 3509 } 3510 } 3511 } // end WCacheSyncReloc__() 3512 3513 /* 3514 WCacheDiscardBlocks__() removes specified blocks from cache. 3515 Blocks are not flushed to media. 3516 Public routine 3517 */ 3518 VOID 3519 WCacheDiscardBlocks__( 3520 IN PW_CACHE Cache, 3521 IN PVOID Context, 3522 IN lba_t ReqLba, 3523 IN ULONG BCount 3524 ) 3525 { 3526 ULONG frame; 3527 lba_t firstLba; 3528 lba_t* List; 3529 lba_t Lba; 3530 PW_CACHE_ENTRY block_array; 3531 BOOLEAN mod; 3532 ULONG i; 3533 3534 ExAcquireResourceExclusiveLite(&(Cache->WCacheLock), TRUE); 3535 3536 UDFPrint((" Discard req: %x@%x\n",BCount, ReqLba)); 3537 3538 List = Cache->CachedBlocksList; 3539 if(!List) { 3540 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3541 return; 3542 } 3543 i = WCacheGetSortedListIndex(Cache->BlockCount, List, ReqLba); 3544 3545 // enumerate requested blocks 3546 while((List[i] < (ReqLba+BCount)) && (i < Cache->BlockCount)) { 3547 3548 Lba = List[i]; 3549 frame = Lba >> Cache->BlocksPerFrameSh; 3550 firstLba = frame << Cache->BlocksPerFrameSh; 3551 block_array = Cache->FrameList[frame].Frame; 3552 if(!block_array) { 3553 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3554 BrutePoint(); 3555 return; 3556 } 3557 // check if modified 3558 mod = WCacheGetModFlag(block_array, Lba - firstLba); 3559 // just discard 3560 3561 // mark as non-cached & free pool 3562 if(WCacheSectorAddr(block_array,Lba-firstLba)) { 3563 WCacheRemoveItemFromList(List, &(Cache->BlockCount), Lba); 3564 if(mod) 3565 WCacheRemoveItemFromList(Cache->CachedModifiedBlocksList, &(Cache->WriteCount), Lba); 3566 // mark as non-cached & free pool 3567 WCacheFreeSector(frame, Lba-firstLba); 3568 // check if frame is empty 3569 if(!Cache->FrameList[frame].BlockCount) { 3570 WCacheRemoveFrame(Cache, Context, frame); 3571 } else { 3572 ASSERT(Cache->FrameList[frame].Frame); 3573 } 3574 } else { 3575 // we should never get here !!! 3576 // getting this part of code means that we have 3577 // placed non-cached block in CachedBlocksList 3578 BrutePoint(); 3579 } 3580 } 3581 ExReleaseResourceForThreadLite(&(Cache->WCacheLock), ExGetCurrentResourceThread()); 3582 } // end WCacheDiscardBlocks__() 3583 3584 OSSTATUS 3585 WCacheCompleteAsync__( 3586 IN PVOID WContext, 3587 IN OSSTATUS Status 3588 ) 3589 { 3590 PW_CACHE_ASYNC AsyncCtx = (PW_CACHE_ASYNC)WContext; 3591 // PW_CACHE Cache = AsyncCtx->Cache; 3592 3593 AsyncCtx->PhContext.IosbToUse.Status = Status; 3594 KeSetEvent(&(AsyncCtx->PhContext.event), 0, FALSE); 3595 3596 return STATUS_SUCCESS; 3597 } // end WCacheSetMode__() 3598 3599 /* 3600 WCacheDecodeFlags() updates internal BOOLEANs according to Flags 3601 Internal routine 3602 */ 3603 OSSTATUS 3604 __fastcall 3605 WCacheDecodeFlags( 3606 IN PW_CACHE Cache, // pointer to the Cache Control structure 3607 IN ULONG Flags // cache mode flags 3608 ) 3609 { 3610 //ULONG OldFlags; 3611 if(Flags & ~WCACHE_VALID_FLAGS) { 3612 UDFPrint(("Invalid flags: %x\n", Flags & ~WCACHE_VALID_FLAGS)); 3613 return STATUS_INVALID_PARAMETER; 3614 } 3615 Cache->CacheWholePacket = (Flags & WCACHE_CACHE_WHOLE_PACKET) ? TRUE : FALSE; 3616 Cache->DoNotCompare = (Flags & WCACHE_DO_NOT_COMPARE) ? TRUE : FALSE; 3617 Cache->Chained = (Flags & WCACHE_CHAINED_IO) ? TRUE : FALSE; 3618 Cache->RememberBB = (Flags & WCACHE_MARK_BAD_BLOCKS) ? TRUE : FALSE; 3619 if(Cache->RememberBB) { 3620 Cache->NoWriteBB = (Flags & WCACHE_RO_BAD_BLOCKS) ? TRUE : FALSE; 3621 } 3622 Cache->NoWriteThrough = (Flags & WCACHE_NO_WRITE_THROUGH) ? TRUE : FALSE; 3623 3624 Cache->Flags = Flags; 3625 3626 return STATUS_SUCCESS; 3627 } 3628 3629 /* 3630 WCacheChFlags__() changes cache flags. 3631 Public routine 3632 */ 3633 ULONG 3634 WCacheChFlags__( 3635 IN PW_CACHE Cache, // pointer to the Cache Control structure 3636 IN ULONG SetFlags, // cache mode/media type to be set 3637 IN ULONG ClrFlags // cache mode/media type to be cleared 3638 ) 3639 { 3640 ULONG Flags; 3641 3642 if(SetFlags || ClrFlags) { 3643 Flags = (Cache->Flags & ~ClrFlags) | SetFlags; 3644 3645 if(!OS_SUCCESS(WCacheDecodeFlags(Cache, Flags))) { 3646 return -1; 3647 } 3648 } else { 3649 return Cache->Flags; 3650 } 3651 return Flags; 3652 } // end WCacheSetMode__() 3653