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