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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 DBG_DEFAULT_CHANNEL(CACHE
);
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 TRACE("CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber
);
34 CacheBlock
= CacheInternalFindBlock(CacheDrive
, BlockNumber
);
36 if (CacheBlock
!= NULL
)
38 TRACE("Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber
, CacheBlock
->BlockNumber
);
43 TRACE("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 TRACE("CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber
);
60 // Make sure the block list has entries before I start searching it.
62 if (!IsListEmpty(&CacheDrive
->CacheBlockHead
))
65 // Search the list and find the BIOS drive number
67 CacheBlock
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Flink
, CACHE_BLOCK
, ListEntry
);
69 while (&CacheBlock
->ListEntry
!= &CacheDrive
->CacheBlockHead
)
72 // We found the block, so return it
74 if (CacheBlock
->BlockNumber
== BlockNumber
)
77 // Increment the blocks access count
79 CacheBlock
->AccessCount
++;
84 CacheBlock
= CONTAINING_RECORD(CacheBlock
->ListEntry
.Flink
, CACHE_BLOCK
, ListEntry
);
91 PCACHE_BLOCK
CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
93 PCACHE_BLOCK CacheBlock
= NULL
;
95 TRACE("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
= MmHeapAlloc(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
= MmHeapAlloc(CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
114 if (CacheBlock
->BlockData
==NULL
)
116 MmHeapFree(CacheBlock
);
120 // Now try to read in the block
121 if (!MachDiskReadLogicalSectors(CacheDrive
->DriveNumber
, (BlockNumber
* CacheDrive
->BlockSize
), CacheDrive
->BlockSize
, (PVOID
)DISKREADBUFFER
))
123 MmHeapFree(CacheBlock
->BlockData
);
124 MmHeapFree(CacheBlock
);
127 RtlCopyMemory(CacheBlock
->BlockData
, (PVOID
)DISKREADBUFFER
, CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
129 // Add it to our list of blocks managed by the cache
130 InsertTailList(&CacheDrive
->CacheBlockHead
, &CacheBlock
->ListEntry
);
132 // Update the cache data
134 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
136 CacheInternalDumpBlockList(CacheDrive
);
141 BOOLEAN
CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive
)
143 PCACHE_BLOCK CacheBlockToFree
;
145 TRACE("CacheInternalFreeBlock()\n");
147 // Get a pointer to the last item in the block list
148 // that isn't forced to be in the cache and remove
150 CacheBlockToFree
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Blink
, CACHE_BLOCK
, ListEntry
);
151 while (&CacheBlockToFree
->ListEntry
!= &CacheDrive
->CacheBlockHead
&& CacheBlockToFree
->LockedInCache
== TRUE
)
153 CacheBlockToFree
= CONTAINING_RECORD(CacheBlockToFree
->ListEntry
.Blink
, CACHE_BLOCK
, ListEntry
);
156 // No blocks left in cache that can be freed
158 if (IsListEmpty(&CacheDrive
->CacheBlockHead
))
163 RemoveEntryList(&CacheBlockToFree
->ListEntry
);
165 // Free the block memory and the block structure
166 MmHeapFree(CacheBlockToFree
->BlockData
);
167 MmHeapFree(CacheBlockToFree
);
169 // Update the cache data
171 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
176 VOID
CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive
)
180 TRACE("CacheInternalCheckCacheSizeLimits()\n");
182 // Calculate the size of the cache if we added a block
183 NewCacheSize
= (CacheBlockCount
+ 1) * (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
185 // Check the new size against the cache size limit
186 if (NewCacheSize
> CacheSizeLimit
)
188 CacheInternalFreeBlock(CacheDrive
);
189 CacheInternalDumpBlockList(CacheDrive
);
193 VOID
CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive
)
195 PCACHE_BLOCK CacheBlock
;
197 TRACE("Dumping block list for BIOS drive 0x%x.\n", CacheDrive
->DriveNumber
);
198 TRACE("BytesPerSector: %d.\n", CacheDrive
->BytesPerSector
);
199 TRACE("BlockSize: %d.\n", CacheDrive
->BlockSize
);
200 TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit
);
201 TRACE("CacheSizeCurrent: %d.\n", CacheSizeCurrent
);
202 TRACE("CacheBlockCount: %d.\n", CacheBlockCount
);
204 CacheBlock
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Flink
, CACHE_BLOCK
, ListEntry
);
205 while (&CacheBlock
->ListEntry
!= &CacheDrive
->CacheBlockHead
)
207 TRACE("Cache Block: CacheBlock: 0x%x\n", CacheBlock
);
208 TRACE("Cache Block: Block Number: %d\n", CacheBlock
->BlockNumber
);
209 TRACE("Cache Block: Access Count: %d\n", CacheBlock
->AccessCount
);
210 TRACE("Cache Block: Block Data: 0x%x\n", CacheBlock
->BlockData
);
211 TRACE("Cache Block: Locked In Cache: %d\n", CacheBlock
->LockedInCache
);
213 if (CacheBlock
->BlockData
== NULL
)
215 BugCheck("CacheBlock->BlockData == NULL\n");
218 CacheBlock
= CONTAINING_RECORD(CacheBlock
->ListEntry
.Flink
, CACHE_BLOCK
, ListEntry
);
222 VOID
CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive
, PCACHE_BLOCK CacheBlock
)
225 TRACE("CacheInternalOptimizeBlockList()\n");
227 // Don't do this if this block is already at the head of the list
228 if (&CacheBlock
->ListEntry
!= CacheDrive
->CacheBlockHead
.Flink
)
230 // Remove this item from the block list
231 RemoveEntryList(&CacheBlock
->ListEntry
);
233 // Re-insert it at the head of the list
234 InsertHeadList(&CacheDrive
->CacheBlockHead
, &CacheBlock
->ListEntry
);