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.
25 // Returns a pointer to a CACHE_BLOCK structure
26 // Adds the block to the cache manager block list
27 // in cache memory if it isn't already there
28 PCACHE_BLOCK
CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
30 PCACHE_BLOCK CacheBlock
= NULL
;
32 DbgPrint((DPRINT_CACHE
, "CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber
));
34 CacheBlock
= CacheInternalFindBlock(CacheDrive
, BlockNumber
);
36 if (CacheBlock
!= NULL
)
38 DbgPrint((DPRINT_CACHE
, "Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber
, CacheBlock
->BlockNumber
));
43 DbgPrint((DPRINT_CACHE
, "Cache miss! BlockNumber: %d\n", BlockNumber
));
45 CacheBlock
= CacheInternalAddBlockToCache(CacheDrive
, BlockNumber
);
47 // Optimize the block list so it has a LRU structure
48 CacheInternalOptimizeBlockList(CacheDrive
, CacheBlock
);
53 PCACHE_BLOCK
CacheInternalFindBlock(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
55 PCACHE_BLOCK CacheBlock
= NULL
;
57 DbgPrint((DPRINT_CACHE
, "CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber
));
60 // Make sure the block list has entries before I start searching it.
62 if (!RtlListIsEmpty((PLIST_ITEM
)CacheDrive
->CacheBlockHead
))
65 // Search the list and find the BIOS drive number
67 CacheBlock
= CacheDrive
->CacheBlockHead
;
69 while (CacheBlock
!= NULL
)
72 // We found the block, so return it
74 if (CacheBlock
->BlockNumber
== BlockNumber
)
77 // Increment the blocks access count
79 CacheBlock
->AccessCount
++;
84 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
91 PCACHE_BLOCK
CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
93 PCACHE_BLOCK CacheBlock
= NULL
;
95 DbgPrint((DPRINT_CACHE
, "CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber
));
97 // Check the size of the cache so we don't exceed our limits
98 CacheInternalCheckCacheSizeLimits(CacheDrive
);
100 // We will need to add the block to the
101 // drive's list of cached blocks. So allocate
103 CacheBlock
= MmAllocateMemory(sizeof(CACHE_BLOCK
));
104 if (CacheBlock
== NULL
)
109 // Now initialize the structure and
110 // allocate room for the block data
111 RtlZeroMemory(CacheBlock
, sizeof(CACHE_BLOCK
));
112 CacheBlock
->BlockNumber
= BlockNumber
;
113 CacheBlock
->BlockData
= MmAllocateMemory(CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
114 if (CacheBlock
->BlockData
==NULL
)
116 MmFreeMemory(CacheBlock
);
120 // Now try to read in the block
121 if (!MachDiskReadLogicalSectors(CacheDrive
->DriveNumber
, (BlockNumber
* CacheDrive
->BlockSize
), CacheDrive
->BlockSize
, (PVOID
)DISKREADBUFFER
))
123 MmFreeMemory(CacheBlock
->BlockData
);
124 MmFreeMemory(CacheBlock
);
127 RtlCopyMemory(CacheBlock
->BlockData
, (PVOID
)DISKREADBUFFER
, CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
129 // Add it to our list of blocks managed by the cache
130 if (CacheDrive
->CacheBlockHead
== NULL
)
132 CacheDrive
->CacheBlockHead
= CacheBlock
;
136 RtlListInsertTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
139 // Update the cache data
141 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
143 CacheInternalDumpBlockList(CacheDrive
);
148 BOOL
CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive
)
150 PCACHE_BLOCK CacheBlockToFree
;
152 DbgPrint((DPRINT_CACHE
, "CacheInternalFreeBlock()\n"));
154 // Get a pointer to the last item in the block list
155 // that isn't forced to be in the cache and remove
157 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
);
158 while (CacheBlockToFree
!= NULL
&& CacheBlockToFree
->LockedInCache
== TRUE
)
160 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetPrevious((PLIST_ITEM
)CacheBlockToFree
);
163 // No blocks left in cache that can be freed
165 if (CacheBlockToFree
== NULL
)
171 // If we are freeing the head of the list then update it's pointer
173 if (CacheBlockToFree
== CacheDrive
->CacheBlockHead
)
175 CacheDrive
->CacheBlockHead
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlockToFree
);
178 RtlListRemoveEntry((PLIST_ITEM
)CacheBlockToFree
);
180 // Free the block memory and the block structure
181 MmFreeMemory(CacheBlockToFree
->BlockData
);
182 MmFreeMemory(CacheBlockToFree
);
184 // Update the cache data
186 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
191 VOID
CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive
)
195 DbgPrint((DPRINT_CACHE
, "CacheInternalCheckCacheSizeLimits()\n"));
197 // Calculate the size of the cache if we added a block
198 NewCacheSize
= (CacheBlockCount
+ 1) * (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
200 // Check the new size against the cache size limit
201 if (NewCacheSize
> CacheSizeLimit
)
203 CacheInternalFreeBlock(CacheDrive
);
204 CacheInternalDumpBlockList(CacheDrive
);
208 VOID
CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive
)
210 PCACHE_BLOCK CacheBlock
;
212 DbgPrint((DPRINT_CACHE
, "Dumping block list for BIOS drive 0x%x.\n", CacheDrive
->DriveNumber
));
213 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheDrive
->BytesPerSector
));
214 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheDrive
->BlockSize
));
215 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
216 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d.\n", CacheSizeCurrent
));
217 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d.\n", CacheBlockCount
));
218 DbgPrint((DPRINT_CACHE
, "Dumping %d cache blocks.\n", RtlListCountEntries((PLIST_ITEM
)CacheDrive
->CacheBlockHead
)));
220 CacheBlock
= CacheDrive
->CacheBlockHead
;
221 while (CacheBlock
!= NULL
)
223 DbgPrint((DPRINT_CACHE
, "Cache Block: CacheBlock: 0x%x\n", CacheBlock
));
224 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Number: %d\n", CacheBlock
->BlockNumber
));
225 DbgPrint((DPRINT_CACHE
, "Cache Block: Access Count: %d\n", CacheBlock
->AccessCount
));
226 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Data: 0x%x\n", CacheBlock
->BlockData
));
227 DbgPrint((DPRINT_CACHE
, "Cache Block: Locked In Cache: %d\n", CacheBlock
->LockedInCache
));
229 if (CacheBlock
->BlockData
== NULL
)
231 BugCheck((DPRINT_CACHE
, "What the heck?!?\n"));
234 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
238 VOID
CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive
, PCACHE_BLOCK CacheBlock
)
241 DbgPrint((DPRINT_CACHE
, "CacheInternalOptimizeBlockList()\n"));
243 // Don't do this if this block is already at the head of the list
244 if (CacheBlock
!= CacheDrive
->CacheBlockHead
)
246 // Remove this item from the block list
247 RtlListRemoveEntry((PLIST_ITEM
)CacheBlock
);
249 // Re-insert it at the head of the list
250 RtlListInsertHead((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
252 // Update the head pointer
253 CacheDrive
->CacheBlockHead
= CacheBlock
;