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.
29 // Returns a pointer to a CACHE_BLOCK structure
30 // Adds the block to the cache manager block list
31 // in cache memory if it isn't already there
32 PCACHE_BLOCK
CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive
, U32 BlockNumber
)
34 PCACHE_BLOCK CacheBlock
= NULL
;
36 DbgPrint((DPRINT_CACHE
, "CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber
));
38 CacheBlock
= CacheInternalFindBlock(CacheDrive
, BlockNumber
);
40 if (CacheBlock
!= NULL
)
42 DbgPrint((DPRINT_CACHE
, "Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber
, CacheBlock
->BlockNumber
));
47 DbgPrint((DPRINT_CACHE
, "Cache miss! BlockNumber: %d\n", BlockNumber
));
49 CacheBlock
= CacheInternalAddBlockToCache(CacheDrive
, BlockNumber
);
51 // Optimize the block list so it has a LRU structure
52 CacheInternalOptimizeBlockList(CacheDrive
, CacheBlock
);
57 PCACHE_BLOCK
CacheInternalFindBlock(PCACHE_DRIVE CacheDrive
, U32 BlockNumber
)
59 PCACHE_BLOCK CacheBlock
= NULL
;
61 DbgPrint((DPRINT_CACHE
, "CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber
));
64 // Make sure the block list has entries before I start searching it.
66 if (!RtlListIsEmpty((PLIST_ITEM
)CacheDrive
->CacheBlockHead
))
69 // Search the list and find the BIOS drive number
71 CacheBlock
= CacheDrive
->CacheBlockHead
;
73 while (CacheBlock
!= NULL
)
76 // We found the block, so return it
78 if (CacheBlock
->BlockNumber
== BlockNumber
)
81 // Increment the blocks access count
83 CacheBlock
->AccessCount
++;
88 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
95 PCACHE_BLOCK
CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive
, U32 BlockNumber
)
97 PCACHE_BLOCK CacheBlock
= NULL
;
99 DbgPrint((DPRINT_CACHE
, "CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber
));
101 // Check the size of the cache so we don't exceed our limits
102 CacheInternalCheckCacheSizeLimits(CacheDrive
);
104 // We will need to add the block to the
105 // drive's list of cached blocks. So allocate
107 CacheBlock
= MmAllocateMemory(sizeof(CACHE_BLOCK
));
108 if (CacheBlock
== NULL
)
113 // Now initialize the structure and
114 // allocate room for the block data
115 RtlZeroMemory(CacheBlock
, sizeof(CACHE_BLOCK
));
116 CacheBlock
->BlockNumber
= BlockNumber
;
117 CacheBlock
->BlockData
= MmAllocateMemory(CacheDrive
->BlockSize
* CacheDrive
->DriveGeometry
.BytesPerSector
);
118 if (CacheBlock
->BlockData
==NULL
)
120 MmFreeMemory(CacheBlock
);
124 // Now try to read in the block
125 if (!DiskReadLogicalSectors(CacheDrive
->DriveNumber
, (BlockNumber
* CacheDrive
->BlockSize
), CacheDrive
->BlockSize
, (PVOID
)DISKREADBUFFER
))
127 MmFreeMemory(CacheBlock
->BlockData
);
128 MmFreeMemory(CacheBlock
);
131 RtlCopyMemory(CacheBlock
->BlockData
, (PVOID
)DISKREADBUFFER
, CacheDrive
->BlockSize
* CacheDrive
->DriveGeometry
.BytesPerSector
);
133 // Add it to our list of blocks managed by the cache
134 if (CacheDrive
->CacheBlockHead
== NULL
)
136 CacheDrive
->CacheBlockHead
= CacheBlock
;
140 RtlListInsertTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
143 // Update the cache data
145 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->DriveGeometry
.BytesPerSector
);
147 CacheInternalDumpBlockList(CacheDrive
);
152 BOOL
CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive
)
154 PCACHE_BLOCK CacheBlockToFree
;
156 DbgPrint((DPRINT_CACHE
, "CacheInternalFreeBlock()\n"));
158 // Get a pointer to the last item in the block list
159 // that isn't forced to be in the cache and remove
161 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetTail((PLIST_ITEM
)CacheDrive
->CacheBlockHead
);
162 while (CacheBlockToFree
!= NULL
&& CacheBlockToFree
->LockedInCache
== TRUE
)
164 CacheBlockToFree
= (PCACHE_BLOCK
)RtlListGetPrevious((PLIST_ITEM
)CacheBlockToFree
);
167 // No blocks left in cache that can be freed
169 if (CacheBlockToFree
== NULL
)
175 // If we are freeing the head of the list then update it's pointer
177 if (CacheBlockToFree
== CacheDrive
->CacheBlockHead
)
179 CacheDrive
->CacheBlockHead
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlockToFree
);
182 RtlListRemoveEntry((PLIST_ITEM
)CacheBlockToFree
);
184 // Free the block memory and the block structure
185 MmFreeMemory(CacheBlockToFree
->BlockData
);
186 MmFreeMemory(CacheBlockToFree
);
188 // Update the cache data
190 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->DriveGeometry
.BytesPerSector
);
195 VOID
CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive
)
199 DbgPrint((DPRINT_CACHE
, "CacheInternalCheckCacheSizeLimits()\n"));
201 // Calculate the size of the cache if we added a block
202 NewCacheSize
= (CacheBlockCount
+ 1) * (CacheDrive
->BlockSize
* CacheDrive
->DriveGeometry
.BytesPerSector
);
204 // Check the new size against the cache size limit
205 if (NewCacheSize
> CacheSizeLimit
)
207 CacheInternalFreeBlock(CacheDrive
);
208 CacheInternalDumpBlockList(CacheDrive
);
212 VOID
CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive
)
214 PCACHE_BLOCK CacheBlock
;
216 DbgPrint((DPRINT_CACHE
, "Dumping block list for BIOS drive 0x%x.\n", CacheDrive
->DriveNumber
));
217 DbgPrint((DPRINT_CACHE
, "Cylinders: %d.\n", CacheDrive
->DriveGeometry
.Cylinders
));
218 DbgPrint((DPRINT_CACHE
, "Heads: %d.\n", CacheDrive
->DriveGeometry
.Heads
));
219 DbgPrint((DPRINT_CACHE
, "Sectors: %d.\n", CacheDrive
->DriveGeometry
.Sectors
));
220 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheDrive
->DriveGeometry
.BytesPerSector
));
221 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheDrive
->BlockSize
));
222 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
223 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d.\n", CacheSizeCurrent
));
224 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d.\n", CacheBlockCount
));
225 DbgPrint((DPRINT_CACHE
, "Dumping %d cache blocks.\n", RtlListCountEntries((PLIST_ITEM
)CacheDrive
->CacheBlockHead
)));
227 CacheBlock
= CacheDrive
->CacheBlockHead
;
228 while (CacheBlock
!= NULL
)
230 DbgPrint((DPRINT_CACHE
, "Cache Block: CacheBlock: 0x%x\n", CacheBlock
));
231 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Number: %d\n", CacheBlock
->BlockNumber
));
232 DbgPrint((DPRINT_CACHE
, "Cache Block: Access Count: %d\n", CacheBlock
->AccessCount
));
233 DbgPrint((DPRINT_CACHE
, "Cache Block: Block Data: 0x%x\n", CacheBlock
->BlockData
));
234 DbgPrint((DPRINT_CACHE
, "Cache Block: Locked In Cache: %d\n", CacheBlock
->LockedInCache
));
236 if (CacheBlock
->BlockData
== NULL
)
238 BugCheck((DPRINT_CACHE
, "What the heck?!?\n"));
241 CacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheBlock
);
245 VOID
CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive
, PCACHE_BLOCK CacheBlock
)
248 DbgPrint((DPRINT_CACHE
, "CacheInternalOptimizeBlockList()\n"));
250 // Don't do this if this block is already at the head of the list
251 if (CacheBlock
!= CacheDrive
->CacheBlockHead
)
253 // Remove this item from the block list
254 RtlListRemoveEntry((PLIST_ITEM
)CacheBlock
);
256 // Re-insert it at the head of the list
257 RtlListInsertHead((PLIST_ITEM
)CacheDrive
->CacheBlockHead
, (PLIST_ITEM
)CacheBlock
);
259 // Update the head pointer
260 CacheDrive
->CacheBlockHead
= CacheBlock
;