3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 // Returns a pointer to a CACHE_BLOCK structure
31 // Adds the block to the cache manager block list
32 // in cache memory if it isn't already there
33 PCACHE_BLOCK
CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
35 PCACHE_BLOCK CacheBlock
= NULL
;
37 DbgPrint((DPRINT_CACHE
, "CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber
));
39 CacheBlock
= CacheInternalFindBlock(CacheDrive
, BlockNumber
);
41 if (CacheBlock
!= NULL
)
43 DbgPrint((DPRINT_CACHE
, "Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber
, CacheBlock
->BlockNumber
));
48 DbgPrint((DPRINT_CACHE
, "Cache miss! BlockNumber: %d\n", BlockNumber
));
50 CacheBlock
= CacheInternalAddBlockToCache(CacheDrive
, BlockNumber
);
52 // Optimize the block list so it has a LRU structure
53 CacheInternalOptimizeBlockList(CacheDrive
, CacheBlock
);
58 PCACHE_BLOCK
CacheInternalFindBlock(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
60 PCACHE_BLOCK CacheBlock
= NULL
;
62 DbgPrint((DPRINT_CACHE
, "CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber
));
65 // Make sure the block list has entries before I start searching it.
67 if (!RtlListIsEmpty((PLIST_ITEM
)CacheDrive
->CacheBlockHead
))
70 // Search the list and find the BIOS drive number
72 CacheBlock
= CacheDrive
->CacheBlockHead
;
74 while (CacheBlock
!= NULL
)
77 // We found the block, so return it
79 if (CacheBlock
->BlockNumber
== BlockNumber
)
82 // Increment the blocks access count
84 CacheBlock
->AccessCount
++;
89 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
96 PCACHE_BLOCK
CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
98 PCACHE_BLOCK CacheBlock
= NULL
;
100 DbgPrint((DPRINT_CACHE
, "CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber
));
102 // Check the size of the cache so we don't exceed our limits
103 CacheInternalCheckCacheSizeLimits(CacheDrive
);
105 // We will need to add the block to the
106 // drive's list of cached blocks. So allocate
108 CacheBlock
= MmAllocateMemory(sizeof(CACHE_BLOCK
));
109 if (CacheBlock
== NULL
)
114 // Now initialize the structure and
115 // allocate room for the block data
116 RtlZeroMemory(CacheBlock
, sizeof(CACHE_BLOCK
));
117 CacheBlock
->BlockNumber
= BlockNumber
;
118 CacheBlock
->BlockData
= MmAllocateMemory(CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
119 if (CacheBlock
->BlockData
==NULL
)
121 MmFreeMemory(CacheBlock
);
125 // Now try to read in the block
126 if (!MachDiskReadLogicalSectors(CacheDrive
->DriveNumber
, (BlockNumber
* CacheDrive
->BlockSize
), CacheDrive
->BlockSize
, (PVOID
)DISKREADBUFFER
))
128 MmFreeMemory(CacheBlock
->BlockData
);
129 MmFreeMemory(CacheBlock
);
132 RtlCopyMemory(CacheBlock
->BlockData
, (PVOID
)DISKREADBUFFER
, CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
134 // Add it to our list of blocks managed by the cache
135 if (CacheDrive
->CacheBlockHead
== NULL
)
137 CacheDrive
->CacheBlockHead
= CacheBlock
;
141 RtlListInsertTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
144 // Update the cache data
146 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
148 CacheInternalDumpBlockList(CacheDrive
);
153 BOOL
CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive
)
155 PCACHE_BLOCK CacheBlockToFree
;
157 DbgPrint((DPRINT_CACHE
, "CacheInternalFreeBlock()\n"));
159 // Get a pointer to the last item in the block list
160 // that isn't forced to be in the cache and remove
162 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
);
163 while (CacheBlockToFree
!= NULL
&& CacheBlockToFree
->LockedInCache
== TRUE
)
165 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetPrevious((PLIST_ITEM
)CacheBlockToFree
);
168 // No blocks left in cache that can be freed
170 if (CacheBlockToFree
== NULL
)
176 // If we are freeing the head of the list then update it's pointer
178 if (CacheBlockToFree
== CacheDrive
->CacheBlockHead
)
180 CacheDrive
->CacheBlockHead
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlockToFree
);
183 RtlListRemoveEntry((PLIST_ITEM
)CacheBlockToFree
);
185 // Free the block memory and the block structure
186 MmFreeMemory(CacheBlockToFree
->BlockData
);
187 MmFreeMemory(CacheBlockToFree
);
189 // Update the cache data
191 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
196 VOID
CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive
)
200 DbgPrint((DPRINT_CACHE
, "CacheInternalCheckCacheSizeLimits()\n"));
202 // Calculate the size of the cache if we added a block
203 NewCacheSize
= (CacheBlockCount
+ 1) * (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
205 // Check the new size against the cache size limit
206 if (NewCacheSize
> CacheSizeLimit
)
208 CacheInternalFreeBlock(CacheDrive
);
209 CacheInternalDumpBlockList(CacheDrive
);
213 VOID
CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive
)
215 PCACHE_BLOCK CacheBlock
;
217 DbgPrint((DPRINT_CACHE
, "Dumping block list for BIOS drive 0x%x.\n", CacheDrive
->DriveNumber
));
218 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheDrive
->BytesPerSector
));
219 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheDrive
->BlockSize
));
220 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
221 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d.\n", CacheSizeCurrent
));
222 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d.\n", CacheBlockCount
));
223 DbgPrint((DPRINT_CACHE
, "Dumping %d cache blocks.\n", RtlListCountEntries((PLIST_ITEM
)CacheDrive
->CacheBlockHead
)));
225 CacheBlock
= CacheDrive
->CacheBlockHead
;
226 while (CacheBlock
!= NULL
)
228 DbgPrint((DPRINT_CACHE
, "Cache Block: CacheBlock: 0x%x\n", CacheBlock
));
229 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Number: %d\n", CacheBlock
->BlockNumber
));
230 DbgPrint((DPRINT_CACHE
, "Cache Block: Access Count: %d\n", CacheBlock
->AccessCount
));
231 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Data: 0x%x\n", CacheBlock
->BlockData
));
232 DbgPrint((DPRINT_CACHE
, "Cache Block: Locked In Cache: %d\n", CacheBlock
->LockedInCache
));
234 if (CacheBlock
->BlockData
== NULL
)
236 BugCheck((DPRINT_CACHE
, "What the heck?!?\n"));
239 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
243 VOID
CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive
, PCACHE_BLOCK CacheBlock
)
246 DbgPrint((DPRINT_CACHE
, "CacheInternalOptimizeBlockList()\n"));
248 // Don't do this if this block is already at the head of the list
249 if (CacheBlock
!= CacheDrive
->CacheBlockHead
)
251 // Remove this item from the block list
252 RtlListRemoveEntry((PLIST_ITEM
)CacheBlock
);
254 // Re-insert it at the head of the list
255 RtlListInsertHead((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
257 // Update the head pointer
258 CacheDrive
->CacheBlockHead
= CacheBlock
;