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