CS350 COS
COS
Loading...
Searching...
No Matches
bufcache.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006-2022 Ali Mashtizadeh
3 * All rights reserved.
4 */
5
6#include <stdbool.h>
7#include <stdint.h>
8#include <string.h>
9
10#include <sys/kassert.h>
11#include <sys/kdebug.h>
12#include <sys/kmem.h>
13#include <sys/spinlock.h>
14#include <sys/disk.h>
15#include <sys/bufcache.h>
16#include <errno.h>
17
20
21static TAILQ_HEAD(CacheHashTable, BufCacheEntry) *hashTable;
22static TAILQ_HEAD(LRUCacheList, BufCacheEntry) lruList;
23static uint64_t cacheHit;
24static uint64_t cacheMiss;
25static uint64_t cacheAlloc;
26static Slab cacheEntrySlab;
27
28DEFINE_SLAB(BufCacheEntry, &cacheEntrySlab);
29
30#define CACHESIZE (16*1024*1024)
31#define HASHTABLEENTRIES 128
32#define BLOCKSIZE (16*1024)
33
39void
41{
42 int i;
43
45
46 diskBuf = XMem_New();
47 if (!diskBuf)
48 Panic("BufCache: Cannot create XMem region\n");
49
51 Panic("BufCache: Cannot back XMem region\n");
52
53 TAILQ_INIT(&lruList);
54
55 hashTable = PAlloc_AllocPage();
56 if (!hashTable)
57 Panic("BufCache: Cannot allocate hash table\n");
58 for (i = 0; i < HASHTABLEENTRIES; i++) {
59 TAILQ_INIT(&hashTable[i]);
60 }
61
62 Slab_Init(&cacheEntrySlab, "BufCacheEntry Slab", sizeof(BufCacheEntry), 16);
63
64 // Initialize cache
66 for (i = 0; i < CACHESIZE/BLOCKSIZE; i++) {
67 BufCacheEntry *e = BufCacheEntry_Alloc();
68 if (!e) {
69 Panic("BufCache: Cannot allocate cache entry\n");
70 }
71
72 memset(e, 0, sizeof(*e));
73 e->disk = NULL;
74 e->buffer = (void *)(bufBase + BLOCKSIZE * i);
75 TAILQ_INSERT_TAIL(&lruList, e, lruEntry);
76 }
77
78 cacheHit = 0;
79 cacheMiss = 0;
80 cacheAlloc = 0;
81}
82
96static int
98{
99 struct CacheHashTable *table;
100 BufCacheEntry *e;
101
102 // Check hash table
103 table = &hashTable[diskOffset % HASHTABLEENTRIES];
104 TAILQ_FOREACH(e, table, htEntry) {
105 if (e->disk == disk && e->diskOffset == diskOffset) {
106 e->refCount++;
107 if (e->refCount == 1) {
108 TAILQ_REMOVE(&lruList, e, lruEntry);
109 }
110 *entry = e;
111 return 0;
112 }
113 }
114
115 *entry = NULL;
116 return ENOENT;
117}
118
132static int
134{
135 struct CacheHashTable *table;
136 BufCacheEntry *e;
137
138 // Allocate from LRU list
139 e = TAILQ_FIRST(&lruList);
140 if (e == NULL) {
141 kprintf("BufCache: No space left!\n");
142 return ENOMEM;
143 }
144 TAILQ_REMOVE(&lruList, e, lruEntry);
145
146 // Remove from hash table
147 if (e->disk != NULL) {
148 table = &hashTable[e->diskOffset % HASHTABLEENTRIES];
149 TAILQ_REMOVE(table, e, htEntry);
150 }
151
152 // Initialize
153 e->disk = disk;
155 e->refCount = 1;
156
157 // Reinsert into hash table
158 table = &hashTable[diskOffset % HASHTABLEENTRIES];
159 TAILQ_INSERT_HEAD(table, e, htEntry);
160 *entry = e;
161
162 return 0;
163}
164
177int
179{
180 int status;
181
183
184 status = BufCacheLookup(disk, diskOffset, entry);
185 if (*entry == NULL) {
186 status = BufCacheAlloc(disk, diskOffset, entry);
187 }
188
189 cacheAlloc++;
190
192
193 return status;
194}
195
204void
206{
208
209 entry->refCount--;
210 if (entry->refCount == 0) {
211 TAILQ_INSERT_TAIL(&lruList, entry, lruEntry);
212 }
213
215}
216
228int
230{
231 int status;
232 void *buf;
233 SGArray sga;
234
236 status = BufCacheLookup(disk, diskOffset, entry);
237 if (*entry != NULL) {
238 cacheHit++;
240 return status;
241 }
242 cacheMiss++;
243
244 status = BufCacheAlloc(disk, diskOffset, entry);
245 if (status != 0) {
247 return status;
248 }
249
250 buf = (*entry)->buffer;
251 SGArray_Init(&sga);
253
254 /*
255 * XXX: Need to avoid holding cacheLock while reading from the disk, but
256 * need ensure other cores doesn't issue a read to the same block.
257 */
258 status = Disk_Read(disk, buf, &sga, NULL, NULL);
260
261 return status;
262}
263
272int
274{
275 void *buf = entry->buffer;
276 SGArray sga;
277
278 SGArray_Init(&sga);
279 SGArray_Append(&sga, entry->diskOffset, BLOCKSIZE);
280
281 return Disk_Write(entry->disk, buf, &sga, NULL, NULL);
282}
283
284static void
285Debug_BufCache(int argc, const char *argv[])
286{
287 kprintf("Hits: %lld\n", cacheHit);
288 kprintf("Misses: %lld\n", cacheMiss);
289 kprintf("Allocations: %lld\n", cacheAlloc);
290}
291
292REGISTER_DBGCMD(diskcache, "Display disk cache statistics", Debug_BufCache);
293
static void Debug_BufCache(int argc, const char *argv[])
Definition: bufcache.c:285
int BufCache_Write(BufCacheEntry *entry)
Definition: bufcache.c:273
XMem * diskBuf
Definition: bufcache.c:19
Spinlock cacheLock
Definition: bufcache.c:18
#define HASHTABLEENTRIES
int BufCache_Read(Disk *disk, uint64_t diskOffset, BufCacheEntry **entry)
Definition: bufcache.c:229
static int BufCacheLookup(Disk *disk, uint64_t diskOffset, BufCacheEntry **entry)
Definition: bufcache.c:97
void BufCache_Release(BufCacheEntry *entry)
Definition: bufcache.c:205
#define CACHESIZE
static int BufCacheAlloc(Disk *disk, uint64_t diskOffset, BufCacheEntry **entry)
Definition: bufcache.c:133
int BufCache_Alloc(Disk *disk, uint64_t diskOffset, BufCacheEntry **entry)
Definition: bufcache.c:178
#define BLOCKSIZE
void BufCache_Init()
int Disk_Write(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
Definition: disk.c:50
int Disk_Read(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
Definition: disk.c:44
#define ENOENT
Definition: errno.h:15
#define ENOMEM
Definition: errno.h:14
static char buf[4096]
Definition: ethdump.c:10
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
void * PAlloc_AllocPage()
Definition: palloc.c:188
#define DEFINE_SLAB(_type, _pool)
Definition: kmem.h:69
void Slab_Init(Slab *slab, const char *name, uintptr_t objsz, uintptr_t align)
uint64_t diskOffset
Definition: newfs_o2fs.c:28
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:557
#define TAILQ_INIT(head)
Definition: queue.h:597
#define TAILQ_HEAD(name, type)
Definition: queue.h:491
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:641
#define TAILQ_FIRST(head)
Definition: queue.h:555
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:659
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:628
void SGArray_Init(SGArray *sga)
Definition: sga.c:12
int SGArray_Append(SGArray *sga, uint64_t off, uint64_t len)
Definition: sga.c:18
Definition: sga.h:14
void Spinlock_Unlock(Spinlock *lock) __UNLOCK_EX(*lock)
Definition: spinlock.c:109
#define SPINLOCK_TYPE_NORMAL
Definition: spinlock.h:12
void Spinlock_Lock(Spinlock *lock) __LOCK_EX(*lock)
Definition: spinlock.c:75
void Spinlock_Init(Spinlock *lock, const char *name, uint64_t type)
Definition: spinlock.c:43
#define NULL
Definition: stddef.h:6
void * memset(void *dst, int c, size_t len)
Definition: string.c:164
void * buffer
Definition: bufcache.h:11
Disk * disk
Definition: bufcache.h:8
uint64_t diskOffset
Definition: bufcache.h:9
uint64_t refCount
Definition: bufcache.h:10
Definition: disk.h:11
Definition: kmem.h:46
uint64_t uintptr_t
Definition: types.h:16
unsigned long uint64_t
Definition: types.h:13
void Panic(const char *str)
Definition: vgacons.c:164
XMem * XMem_New()
Definition: xmem.c:47
bool XMem_Allocate(XMem *xmem, uintptr_t length)
Definition: xmem.c:92
uintptr_t XMem_GetBase(XMem *xmem)
Definition: xmem.c:80
Definition: xmem.c:18