1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
7 /*********************************************************************/
9 OSSTATUS __fastcall
WCacheCheckLimits(IN PW_CACHE Cache
,
14 OSSTATUS __fastcall
WCacheCheckLimitsRAM(IN PW_CACHE Cache
,
19 OSSTATUS __fastcall
WCacheCheckLimitsRW(IN PW_CACHE Cache
,
24 OSSTATUS __fastcall
WCacheCheckLimitsR(IN PW_CACHE Cache
,
29 VOID __fastcall
WCachePurgeAllRW(IN PW_CACHE Cache
,
32 VOID __fastcall
WCacheFlushAllRW(IN PW_CACHE Cache
,
35 VOID __fastcall
WCachePurgeAllR(IN PW_CACHE Cache
,
38 OSSTATUS __fastcall
WCacheDecodeFlags(IN PW_CACHE Cache
,
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
48 #define ASYNC_CMD_NONE 0
49 #define ASYNC_CMD_READ 1
50 #define ASYNC_CMD_UPDATE 2
52 #define WCACHE_MAX_CHAIN (0x10)
54 #define MEM_WCCTX_TAG 'xtCW'
55 #define MEM_WCFRM_TAG 'rfCW'
56 #define MEM_WCBUF_TAG 'fbCW'
61 #define WcPrint UDFPrint
63 #define WcPrint(x) {;}
66 typedef struct _W_CACHE_ASYNC
{
67 UDF_PH_CALL_CONTEXT PhContext
;
73 SIZE_T TransferredBytes
;
76 struct _W_CACHE_ASYNC
* NextWContext
;
77 struct _W_CACHE_ASYNC
* PrevWContext
;
78 } W_CACHE_ASYNC
, *PW_CACHE_ASYNC
;
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
89 /*********************************************************************/
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
110 WCacheInit__() returns initialization status. If initialization failed,
111 all allocated memory and resources are automaticelly freed.
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
120 IN ULONG MaxBlocks
, // maximum number of Blocks to be kept in memory
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
131 IN lba_t LastLba
, // Logical Block Address (LBA) of the last block
133 IN ULONG Mode
, // media mode:
138 // the following modes are planned to be implemented:
140 IN ULONG Flags
, // cache mode flags:
141 // WCACHE_CACHE_WHOLE_PACKET
142 // read long (Packet-sized) blocks of
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
173 ULONG PacketSize
= (1) << PacketSizeSh
;
174 ULONG BlockSize
= (1) << BlockSizeSh
;
175 ULONG BlocksPerFrame
= (1) << BlocksPerFrameSh
;
176 OSSTATUS RC
= STATUS_SUCCESS
;
178 ULONG res_init_flags
= 0;
183 // check input parameters
184 if(Mode
== WCACHE_MODE_R
) {
185 UDFPrint(("Disable Async-Write for WORM media\n"));
186 WriteProcAsync
= NULL
;
188 if((MaxBlocks
% PacketSize
) || !MaxBlocks
) {
189 UDFPrint(("Total number of sectors must be packet-size-aligned\n"));
190 try_return(RC
= STATUS_INVALID_PARAMETER
);
192 if(BlocksPerFrame
% PacketSize
) {
193 UDFPrint(("Number of sectors per Frame must be packet-size-aligned\n"));
194 try_return(RC
= STATUS_INVALID_PARAMETER
);
197 UDFPrint(("Read routine pointer must be valid\n"));
198 try_return(RC
= STATUS_INVALID_PARAMETER
);
200 if(FirstLba
>= LastLba
) {
201 UDFPrint(("Invalid cached area parameters: (%x - %x)\n",FirstLba
, LastLba
));
202 try_return(RC
= STATUS_INVALID_PARAMETER
);
205 UDFPrint(("Total frame number must be non-zero\n",FirstLba
, LastLba
));
206 try_return(RC
= STATUS_INVALID_PARAMETER
);
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
);
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
);
218 UDFPrint(("Write routine not specified\n"));
219 UDFPrint(("Read-only mode enabled\n"));
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
);
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
);
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
);
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
);
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
;
266 if(!OS_SUCCESS(RC
= WCacheDecodeFlags(Cache
, Flags
))) {
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
);
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
);
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
);
294 if(!OS_SUCCESS(RC
= ExInitializeResourceLite(&(Cache
->WCacheLock
)))) {
295 UDFPrint(("Cache init err (res)\n"));
298 res_init_flags
|= WCLOCK_RES
;
299 KeQuerySystemTime((PLARGE_INTEGER
)(&rseed
));
300 WCache_random
= rseed
.LowPart
;
306 if(!OS_SUCCESS(RC
)) {
307 if(res_init_flags
& WCLOCK_RES
)
308 ExDeleteResourceLite(&(Cache
->WCacheLock
));
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
);
320 MyFreePool__(Cache
->tmp_buff
);
322 MyFreePool__(Cache
->reloc_tab
);
323 RtlZeroMemory(Cache
, sizeof(W_CACHE
));
325 Cache
->Tag
= 0xCAC11E00;
331 } // end WCacheInit__()
334 WCacheRandom() - just a random generator
335 Returns random LONGLONG number
341 WCache_random
= (WCache_random
* 0x8088405 + 1);
342 return WCache_random
;
343 } // end WCacheRandom()
346 WCacheFindLbaToRelease() finds Block to be flushed and purged from cache
352 WCacheFindLbaToRelease(
356 if(!(Cache
->BlockCount
))
357 return WCACHE_INVALID_LBA
;
358 return(Cache
->CachedBlocksList
[((ULONG
)WCacheRandom() % Cache
->BlockCount
)]);
359 } // end WCacheFindLbaToRelease()
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)
369 WCacheFindModifiedLbaToRelease(
373 if(!(Cache
->WriteCount
))
374 return WCACHE_INVALID_LBA
;
375 return(Cache
->CachedModifiedBlocksList
[((ULONG
)WCacheRandom() % Cache
->WriteCount
)]);
376 } // end WCacheFindModifiedLbaToRelease()
379 WCacheFindFrameToRelease() finds Frame to be flushed and purged with all
380 Blocks (from this Frame) from cache
381 Returns random Frame number
386 WCacheFindFrameToRelease(
397 if(!(Cache
->FrameCount
))
400 return(Cache->CachedFramesList[((ULONG)WCacheRandom() % Cache->FrameCount)]);
403 for(i
=0; i
<Cache
->FrameCount
; i
++) {
405 j
= Cache
->CachedFramesList
[i
];
407 mod
|= (Cache
->FrameList
[j
].UpdateCount
!= 0);
408 uc
= Cache
->FrameList
[j
].UpdateCount
*32 + Cache
->FrameList
[j
].AccessCount
;
416 frame
= Cache
->CachedFramesList
[((ULONG
)WCacheRandom() % Cache
->FrameCount
)];
417 lba
= frame
<< Cache
->BlocksPerFrameSh
;
418 WcPrint(("WC:-frm %x\n", lba
));
420 lba
= frame
<< Cache
->BlocksPerFrameSh
;
421 WcPrint(("WC:-frm(mod) %x\n", lba
));
422 for(i
=0; i
<Cache
->FrameCount
; i
++) {
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;
430 } // end WCacheFindFrameToRelease()
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
443 #pragma warning(push)
444 #pragma warning(disable:4035) // re-enable below
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
458 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
466 // right = BlockCount - 1;
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
476 // while(left != right) {
480 // pos = (left + right) >> 1;
481 __asm lea esi
,[ebx
+edx
]
483 // if(List[pos] == Lba)
485 __asm mov eax
,[edi
+esi
*4]
489 // if(right - left == 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
502 // if(List[pos] < Lba) {
517 // if((List[pos] < Lba) && ((pos+1) <= BlockCount)) pos++;
518 __asm mov eax
,[edi
+esi
*4]
522 __asm cmp esi
,BlockCount
535 #else // NO X86 optimization , use generic C/C++
545 right
= BlockCount
- 1;
547 while(left
!= right
) {
548 pos
= (left
+ right
) >> 1;
551 if(right
- left
== 1) {
552 if(List
[pos
+1] < Lba
)
556 if(List
[pos
] < Lba
) {
562 if((List
[pos
] < Lba
) && ((pos
+1) <= BlockCount
)) pos
++;
571 #pragma warning(pop) // re-enable warning #4035
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
583 WCacheInsertRangeToList() assumes that target array is of enough size.
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
598 ASSERT(!(BCount
& 0x80000000));
600 ULONG firstPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
);
601 ULONG lastPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
+BCount
);
602 ULONG offs
= firstPos
+ BCount
- lastPos
;
606 // ASSERT(lastPos+offs + ((*BlockCount) - lastPos) <= qq);
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
));
614 for(; firstPos
<lastPos
; firstPos
++) {
615 #ifdef WCACHE_BOUND_CHECKS
616 MyCheckArray(List
, firstPos
);
617 #endif //WCACHE_BOUND_CHECKS
618 List
[firstPos
] = Lba
;
621 (*BlockCount
) += offs
;
623 } // end WCacheInsertRangeToList()
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
632 WCacheInsertItemToList() assumes that target array is of enough size.
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
643 ULONG firstPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
+1);
644 if(firstPos
&& (List
[firstPos
-1] == Lba
))
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
));
655 #ifdef WCACHE_BOUND_CHECKS
656 MyCheckArray(List
, firstPos
);
657 #endif //WCACHE_BOUND_CHECKS
658 List
[firstPos
] = Lba
;
660 } // end WCacheInsertItemToList()
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
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
682 ULONG firstPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
);
683 ULONG lastPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
+BCount
);
684 ULONG offs
= lastPos
- firstPos
;
688 DbgMoveMemory(&(List
[lastPos
-offs
]), &(List
[lastPos
]), ((*BlockCount
) - lastPos
) * sizeof(ULONG
));
689 (*BlockCount
) -= offs
;
691 } // end WCacheRemoveRangeFromList()
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
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
710 if(!(*BlockCount
)) return;
711 ULONG lastPos
= WCacheGetSortedListIndex(*BlockCount
, List
, Lba
+1);
712 if(!lastPos
|| (lastPos
&& (List
[lastPos
-1] != Lba
)))
716 DbgMoveMemory(&(List
[lastPos
-1]), &(List
[lastPos
]), ((*BlockCount
) - lastPos
) * sizeof(ULONG
));
718 } // end WCacheRemoveItemFromList()
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
725 WCacheInitFrame() also checks if number of frames reaches limit
726 and invokes WCacheCheckLimits() to free some Frames/Blocks
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
737 PW_CACHE_ENTRY block_array
;
740 ULONG old_count
= Cache
->FrameCount
;
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
) {
748 WCacheCheckLimits(Cache
, Context
, frame
<< Cache
->BlocksPerFrameSh
, Cache
->PacketSize
*2);
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
;
755 //Cache->FrameList[frame].UpdateCount = 0;
756 //Cache->FrameList[frame].AccessCount = 0;
759 ASSERT((ULONG_PTR
)block_array
> 0x1000);
760 WCacheInsertItemToList(Cache
->CachedFramesList
, &(Cache
->FrameCount
), frame
);
761 RtlZeroMemory(block_array
, l
);
765 ASSERT(Cache
->FrameCount
<= Cache
->MaxFrames
);
767 ASSERT(old_count
< Cache
->FrameCount
);
770 } // end WCacheInitFrame()
773 WCacheRemoveFrame() frees storage for Frame (block_array) with
774 index 'frame' and removes it's index from sorted array of
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
786 PW_CACHE_ENTRY block_array
;
788 ULONG old_count
= Cache
->FrameCount
;
791 ASSERT(Cache
->FrameCount
<= Cache
->MaxFrames
);
792 block_array
= Cache
->FrameList
[frame
].Frame
;
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
);
801 ASSERT(old_count
> Cache
->FrameCount
);
804 } // end WCacheRemoveFrame()
807 WCacheSetModFlag() sets Modified flag for Block with offset 'i'
808 in Frame 'block_array'
811 #define WCacheSetModFlag(block_array, i) \
812 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_MODIFIED
815 WCacheClrModFlag() clears Modified flag for Block with offset 'i'
816 in Frame 'block_array'
819 #define WCacheClrModFlag(block_array, i) \
820 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_MODIFIED
823 WCacheGetModFlag() returns non-zero value if Modified flag for
824 Block with offset 'i' in Frame 'block_array' is set. Otherwise
828 #define WCacheGetModFlag(block_array, i) \
829 (*((PULONG)&(block_array[i].Sector)) & WCACHE_FLAG_MODIFIED)
833 WCacheSetBadFlag() sets Modified flag for Block with offset 'i'
834 in Frame 'block_array'
837 #define WCacheSetBadFlag(block_array, i) \
838 *((PULONG)&(block_array[i].Sector)) |= WCACHE_FLAG_BAD
841 WCacheClrBadFlag() clears Modified flag for Block with offset 'i'
842 in Frame 'block_array'
845 #define WCacheClrBadFlag(block_array, i) \
846 *((PULONG)&(block_array[i].Sector)) &= ~WCACHE_FLAG_BAD
849 WCacheGetBadFlag() returns non-zero value if Modified flag for
850 Block with offset 'i' in Frame 'block_array' is set. Otherwise
854 #define WCacheGetBadFlag(block_array, i) \
855 (((UCHAR)(block_array[i].Sector)) & WCACHE_FLAG_BAD)
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.
864 #define WCacheSectorAddr(block_array, i) \
865 ((ULONG_PTR)(block_array[i].Sector) & WCACHE_ADDR_MASK)
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.
873 #define WCacheFreeSector(frame, offs) \
875 DbgFreePool((PVOID)WCacheSectorAddr(block_array, offs)); \
876 block_array[offs].Sector = NULL; \
877 Cache->FrameList[frame].BlockCount--; \
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.
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
899 PW_CACHE_ASYNC WContext
;
902 WContext
= (PW_CACHE_ASYNC
)MyAllocatePoolTag__(NonPagedPool
,sizeof(W_CACHE_ASYNC
), MEM_WCCTX_TAG
);
905 Buffer
= (PCHAR
)DbgAllocatePoolWithTag(NonPagedPool
, BufferSize
*(2-Cache
->Chained
), MEM_WCBUF_TAG
);
907 MyFreePool__(WContext
);
912 KeInitializeEvent(&(WContext
->PhContext
.event
), SynchronizationEvent
, FALSE
);
913 WContext
->Cache
= Cache
;
915 (*PrevWContext
)->NextWContext
= WContext
;
916 // WContext->NextWContext = (*PrevWContext);
917 WContext
->NextWContext
= NULL
;
918 WContext
->Buffer
= Buffer
;
919 WContext
->Buffer2
= Buffer
+(Cache
->Chained
? 0 : BufferSize
);
921 if(!(*FirstWContext
))
922 (*FirstWContext
) = WContext
;
923 (*PrevWContext
) = WContext
;
926 } // end WCacheAllocAsyncEntry()
929 WCacheFreeAsyncEntry() releases storage previously allocated for
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
939 DbgFreePool(WContext
->Buffer
);
940 MyFreePool__(WContext
);
941 } // end WCacheFreeAsyncEntry()
943 //#define WCacheRaiseIoError(c, ct, s, l, bc, b, o, r)
947 IN PW_CACHE Cache
, // pointer to the Cache Control structure
957 if(!Cache
->ErrorHandlerProc
)
960 WCACHE_ERROR_CONTEXT ec
;
962 ec
.WCErrorCode
= ReadOp
? WCACHE_ERROR_READ
: WCACHE_ERROR_WRITE
;
964 ec
.ReadWrite
.Lba
= Lba
;
965 ec
.ReadWrite
.BCount
= BCount
;
966 ec
.ReadWrite
.Buffer
= Buffer
;
967 Status
= Cache
->ErrorHandlerProc(Context
, &ec
);
973 } // end WCacheRaiseIoError()
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
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
1005 PCHAR tmp_buff
= Cache
->tmp_buff
;
1006 PCHAR tmp_buff2
= Cache
->tmp_buff
;
1012 PW_CACHE_ASYNC WContext
;
1013 BOOLEAN Async
= (Cache
->ReadProcAsync
&& Cache
->WriteProcAsync
);
1015 BOOLEAN Chained
= Cache
->Chained
;
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
);
1024 mod
= (DbgCompareMemory(tmp_buff2
, tmp_buff
, PS
) != PS
);
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
)) {
1036 } else if(!WCacheSectorAddr(block_array
,Lba0
) &&
1037 ((block_type
= Cache
->CheckUsedProc(Context
, Lba
+i
)) & WCACHE_BLOCK_USED
) ) {
1039 if(block_type
& WCACHE_BLOCK_ZERO
) {
1046 // check if we are allowed to write to media
1047 if(mod
&& !PrefereWrite
) {
1048 return STATUS_RETRY
;
1050 // return STATUS_SUCCESS if requested packet contains no modified blocks
1053 return STATUS_SUCCESS
;
1056 // pefrorm full update cycle: prepare(optional)/read/modify/write
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
1067 WContext
= WCacheAllocAsyncEntry(Cache
, FirstWContext
, PrevWContext
, PS
);
1069 //return STATUS_INSUFFICIENT_RESOURCES;
1074 tmp_buff
= tmp_buff2
= (PCHAR
)(WContext
->Buffer
);
1075 WContext
->Lba
= Lba
;
1076 WContext
->Cmd
= ASYNC_CMD_UPDATE
;
1077 WContext
->State
= ASYNC_STATE_NONE
;
1081 // read packet (if it necessary)
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);
1091 status
= Cache
->ReadProc(Context
, tmp_buff
, PS
, Lba
, ReadBytes
, PH_TMP_BUFFER
);
1093 if(!OS_SUCCESS(status
)) {
1094 status
= WCacheRaiseIoError(Cache
, Context
, status
, Lba
, PSs
, tmp_buff
, WCACHE_R_OP
, NULL
);
1095 if(!OS_SUCCESS(status
)) {
1101 RtlZeroMemory(tmp_buff
, PS
);
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
;
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
)) ) {
1123 ASSERT((ULONG
)WCacheSectorAddr(block_array
,Lba0
) & 0x80000000);
1127 mod
= (DbgCompareMemory(tmp_buff2
+ (i
<< BSh
),
1128 (PVOID
)WCacheSectorAddr(block_array
, Lba0
),
1132 DbgCopyMemory(tmp_buff2
+ (i
<< BSh
),
1133 (PVOID
)WCacheSectorAddr(block_array
, Lba0
),
1139 WContext
->State
== ASYNC_STATE_WRITE_PRE
) {
1140 // Return if block is prepared for write and we are in chained mode.
1142 // Mark block as written if we have found that data in it
1143 // is not actually modified.
1144 WContext
->State
= ASYNC_STATE_DONE
;
1147 return STATUS_SUCCESS
;
1152 // If the check above reported some changes in packet
1153 // we should write packet out to media.
1154 // Otherwise, just complete request.
1158 WContext
->State
= ASYNC_STATE_WRITE
;
1159 status
= Cache
->WriteProcAsync(Context
, WContext
, tmp_buff2
, PS
, Lba
,
1160 &(WContext
->TransferredBytes
), FALSE
);
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
);
1170 WCacheCompleteAsync__(WContext
, STATUS_SUCCESS
);
1172 return STATUS_SUCCESS
;
1176 } // end WCacheUpdatePacket()
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.
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)
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
);
1201 } // end WCacheFreePacket()
1204 WCacheUpdatePacketComplete() is called to continue processing of packet
1206 In async mode it waits for completion of pre-read requests,
1207 initiates writes, waits for their completion and returns control to
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
1220 PW_CACHE_ASYNC WContext
= (*FirstWContext
);
1223 PW_CACHE_ASYNC NextWContext
;
1224 ULONG PS
= Cache
->BlockSize
<< Cache
->PacketSizeSh
; // packet size (bytes)
1225 ULONG PSs
= Cache
->PacketSize
;
1229 // Walk through all chained blocks and wait
1230 // for completion of read operations.
1231 // Also invoke writes of already prepared packets.
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
);
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
);
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
;
1251 if(WContext
->Cmd
== ASYNC_CMD_READ
&&
1252 WContext
->State
== ASYNC_STATE_READ
) {
1253 // wait for async read
1254 DbgWaitForSingleObject(&(WContext
->PhContext
.event
), NULL
);
1256 WContext
= WContext
->NextWContext
;
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
);
1263 NextWContext
= WContext
->NextWContext
;
1264 if(WContext
->Cmd
== ASYNC_CMD_UPDATE
&&
1265 WContext
->State
== ASYNC_STATE_WRITE
) {
1268 DbgWaitForSingleObject(&(WContext
->PhContext
.event
), NULL
);
1270 frame
= WContext
->Lba
>> Cache
->BlocksPerFrameSh
;
1271 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
1274 WCacheFreePacket(Cache
, frame
,
1275 Cache
->FrameList
[frame
].Frame
,
1276 WContext
->Lba
- firstLba
, PSs
);
1279 WCacheFreeAsyncEntry(Cache
, WContext
);
1280 WContext
= NextWContext
;
1282 (*FirstWContext
) = NULL
;
1283 (*PrevWContext
) = NULL
;
1284 } // end WCacheUpdatePacketComplete()
1287 WCacheCheckLimits() checks if we've enough free Frame- &
1288 Block-entries under Frame- and Block-limit to feet
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
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
1306 /* if(!Cache->FrameCount || !Cache->BlockCount) {
1307 ASSERT(!Cache->FrameCount);
1308 ASSERT(!Cache->BlockCount);
1309 if(!Cache->FrameCount)
1310 return STATUS_SUCCESS;
1313 // check if we have reached Frame or Block limit
1314 if(!Cache
->FrameCount
&& !Cache
->BlockCount
) {
1315 return STATUS_SUCCESS
;
1318 // check for empty frames
1319 if(Cache
->FrameCount
> (Cache
->MaxFrames
*3)/4) {
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
);
1328 ASSERT(Cache
->FrameList
[frame
].Frame
);
1333 if(!Cache
->BlockCount
) {
1334 return STATUS_SUCCESS
;
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
);
1345 return WCacheCheckLimitsR(Cache
, Context
, ReqLba
, BCount
);
1347 return STATUS_DRIVER_INTERNAL_ERROR
;
1348 } // end WCacheCheckLimits()
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()
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
1369 lba_t
* List
= Cache
->CachedBlocksList
;
1372 // PCHAR tmp_buff = Cache->tmp_buff;
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
;
1383 ULONG FreeFrameCount
= 0;
1385 PW_CACHE_ASYNC FirstWContext
= NULL
;
1386 PW_CACHE_ASYNC PrevWContext
= NULL
;
1387 ULONG chain_count
= 0;
1389 if(Cache
->FrameCount
>= Cache
->MaxFrames
) {
1390 FreeFrameCount
= Cache
->FramesToKeepFree
;
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
;
1399 // remove(flush) some frames
1400 while((Cache
->FrameCount
>= Cache
->MaxFrames
) || FreeFrameCount
) {
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
));
1407 ASSERT(!Cache
->BlockCount
);
1408 if(!Cache
->FrameCount
)
1412 frame
= WCacheFindFrameToRelease(Cache
);
1414 if(Cache
->FrameList
[frame
].WriteCount
) {
1416 if(try_count
< MAX_TRIES_FOR_NA
) goto Try_Another_Frame
;
1421 if(Cache
->FrameList
[frame
].UpdateCount
) {
1422 try_count
= MAX_TRIES_FOR_NA
;
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
;
1438 UDFPrint(("Hmm...\n"));
1440 return STATUS_DRIVER_INTERNAL_ERROR
;
1443 while(firstPos
< lastPos
) {
1445 Lba
= List
[firstPos
] & ~(PSs
-1);
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
);
1451 if(status
!= STATUS_PENDING
) {
1453 WCacheFreePacket(Cache
, frame
, block_array
, Lba
-firstLba
, PSs
);
1457 while((firstPos
< lastPos
) && (Lba
> List
[firstPos
])) {
1461 // write chained packets
1462 if(chain_count
>= WCACHE_MAX_CHAIN
) {
1463 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
1467 // remove flushed blocks from all lists
1468 WCacheRemoveRangeFromList(List
, &(Cache
->BlockCount
), firstLba
, Cache
->BlocksPerFrame
);
1469 WCacheRemoveRangeFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), firstLba
, Cache
->BlocksPerFrame
);
1471 WCacheRemoveFrame(Cache
, Context
, frame
);
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
;
1480 // remove(flush) packet
1481 while((Cache
->BlockCount
+ WCacheGetSortedListIndex(Cache
->BlockCount
, List
, ReqLba
) +
1482 BCount
- WCacheGetSortedListIndex(Cache
->BlockCount
, List
, ReqLba
+BCount
)) > Cache
->MaxBlocks
) {
1486 Lba
= WCacheFindLbaToRelease(Cache
) & ~(PSs
-1);
1487 if(Lba
== WCACHE_INVALID_LBA
) {
1488 ASSERT(!Cache
->FrameCount
);
1489 ASSERT(!Cache
->BlockCount
);
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
;
1498 // write already prepared blocks to disk and return error
1499 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
);
1501 return STATUS_DRIVER_INTERNAL_ERROR
;
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
);
1508 if(status
== STATUS_RETRY
) {
1510 goto Try_Another_Block
;
1514 WCacheFreePacket(Cache
, frame
, block_array
, Lba
-firstLba
, PSs
);
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
);
1522 ASSERT(Cache
->FrameList
[frame
].Frame
);
1525 if(chain_count
>= WCACHE_MAX_CHAIN
) {
1526 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
1530 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
);
1531 return STATUS_SUCCESS
;
1532 } // end WCacheCheckLimitsRW()
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
,
1550 PCHAR tmp_buff
= NULL
;
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
;
1559 frame
= List
[firstPos
] >> Cache
->BlocksPerFrameSh
;
1560 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
1562 while(firstPos
< lastPos
) {
1564 ASSERT(Cache
->FrameCount
<= Cache
->MaxFrames
);
1565 Lba
= List
[firstPos
];
1566 if(!WCacheGetModFlag(block_array
, Lba
- firstLba
)) {
1569 WCacheFreePacket(Cache
, frame
, block_array
, Lba
-firstLba
, 1);
1574 tmp_buff
= Cache
->tmp_buff
;
1577 while((firstPos
+n
< lastPos
) &&
1578 (List
[firstPos
+n
] == PrevLba
+1)) {
1580 if(!WCacheGetModFlag(block_array
, PrevLba
- firstLba
))
1582 DbgCopyMemory(tmp_buff
+ (n
<< BSh
),
1583 (PVOID
)WCacheSectorAddr(block_array
, PrevLba
- firstLba
),
1590 DbgCopyMemory(tmp_buff
,
1591 (PVOID
)WCacheSectorAddr(block_array
, Lba
- firstLba
),
1594 tmp_buff
= (PCHAR
)WCacheSectorAddr(block_array
, Lba
- firstLba
);
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
)) {
1607 WCacheFreePacket(Cache
, frame
, block_array
, Lba
-firstLba
, n
);
1609 // clear Modified flag
1612 for(i
=0; i
<n
; i
++) {
1613 WCacheClrModFlag(block_array
, Lba
+i
);
1619 } // end WCacheFlushBlocksRAM()
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()
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
1639 lba_t
* List
= Cache
->CachedBlocksList
;
1642 // PCHAR tmp_buff = Cache->tmp_buff;
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
;
1652 ULONG FreeFrameCount
= 0;
1655 if(Cache
->FrameCount
>= Cache
->MaxFrames
) {
1656 FreeFrameCount
= Cache
->FramesToKeepFree
;
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
;
1665 // remove(flush) some frames
1666 while((Cache
->FrameCount
>= Cache
->MaxFrames
) || FreeFrameCount
) {
1667 ASSERT(Cache
->FrameCount
<= Cache
->MaxFrames
);
1669 if(!Cache
->FrameCount
|| !Cache
->BlockCount
) {
1670 ASSERT(!Cache
->FrameCount
);
1671 ASSERT(!Cache
->BlockCount
);
1672 if(!Cache
->FrameCount
)
1676 frame
= WCacheFindFrameToRelease(Cache
);
1678 if(Cache
->FrameList
[frame
].WriteCount
) {
1680 if(try_count
< MAX_TRIES_FOR_NA
) goto Try_Another_Frame
;
1686 if(Cache->FrameList[frame].UpdateCount) {
1687 try_count = MAX_TRIES_FOR_NA;
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
;
1704 UDFPrint(("Hmm...\n"));
1706 return STATUS_DRIVER_INTERNAL_ERROR
;
1708 WCacheFlushBlocksRAM(Cache
, Context
, block_array
, List
, firstPos
, lastPos
, TRUE
);
1710 WCacheRemoveRangeFromList(List
, &(Cache
->BlockCount
), firstLba
, Cache
->BlocksPerFrame
);
1711 WCacheRemoveRangeFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), firstLba
, Cache
->BlocksPerFrame
);
1712 WCacheRemoveFrame(Cache
, Context
, frame
);
1715 // check if we try to read too much data
1716 if(BCount
> Cache
->MaxBlocks
) {
1717 return STATUS_INVALID_PARAMETER
;
1720 // remove(flush) packet
1721 while((Cache
->BlockCount
+ WCacheGetSortedListIndex(Cache
->BlockCount
, List
, ReqLba
) +
1722 BCount
- WCacheGetSortedListIndex(Cache
->BlockCount
, List
, ReqLba
+BCount
)) > Cache
->MaxBlocks
) {
1724 //Try_Another_Block:
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
);
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
;
1740 return STATUS_DRIVER_INTERNAL_ERROR
;
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
);
1749 ASSERT(Cache
->FrameList
[frame
].Frame
);
1752 return STATUS_SUCCESS
;
1753 } // end WCacheCheckLimitsRAM()
1762 IN PW_CACHE Cache
, // pointer to the Cache Control structure
1763 IN PVOID Context
// user-supplied context for IO callbacks
1768 lba_t
* List
= Cache
->CachedBlocksList
;
1772 PW_CACHE_ENTRY block_array
;
1775 // remove(flush) some frames
1776 while(Cache
->FrameCount
) {
1778 frame
= Cache
->CachedFramesList
[0];
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
;
1787 UDFPrint(("Hmm...\n"));
1789 return STATUS_DRIVER_INTERNAL_ERROR
;
1791 WCacheFlushBlocksRAM(Cache
, Context
, block_array
, List
, firstPos
, lastPos
, TRUE
);
1793 WCacheRemoveRangeFromList(List
, &(Cache
->BlockCount
), firstLba
, Cache
->BlocksPerFrame
);
1794 WCacheRemoveRangeFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), firstLba
, Cache
->BlocksPerFrame
);
1795 WCacheRemoveFrame(Cache
, Context
, frame
);
1798 ASSERT(!Cache
->FrameCount
);
1799 ASSERT(!Cache
->BlockCount
);
1800 return STATUS_SUCCESS
;
1801 } // end WCachePurgeAllRAM()
1810 IN PW_CACHE Cache
, // pointer to the Cache Control structure
1811 IN PVOID Context
// user-supplied context for IO callbacks
1816 lba_t
* List
= Cache
->CachedBlocksList
;
1820 PW_CACHE_ENTRY block_array
;
1824 while(Cache
->WriteCount
) {
1826 frame
= Cache
->CachedModifiedBlocksList
[0] >> Cache
->BlocksPerFrameSh
;
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
;
1835 UDFPrint(("Hmm...\n"));
1837 return STATUS_DRIVER_INTERNAL_ERROR
;
1839 WCacheFlushBlocksRAM(Cache
, Context
, block_array
, List
, firstPos
, lastPos
, FALSE
);
1841 WCacheRemoveRangeFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), firstLba
, Cache
->BlocksPerFrame
);
1844 return STATUS_SUCCESS
;
1845 } // end WCacheFlushAllRAM()
1848 WCachePreReadPacket__() reads & caches the whole packet containing
1849 requested LBA. This routine just caches data, it doesn't copy anything
1851 In general we have no user buffer here... ;)
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
1862 OSSTATUS status
= STATUS_SUCCESS
;
1863 PW_CACHE_ENTRY block_array
;
1864 ULONG BSh
= Cache
->BlockSizeSh
;
1865 ULONG BS
= Cache
->BlockSize
;
1868 ULONG PS
= Cache
->PacketSize
; // (in blocks)
1870 ULONG i
, n
, err_count
;
1871 BOOLEAN sector_added
= FALSE
;
1873 BOOLEAN zero
= FALSE
;//TRUE;
1875 ULONG first_zero=0, last_zero=0;
1876 BOOLEAN count_first_zero = TRUE;
1880 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
1881 i
= Lba
- (frame
<< Cache
->BlocksPerFrameSh
);
1883 // assume successful operation
1884 block_array
= Cache
->FrameList
[frame
].Frame
;
1886 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
1887 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
1889 return STATUS_INSUFFICIENT_RESOURCES
;
1892 // skip cached extent (if any)
1894 while((n
< BCount
) &&
1895 (n
< Cache
->BlocksPerFrame
)) {
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
;
1904 if(!(block_type
& WCACHE_BLOCK_ZERO
)) {
1906 //count_first_zero = FALSE;
1909 // sector is not cached, stop search
1914 if(count_first_zero) {
1922 // do nothing if all sectors are already cached
1925 // read whole packet
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
);
1932 status
= STATUS_SUCCESS
;
1933 //RtlZeroMemory(Cache->tmp_buff_r, PS<<BSh);
1934 _ReadBytes
= PS
<<BSh
;
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
)) {
1942 addr
= block_array
[i
].Sector
= (PCHAR
)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE
, BS
, MEM_WCBUF_TAG
);
1947 sector_added
= TRUE
;
1949 DbgCopyMemory(addr
, Cache
->tmp_buff_r
+(n
<<BSh
), BS
);
1951 RtlZeroMemory(addr
, BS
);
1953 Cache
->FrameList
[frame
].BlockCount
++;
1956 // read sectors one by one and copy them to cache
1957 // unreadable sectors will be treated as zero-filled
1959 for(n
=0; n
<BCount
; n
++, i
++) {
1960 if(WCacheSectorAddr(block_array
,i
)) {
1963 addr
= block_array
[i
].Sector
= (PCHAR
)DbgAllocatePoolWithTag(CACHED_BLOCK_MEMORY_TYPE
, BS
, MEM_WCBUF_TAG
);
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
)) {
1976 if(!zero
&& OS_SUCCESS(status
)) {
1977 DbgCopyMemory(addr
, Cache
->tmp_buff_r
, BS
);
1979 if(Cache
->RememberBB
) {
1980 RtlZeroMemory(addr
, BS
);
1982 if(!OS_SUCCESS(status)) {
1983 WCacheSetBadFlag(block_array,i);
1987 Cache
->FrameList
[frame
].BlockCount
++;
1988 if(err_count
>= 2) {
1992 // _ReadBytes = n<<BSh;
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
2000 WCacheInsertRangeToList(Cache
->CachedBlocksList
, &(Cache
->BlockCount
), Lba
, n
);
2003 } // end WCachePreReadPacket__()
2006 WCacheReadBlocks__() reads data from cache or
2007 read it form media and store in cache.
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
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
;
2029 ULONG to_read
, saved_to_read
;
2030 // PCHAR saved_buff = Buffer;
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
2038 WcPrint(("WC:R %x (%x)\n", Lba
, BCount
));
2041 // check if we try to read too much data
2042 if(BCount
>= Cache
->MaxBlocks
) {
2045 status
= STATUS_INVALID_PARAMETER
;
2049 status
= WCacheReadBlocks__(Cache
, Context
, Buffer
+ (i
<<BSh
), Lba
, PS
, &_ReadBytes
, FALSE
);
2050 (*ReadBytes
) += _ReadBytes
;
2051 if(!OS_SUCCESS(status
) || (BCount
<= PS
)) break;
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
);
2068 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
2071 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
2072 i
= Lba
- (frame
<< Cache
->BlocksPerFrameSh
);
2074 if(Cache
->CacheWholePacket
&& (BCount
< PS
)) {
2076 !OS_SUCCESS(status
= WCacheCheckLimits(Cache
, Context
, Lba
& ~(PS
-1), PS
*2)) ) {
2077 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2082 !OS_SUCCESS(status
= WCacheCheckLimits(Cache
, Context
, Lba
, BCount
))) {
2083 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2088 // convert to shared
2089 // ExConvertExclusiveToSharedLite(&(Cache->WCacheLock));
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
2098 status
= WCachePreReadPacket__(Cache
, Context
, Lba
);
2100 status
= STATUS_SUCCESS
;
2103 // assume successful operation
2104 block_array
= Cache
->FrameList
[frame
].Frame
;
2106 ASSERT(!CachedOnly
);
2107 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
2108 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
2110 status
= STATUS_INSUFFICIENT_RESOURCES
;
2115 Cache
->FrameList
[frame
].AccessCount
++;
2117 if(i
>= Cache
->BlocksPerFrame
) {
2119 block_array
= Cache
->FrameList
[frame
].Frame
;
2120 i
-= Cache
->BlocksPerFrame
;
2123 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
2124 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
2126 status
= STATUS_INSUFFICIENT_RESOURCES
;
2130 // 'read' cached extent (if any)
2131 // it is just copying
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
;
2141 DbgCopyMemory(Buffer
, addr
, BS
);
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
) {
2152 (i
< Cache
->BlocksPerFrame
) &&
2153 (!WCacheSectorAddr(block_array
, i
)) ) {
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
)) {
2166 // WCacheInsertRangeToList(Cache->CachedBlocksList, &(Cache->BlockCount), Lba, saved_BC - BCount);
2168 Lba
+= saved_BC
- BCount
;
2175 // UDFPrint(("Unaligned\n"));
2177 // read non-cached extent (if any)
2178 // firstable, we'll get total number of sectors to read
2183 (i
< Cache
->BlocksPerFrame
) &&
2184 (!WCacheSectorAddr(block_array
, i
)) ) {
2189 // read some not cached sectors
2192 saved_to_read
= to_read
;
2194 // split request if necessary
2195 if(saved_to_read
> MaxR
) {
2196 WCacheInsertRangeToList(Cache
->CachedBlocksList
, &(Cache
->BlockCount
), Lba
, saved_BC
- BCount
);
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
;
2207 goto store_read_data_1
;
2210 saved_to_read
-= MaxR
;
2214 } while(saved_to_read
> MaxR
);
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
;
2227 Buffer
+= saved_to_read
;
2233 // and now we'll copy them to cache
2236 Buffer
-= (to_read
- saved_to_read
);
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
;
2245 DbgCopyMemory(block_array
[i
].Sector
, Buffer
, BS
);
2246 Cache
->FrameList
[frame
].BlockCount
++;
2251 if(!OS_SUCCESS(status
))
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;
2266 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2270 } // end WCacheReadBlocks__()
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
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
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
;
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
2303 // BOOLEAN Aligned = FALSE;
2305 BOOLEAN WriteThrough
= FALSE
;
2309 WcPrint(("WC:W %x (%x)\n", Lba
, BCount
));
2312 // UDFPrint(("BCount:%x\n",BCount));
2313 // check if we try to read too much data
2314 if(BCount
>= Cache
->MaxBlocks
) {
2317 status
= STATUS_INVALID_PARAMETER
;
2321 // UDFPrint((" BCount:%x\n",BCount));
2322 status
= WCacheWriteBlocks__(Cache
, Context
, Buffer
+ (i
<<BSh
), Lba
, min(PS
,BCount
), &_WrittenBytes
, FALSE
);
2323 (*WrittenBytes
) += _WrittenBytes
;
2327 if(!OS_SUCCESS(status
) || (BCount
< PS
))
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
;
2337 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
2340 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
2341 i
= Lba
- (frame
<< Cache
->BlocksPerFrameSh
);
2344 !OS_SUCCESS(status
= WCacheCheckLimits(Cache
, Context
, Lba
, BCount
))) {
2345 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2349 // assume successful operation
2350 block_array
= Cache
->FrameList
[frame
].Frame
;
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
);
2364 ASSERT(!CachedOnly
);
2365 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
2366 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
2368 status
= STATUS_INSUFFICIENT_RESOURCES
;
2373 if(Cache
->Mode
== WCACHE_MODE_RAM
&&
2375 // !(Lba & (PS-1)) &&
2376 (!(BCount
& (PS
-1)) || (BCount
> PS
)) ) {
2377 WriteThrough
= TRUE
;
2379 WTh_BCount
= BCount
;
2381 if(Cache
->Mode
== WCACHE_MODE_RAM
&&
2382 ((Lba
& ~PacketMask
) != ((Lba
+BCount
-1) & ~PacketMask
))
2384 WriteThrough
= TRUE
;
2385 WTh_Lba
= Lba
& ~PacketMask
;
2389 Cache
->FrameList
[frame
].UpdateCount
++;
2390 // UDFPrint((" BCount:%x\n",BCount));
2392 if(i
>= Cache
->BlocksPerFrame
) {
2394 block_array
= Cache
->FrameList
[frame
].Frame
;
2395 i
-= Cache
->BlocksPerFrame
;
2398 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
2399 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
2401 status
= STATUS_INSUFFICIENT_RESOURCES
;
2405 // 'write' cached extent (if any)
2406 // it is just copying
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
;
2419 DbgCopyMemory(addr
, Buffer
, BS
);
2420 WCacheSetModFlag(block_array
, i
);
2422 *WrittenBytes
+= BS
;
2426 // write non-cached not-aligned extent (if any) till aligned one
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
;
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
);
2442 *WrittenBytes
+= BS
;
2444 Cache
->FrameList
[frame
].BlockCount
++;
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
2450 ( !(i
& PacketMask
) ||
2451 ((Cache
->Mode
== WCACHE_MODE_R
) && (BCount
>= PS
)) )) {
2454 (i
< Cache
->BlocksPerFrame
) &&
2455 (!WCacheSectorAddr(block_array
, i
)) ) {
2461 // if(!OS_SUCCESS(status = Cache->WriteProcAsync(Context, Buffer, BS*n, Lba+saved_BC-BCount, &_WrittenBytes, FALSE)))
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
);
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
)) {
2484 *WrittenBytes
+= PS
<<BSh
;
2489 // write non-cached not-aligned extent (if any)
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
;
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
);
2503 *WrittenBytes
+= BS
;
2505 Cache
->FrameList
[frame
].BlockCount
++;
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
);
2517 if(WriteThrough
&& !BCount
) {
2523 BCount
= WTh_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
;
2538 status
= WCacheFlushBlocksRAM(Cache
, Context
, block_array
, Cache
->CachedBlocksList
, firstPos
, lastPos
, FALSE
);
2539 WCacheRemoveRangeFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), Lba
, d
);
2548 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2551 } // end WCacheWriteBlocks__()
2554 WCacheFlushAll__() copies all data stored in cache to media.
2555 Flushed blocks are kept in cache.
2560 IN PW_CACHE Cache
, // pointer to the Cache Control structure
2561 IN PVOID Context
) // user-supplied context for IO callbacks
2563 if(!(Cache
->ReadProc
)) return;
2564 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
2566 switch(Cache
->Mode
) {
2567 case WCACHE_MODE_RAM
:
2568 WCacheFlushAllRAM(Cache
, Context
);
2570 case WCACHE_MODE_ROM
:
2571 case WCACHE_MODE_RW
:
2572 WCacheFlushAllRW(Cache
, Context
);
2575 WCachePurgeAllR(Cache
, Context
);
2579 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2581 } // end WCacheFlushAll__()
2584 WCachePurgeAll__() copies all data stored in cache to media.
2585 Flushed blocks are removed cache.
2590 IN PW_CACHE Cache
, // pointer to the Cache Control structure
2591 IN PVOID Context
) // user-supplied context for IO callbacks
2593 if(!(Cache
->ReadProc
)) return;
2594 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
2596 switch(Cache
->Mode
) {
2597 case WCACHE_MODE_RAM
:
2598 WCachePurgeAllRAM(Cache
, Context
);
2600 case WCACHE_MODE_ROM
:
2601 case WCACHE_MODE_RW
:
2602 WCachePurgeAllRW(Cache
, Context
);
2605 WCachePurgeAllR(Cache
, Context
);
2609 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2611 } // end WCachePurgeAll__()
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.
2622 IN PW_CACHE Cache
, // pointer to the Cache Control structure
2623 IN PVOID Context
) // user-supplied context for IO callbacks
2627 lba_t
* List
= Cache
->CachedBlocksList
;
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
;
2638 PW_CACHE_ASYNC FirstWContext
= NULL
;
2639 PW_CACHE_ASYNC PrevWContext
= NULL
;
2640 ULONG chain_count
= 0;
2642 if(!(Cache
->ReadProc
)) return;
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
;
2656 WCacheUpdatePacket(Cache
, Context
, &FirstWContext
, &PrevWContext
, block_array
, firstLba
,
2657 Lba
, BSh
, BS
, PS
, PSs
, &ReadBytes
, TRUE
, ASYNC_STATE_NONE
);
2660 WCacheFreePacket(Cache
, frame
, block_array
, Lba
-firstLba
, PSs
);
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
);
2668 ASSERT(Cache
->FrameList
[frame
].Frame
);
2671 if(chain_count
>= WCACHE_MAX_CHAIN
) {
2672 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
2676 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
);
2678 } // end WCachePurgeAllRW()
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.
2689 IN PW_CACHE Cache
, // pointer to the Cache Control structure
2690 IN PVOID Context
) // user-supplied context for IO callbacks
2694 lba_t
* List
= Cache
->CachedModifiedBlocksList
;
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
;
2706 PW_CACHE_ASYNC FirstWContext
= NULL
;
2707 PW_CACHE_ASYNC PrevWContext
= NULL
;
2709 ULONG chain_count
= 0;
2711 if(!(Cache
->ReadProc
)) return;
2713 // walk through modified blocks
2714 while(Cache
->WriteCount
) {
2715 Lba
= List
[0] & ~(PSs
-1);
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
;
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
);
2731 for(i
=0; i
<PSs
; i
++) {
2732 WCacheClrModFlag(block_array
, Lba
+i
);
2736 if(chain_count
>= WCACHE_MAX_CHAIN
) {
2737 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
2741 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
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
;
2754 ASSERT(!WCacheGetModFlag(block_array
, Lba
-firstLba
));
2759 } // end WCacheFlushAllRW()
2762 WCacheRelease__() frees all allocated memory blocks and
2763 deletes synchronization resources
2768 IN PW_CACHE Cache
// pointer to the Cache Control structure
2772 PW_CACHE_ENTRY block_array
;
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
;
2782 for(k
=0; k
<Cache
->BlocksPerFrame
; k
++) {
2783 if(WCacheSectorAddr(block_array
, k
)) {
2784 WCacheFreeSector(j
, k
);
2787 MyFreePool__(block_array
);
2790 if(Cache
->FrameList
)
2791 MyFreePool__(Cache
->FrameList
);
2792 if(Cache
->CachedBlocksList
)
2793 MyFreePool__(Cache
->CachedBlocksList
);
2794 if(Cache
->CachedBlocksList
)
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
));
2808 } // end WCacheRelease__()
2811 WCacheIsInitialized__() checks if the pointer supplied points
2812 to initialized cache structure.
2816 WCacheIsInitialized__(
2820 return (Cache
->ReadProc
!= NULL
);
2821 } // end WCacheIsInitialized__()
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
2833 lba_t
* List
= Cache
->CachedModifiedBlocksList
;
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
;
2845 PW_CACHE_ASYNC FirstWContext
= NULL
;
2846 PW_CACHE_ASYNC PrevWContext
= NULL
;
2848 ULONG chain_count
= 0;
2851 if(!(Cache
->ReadProc
)) return STATUS_INVALID_PARAMETER
;
2853 // walk through modified blocks
2854 lim
= (_Lba
+BCount
+PSs
-1) & ~(PSs
-1);
2855 for(Lba
= _Lba
& ~(PSs
-1);Lba
< lim
; Lba
+= PSs
) {
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
;
2862 // not cached block may be requested for flush
2863 Lba
+= (1 << BFs
) - PSs
;
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
);
2872 for(i
=0; i
<PSs
; i
++) {
2873 WCacheClrModFlag(block_array
, Lba
+i
);
2878 if(chain_count
>= WCACHE_MAX_CHAIN
) {
2879 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
2883 WCacheUpdatePacketComplete(Cache
, Context
, &FirstWContext
, &PrevWContext
, FALSE
);
2885 if(Cache->Mode != WCACHE_MODE_RAM)
2886 return STATUS_SUCCESS;
2889 return STATUS_SUCCESS
;
2890 } // end WCacheFlushBlocksRW()
2893 WCacheFlushBlocks__() copies specified blocks stored in cache to media.
2894 Flushed blocks are kept in cache.
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
2907 if(!(Cache
->ReadProc
)) return STATUS_INVALID_PARAMETER
;
2908 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
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
));
2915 status
= STATUS_INVALID_PARAMETER
;
2919 switch(Cache
->Mode
) {
2920 case WCACHE_MODE_RAM
:
2921 // WCacheFlushBlocksRW(Cache, Context);
2923 case WCACHE_MODE_ROM
:
2924 case WCACHE_MODE_RW
:
2925 status
= WCacheFlushBlocksRW(Cache
, Context
, Lba
, BCount
);
2928 status
= STATUS_SUCCESS
;
2932 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
2934 } // end WCacheFlushBlocks__()
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.
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
2959 OSSTATUS status
= STATUS_SUCCESS
;
2960 PW_CACHE_ENTRY block_array
;
2961 ULONG BS
= Cache
->BlockSize
;
2966 WcPrint(("WC:%sD %x (1)\n", Modified
? "W" : "R", Lba
));
2968 // lock cache if nececcary
2970 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
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
));
2977 status
= STATUS_INVALID_PARAMETER
;
2981 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
2982 i
= Lba
- (frame
<< Cache
->BlocksPerFrameSh
);
2983 // check if we have enough space to store requested block
2985 !OS_SUCCESS(status
= WCacheCheckLimits(Cache
, Context
, Lba
, 1))) {
2990 // small updates are more important
2991 block_array
= Cache
->FrameList
[frame
].Frame
;
2993 Cache
->FrameList
[frame
].UpdateCount
+=8;
2995 Cache
->FrameList
[frame
].AccessCount
+=8;
2998 ASSERT(Cache
->FrameCount
< Cache
->MaxFrames
);
2999 block_array
= WCacheInitFrame(Cache
, Context
, frame
);
3001 status
= STATUS_INSUFFICIENT_RESOURCES
;
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
);
3013 status
= STATUS_INSUFFICIENT_RESOURCES
;
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);
3026 if(block_type
& WCACHE_BLOCK_BAD
) {
3029 status
= STATUS_DEVICE_DATA_ERROR
;
3032 if(!(block_type
& WCACHE_BLOCK_ZERO
)) {
3035 status
= STATUS_SUCCESS
;
3036 RtlZeroMemory(addr
, BS
);
3038 // now add pointer to buffer to common storage
3039 block_array
[i
].Sector
= addr
;
3040 WCacheInsertItemToList(Cache
->CachedBlocksList
, &(Cache
->BlockCount
), Lba
);
3042 WCacheInsertItemToList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), Lba
);
3043 WCacheSetModFlag(block_array
, i
);
3045 Cache
->FrameList
[frame
].BlockCount
++;
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
;
3056 #ifndef UDF_CHECK_UTIL
3057 ASSERT(block_type
& WCACHE_BLOCK_USED
);
3059 if(!(block_type
& WCACHE_BLOCK_USED
)) {
3060 UDFPrint(("LBA %#x is not marked as used\n", Lba
));
3064 !WCacheGetModFlag(block_array
, i
)) {
3065 WCacheInsertItemToList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), Lba
);
3066 WCacheSetModFlag(block_array
, i
);
3069 (*CachedBlock
) = addr
;
3074 } // end WCacheDirect__()
3077 WCacheEODirect__() must be used to unlock cache after calls to
3078 to WCacheStartDirect__().
3083 IN PW_CACHE Cache
, // pointer to the Cache Control structure
3084 IN PVOID Context
// user-supplied context for IO callbacks
3087 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
3088 return STATUS_SUCCESS
;
3089 } // end WCacheEODirect__()
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__().
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.
3108 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
3111 ExAcquireResourceSharedLite(&(Cache
->WCacheLock
), TRUE
);
3113 return STATUS_SUCCESS
;
3114 } // end WCacheStartDirect__()
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__().
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
3134 PW_CACHE_ENTRY block_array
;
3136 // check if we try to access beyond cached area
3137 if((Lba
< Cache
->FirstLba
) ||
3138 (Lba
+ BCount
- 1 > Cache
->LastLba
)) {
3142 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3143 i
= Lba
- (frame
<< Cache
->BlocksPerFrameSh
);
3145 block_array
= Cache
->FrameList
[frame
].Frame
;
3151 if(i
>= Cache
->BlocksPerFrame
) {
3153 block_array
= Cache
->FrameList
[frame
].Frame
;
3154 i
-= Cache
->BlocksPerFrame
;
3159 // 'read' cached extent (if any)
3161 (i
< Cache
->BlocksPerFrame
) &&
3162 WCacheSectorAddr(block_array
, i
) &&
3163 /*!WCacheGetBadFlag(block_array, i)*/
3164 /*!(Cache->CheckUsedProc(Context, Lba) & WCACHE_BLOCK_BAD)*/
3171 (i
< Cache
->BlocksPerFrame
) /*&&
3172 (!WCacheSectorAddr(block_array, i))*/ ) {
3177 } // end WCacheIsCached__()
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()
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
3197 lba_t
* List
= Cache
->CachedBlocksList
;
3199 PCHAR tmp_buff
= Cache
->tmp_buff
;
3201 ULONG BSh
= Cache
->BlockSizeSh
;
3202 ULONG BS
= Cache
->BlockSize
;
3203 ULONG PS
= BS
<< Cache
->PacketSizeSh
; // packet size (bytes)
3204 ULONG PSs
= Cache
->PacketSize
;
3206 PW_CACHE_ENTRY block_array
;
3210 ULONG MaxReloc
= Cache
->PacketSize
;
3211 PULONG reloc_tab
= Cache
->reloc_tab
;
3213 // check if we try to read too much data
3214 if(BCount
> Cache
->MaxBlocks
) {
3215 return STATUS_INVALID_PARAMETER
;
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
) ) {
3225 Lba
= WCacheFindLbaToRelease(Cache
);
3226 if(Lba
== WCACHE_INVALID_LBA
) {
3227 ASSERT(!Cache
->FrameCount
);
3228 ASSERT(!Cache
->BlockCount
);
3231 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3232 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3233 firstPos
= WCacheGetSortedListIndex(Cache
->BlockCount
, List
, Lba
);
3234 block_array
= Cache
->FrameList
[frame
].Frame
;
3236 return STATUS_DRIVER_INTERNAL_ERROR
;
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
);
3245 return STATUS_DRIVER_INTERNAL_ERROR
;
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
),
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
);
3265 if(firstPos
>= Cache
->WriteCount
) firstPos
=0;
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
);
3276 if((i
= Cache
->BlockCount
- Cache
->WriteCount
) > MaxReloc
) i
= MaxReloc
;
3279 Lba
= List
[firstPos
];
3280 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3281 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3282 block_array
= Cache
->FrameList
[frame
].Frame
;
3284 if( (mod
= WCacheGetModFlag(block_array
, Lba
- firstLba
)) &&
3285 (Cache
->CheckUsedProc(Context
, Lba
) & WCACHE_BLOCK_USED
) )
3287 WCacheRemoveItemFromList(List
, &(Cache
->BlockCount
), Lba
);
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
);
3296 if(firstPos
>= Cache
->WriteCount
) firstPos
=0;
3300 return STATUS_SUCCESS
;
3301 } // end WCacheCheckLimitsR()
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.
3312 IN PW_CACHE Cache
, // pointer to the Cache Control structure
3313 IN PVOID Context
) // user-supplied context for IO callbacks
3317 lba_t
* List
= Cache
->CachedBlocksList
;
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
;
3328 ULONG MaxReloc
= Cache
->PacketSize
;
3329 PULONG reloc_tab
= Cache
->reloc_tab
;
3330 ULONG RelocCount
= 0;
3331 BOOLEAN IncompletePacket
;
3335 while(Cache
->WriteCount
< Cache
->BlockCount
) {
3338 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3339 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3340 block_array
= Cache
->FrameList
[frame
].Frame
;
3345 // check if modified
3346 mod
= WCacheGetModFlag(block_array
, Lba
- firstLba
);
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
);
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
);
3368 PacketTail
= Cache
->WriteCount
& (MaxReloc
-1);
3369 IncompletePacket
= (Cache
->WriteCount
>= MaxReloc
) ? FALSE
: TRUE
;
3371 // remove(flush) packet
3372 while((Cache
->WriteCount
> PacketTail
) || (Cache
->WriteCount
&& IncompletePacket
)) {
3375 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3376 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3377 block_array
= Cache
->FrameList
[frame
].Frame
;
3382 // check if modified
3383 mod
= WCacheGetModFlag(block_array
, Lba
- firstLba
);
3386 DbgCopyMemory(tmp_buff
+ (RelocCount
<< BSh
),
3387 (PVOID
)WCacheSectorAddr(block_array
, Lba
-firstLba
),
3389 reloc_tab
[RelocCount
] = Lba
;
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
);
3401 WCacheRemoveItemFromList(Cache
->CachedModifiedBlocksList
, &(Cache
->WriteCount
), Lba
);
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
);
3418 } // end WCachePurgeAllR()
3421 WCacheSetMode__() changes cache operating mode (ROM/R/RW/RAM).
3426 IN PW_CACHE Cache
, // pointer to the Cache Control structure
3427 IN ULONG Mode
// cache mode/media type to be used
3430 if(Mode
> WCACHE_MODE_MAX
) return STATUS_INVALID_PARAMETER
;
3432 return STATUS_SUCCESS
;
3433 } // end WCacheSetMode__()
3436 WCacheGetMode__() returns cache operating mode (ROM/R/RW/RAM).
3445 } // end WCacheGetMode__()
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.
3454 WCacheGetWriteBlockCount__(
3458 return Cache
->WriteCount
;
3459 } // end WCacheGetWriteBlockCount__()
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
3475 lba_t
* List
= Cache
->CachedBlocksList
;
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
;
3483 ULONG MaxReloc
= Cache
->PacketSize
;
3484 PULONG reloc_tab
= Cache
->reloc_tab
;
3485 ULONG RelocCount
= 0;
3486 BOOLEAN IncompletePacket
;
3488 IncompletePacket
= (Cache
->WriteCount
>= MaxReloc
) ? FALSE
: TRUE
;
3489 // enumerate modified blocks
3490 for(ULONG i
=0; IncompletePacket
&& (i
<Cache
->BlockCount
); i
++) {
3493 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3494 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3495 block_array
= Cache
->FrameList
[frame
].Frame
;
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
;
3505 if(RelocCount
>= Cache
->WriteCount
) {
3506 Cache
->UpdateRelocProc(Context
, NULL
, reloc_tab
, RelocCount
);
3511 } // end WCacheSyncReloc__()
3514 WCacheDiscardBlocks__() removes specified blocks from cache.
3515 Blocks are not flushed to media.
3519 WCacheDiscardBlocks__(
3530 PW_CACHE_ENTRY block_array
;
3534 ExAcquireResourceExclusiveLite(&(Cache
->WCacheLock
), TRUE
);
3536 UDFPrint((" Discard req: %x@%x\n",BCount
, ReqLba
));
3538 List
= Cache
->CachedBlocksList
;
3540 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
3543 i
= WCacheGetSortedListIndex(Cache
->BlockCount
, List
, ReqLba
);
3545 // enumerate requested blocks
3546 while((List
[i
] < (ReqLba
+BCount
)) && (i
< Cache
->BlockCount
)) {
3549 frame
= Lba
>> Cache
->BlocksPerFrameSh
;
3550 firstLba
= frame
<< Cache
->BlocksPerFrameSh
;
3551 block_array
= Cache
->FrameList
[frame
].Frame
;
3553 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
3557 // check if modified
3558 mod
= WCacheGetModFlag(block_array
, Lba
- firstLba
);
3561 // mark as non-cached & free pool
3562 if(WCacheSectorAddr(block_array
,Lba
-firstLba
)) {
3563 WCacheRemoveItemFromList(List
, &(Cache
->BlockCount
), Lba
);
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
);
3572 ASSERT(Cache
->FrameList
[frame
].Frame
);
3575 // we should never get here !!!
3576 // getting this part of code means that we have
3577 // placed non-cached block in CachedBlocksList
3581 ExReleaseResourceForThreadLite(&(Cache
->WCacheLock
), ExGetCurrentResourceThread());
3582 } // end WCacheDiscardBlocks__()
3585 WCacheCompleteAsync__(
3590 PW_CACHE_ASYNC AsyncCtx
= (PW_CACHE_ASYNC
)WContext
;
3591 // PW_CACHE Cache = AsyncCtx->Cache;
3593 AsyncCtx
->PhContext
.IosbToUse
.Status
= Status
;
3594 KeSetEvent(&(AsyncCtx
->PhContext
.event
), 0, FALSE
);
3596 return STATUS_SUCCESS
;
3597 } // end WCacheSetMode__()
3600 WCacheDecodeFlags() updates internal BOOLEANs according to Flags
3606 IN PW_CACHE Cache
, // pointer to the Cache Control structure
3607 IN ULONG Flags
// cache mode flags
3611 if(Flags
& ~WCACHE_VALID_FLAGS
) {
3612 UDFPrint(("Invalid flags: %x\n", Flags
& ~WCACHE_VALID_FLAGS
));
3613 return STATUS_INVALID_PARAMETER
;
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
;
3622 Cache
->NoWriteThrough
= (Flags
& WCACHE_NO_WRITE_THROUGH
) ? TRUE
: FALSE
;
3624 Cache
->Flags
= Flags
;
3626 return STATUS_SUCCESS
;
3630 WCacheChFlags__() changes cache flags.
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
3642 if(SetFlags
|| ClrFlags
) {
3643 Flags
= (Cache
->Flags
& ~ClrFlags
) | SetFlags
;
3645 if(!OS_SUCCESS(WCacheDecodeFlags(Cache
, Flags
))) {
3649 return Cache
->Flags
;
3652 } // end WCacheSetMode__()