cache.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include <stdlib.h>
  2. #include "debug.h"
  3. #include "cache.h"
  4. #include "general.h"
  5. void MxfsCacheInit(MINIX_FS *FileSys)
  6. {
  7. InitializeListHead(&FileSys->Cache.MruList);
  8. FileSys->Cache.Count = 0;
  9. InitializeCriticalSection(&FileSys->Cache.Lock);
  10. }
  11. static int MxfsCacheFlushItem(MINIX_FS *FileSys, MX_CACHE_ITEM *Item)
  12. {
  13. unsigned Offset = FileSys->uOffset + Item->Index*MINIX_BLOCK_SIZE;
  14. int Result = ImgWrite(FileSys->pImg, Offset, MINIX_BLOCK_SIZE, Item->Data);
  15. Item->Dirty = FALSE;
  16. if(Result < 0)
  17. ERR("MxfsCacheFlushItem: ImgWrite failed %d\n", Result);
  18. return Result;
  19. }
  20. void MxfsCacheFlush(MINIX_FS *FileSys)
  21. {
  22. EnterCriticalSection(&FileSys->Cache.Lock);
  23. LIST_ENTRY *Entry = FileSys->Cache.MruList.Flink;
  24. while(Entry != &FileSys->Cache.MruList)
  25. {
  26. MX_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, MX_CACHE_ITEM, MruList);
  27. if(Item->Dirty)
  28. MxfsCacheFlushItem(FileSys, Item);
  29. Entry = Entry->Flink;
  30. }
  31. LeaveCriticalSection(&FileSys->Cache.Lock);
  32. }
  33. static void MxfsCacheDestroyLastItem(MINIX_FS *FileSys)
  34. {
  35. ASSERT(FileSys->Cache.Count > 0);
  36. LIST_ENTRY *Entry = RemoveTailList(&FileSys->Cache.MruList);
  37. MX_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, MX_CACHE_ITEM, MruList);
  38. --FileSys->Cache.Count;
  39. if(Item->Dirty)
  40. MxfsCacheFlushItem(FileSys, Item);
  41. MxfsFree(Item);
  42. }
  43. void MxfsCacheDestroy(MINIX_FS *FileSys)
  44. {
  45. while(!IsListEmpty(&FileSys->Cache.MruList))
  46. MxfsCacheDestroyLastItem(FileSys);
  47. }
  48. MX_CACHE_ITEM *MxfsCacheFind(MINIX_FS *FileSys, unsigned Block)
  49. {
  50. LIST_ENTRY *Entry = FileSys->Cache.MruList.Flink;
  51. while(Entry != &FileSys->Cache.MruList)
  52. {
  53. MX_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, MX_CACHE_ITEM, MruList);
  54. if(Item->Index == Block)
  55. return Item;
  56. Entry = Entry->Flink;
  57. }
  58. return NULL;
  59. }
  60. MX_CACHE_ITEM *MxfsCacheLoadBlock(MINIX_FS *FileSys, unsigned Block, BOOL Zero)
  61. {
  62. MX_CACHE_ITEM *Item = MxfsAlloc(sizeof(MX_CACHE_ITEM));
  63. if(!Item) return NULL;
  64. unsigned BlockOffset = Block * MINIX_BLOCK_SIZE;
  65. if(BlockOffset + MINIX_BLOCK_SIZE > FileSys->cbLen)
  66. {
  67. ERR("MxfsCacheLoadBlock: Invalid block %u\n", Block);
  68. return NULL;
  69. }
  70. Item->Index = Block;
  71. if(!Zero)
  72. {
  73. int Result = ImgRead(FileSys->pImg, FileSys->uOffset + BlockOffset, MINIX_BLOCK_SIZE, Item->Data);
  74. if(Result < 0)
  75. {
  76. MxfsFree(Item);
  77. ERR("MxfsCacheLoadBlock: ImgRead failed %d\n", Result);
  78. return NULL;
  79. }
  80. Item->Dirty = FALSE;
  81. } else {
  82. memset(Item->Data, 0, MINIX_BLOCK_SIZE);
  83. Item->Dirty = TRUE;
  84. }
  85. if(FileSys->Cache.Count == BLOCK_CACHE_SIZE)
  86. MxfsCacheDestroyLastItem(FileSys);
  87. InsertHeadList(&FileSys->Cache.MruList, &Item->MruList);
  88. ++FileSys->Cache.Count;
  89. return Item;
  90. }
  91. int MxfsCacheRead(MINIX_FS *FileSys, void *Buffer, unsigned Block, unsigned Offset, unsigned Length)
  92. {
  93. if(!(Offset < MINIX_BLOCK_SIZE && Offset + Length <= MINIX_BLOCK_SIZE))
  94. {
  95. WARN("MxfsCacheRead: wrong offset (%u) or len (%u)\n", Offset, Length);
  96. return -ERROR_INVALID_PARAMETER;
  97. }
  98. EnterCriticalSection(&FileSys->Cache.Lock);
  99. int Result = -ERROR_NOT_FOUND;
  100. MX_CACHE_ITEM *Item = MxfsCacheFind(FileSys, Block);
  101. if(Item)
  102. {
  103. // Push at front
  104. RemoveEntryList(&Item->MruList);
  105. InsertHeadList(&FileSys->Cache.MruList, &Item->MruList);
  106. } else
  107. Item = MxfsCacheLoadBlock(FileSys, Block, FALSE);
  108. if(Item)
  109. {
  110. memcpy(Buffer, Item->Data + Offset, Length);
  111. Result = 0;
  112. }
  113. LeaveCriticalSection(&FileSys->Cache.Lock);
  114. return Result;
  115. }
  116. int MxfsCacheWrite(MINIX_FS *FileSys, const void *Buffer, unsigned Block, unsigned Offset, unsigned Length)
  117. {
  118. if(!(Offset < MINIX_BLOCK_SIZE && Offset + Length <= MINIX_BLOCK_SIZE))
  119. {
  120. WARN("MxfsCacheWrite: wrong offset (%u) or len (%u)\n", Offset, Length);
  121. return -ERROR_INVALID_PARAMETER;
  122. }
  123. EnterCriticalSection(&FileSys->Cache.Lock);
  124. int Result = -ERROR_WRITE_FAULT;
  125. MX_CACHE_ITEM *Item = MxfsCacheFind(FileSys, Block);
  126. if(!Item)
  127. Item = MxfsCacheLoadBlock(FileSys, Block, FALSE);
  128. if(Item)
  129. {
  130. memcpy(Item->Data + Offset, Buffer, Length);
  131. Item->Dirty = TRUE;
  132. Result = 0;
  133. }
  134. LeaveCriticalSection(&FileSys->Cache.Lock);
  135. return Result;
  136. }
  137. void MxfsCacheZero(MINIX_FS *FileSys, unsigned Block)
  138. {
  139. EnterCriticalSection(&FileSys->Cache.Lock);
  140. MX_CACHE_ITEM *Item = MxfsCacheFind(FileSys, Block);
  141. if(Item)
  142. {
  143. memset(Item->Data, 0, MINIX_BLOCK_SIZE);
  144. Item->Dirty = TRUE;
  145. }
  146. else
  147. MxfsCacheLoadBlock(FileSys, Block, TRUE);
  148. LeaveCriticalSection(&FileSys->Cache.Lock);
  149. }