Implement disk cache and improve other related parts of the kernel.

This commit is contained in:
Ali Mashtizadeh 2014-07-30 17:19:24 -07:00
parent e42e159f13
commit e901bdc7ce
8 changed files with 262 additions and 2 deletions

View File

@ -36,10 +36,12 @@ src_amd64 = [
src_common = [
"kern/debug.c",
"kern/disk.c",
"kern/diskcache.c",
"kern/libc.c",
"kern/loader.c",
"kern/palloc.c",
"kern/printf.c",
"kern/sga.c",
"kern/spinlock.c",
"kern/syscall.c",
"kern/thread.c",

View File

@ -15,6 +15,8 @@
#include <machine/pmap.h>
#include <sys/thread.h>
#include <sys/disk.h>
#include <sys/diskcache.h>
#include <sys/elf64.h>
#include "../dev/console.h"
@ -136,6 +138,7 @@ void Machine_Init()
PCI_Init();
IDE_Init();
DiskCache_Init();
Critical_Exit();

View File

@ -105,7 +105,7 @@ XMem_Allocate(XMem *xmem, uintptr_t length)
if (pg == NULL)
return false;
// PMap
PMap_SystemMap(DMVA2PA((uint64_t)pg), xmem->base + off, 1, 0);
}
return true;

23
sys/include/diskcache.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __SYS_DISKCACHE_H__
#define __SYS_DISKCACHE_H__
#include <sys/queue.h>
typedef struct DiskCacheEntry {
Disk *disk;
uint64_t diskOffset;
uint64_t refCount;
void *buffer;
TAILQ_ENTRY(DiskCacheEntry) htEntry;
TAILQ_ENTRY(DiskCacheEntry) lruEntry;
} DiskCacheEntry;
void DiskCache_Init();
int DiskCache_Alloc(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry);
void DiskCache_Release(DiskCacheEntry *entry);
int DiskCache_Read(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry);
int DiskCache_Write(DiskCacheEntry *entry);
#endif /* __SYS_DISKCACHE_H__ */

View File

@ -16,5 +16,9 @@ typedef struct SGArray
SGEntry entries[SGARRAY_MAX_ENTRIES];
} SGArray;
void SGArray_Init(SGArray *sga);
int SGArray_Append(SGArray *sga, uint64_t off, uint64_t len);
void SGArray_Dump(SGArray *sga);
#endif /* __SGA_H__ */

View File

@ -9,7 +9,7 @@
#include <sys/disk.h>
#include <sys/spinlock.h>
LIST_HEAD(DiskList, Disk) diskList;
LIST_HEAD(DiskList, Disk) diskList = LIST_HEAD_INITIALIZER(diskList);
void
Disk_AddDisk(Disk *disk)

190
sys/kern/diskcache.c Normal file
View File

@ -0,0 +1,190 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/spinlock.h>
#include <sys/disk.h>
#include <sys/diskcache.h>
Spinlock cacheLock;
XMem *diskBuf;
static TAILQ_HEAD(CacheHashTable, DiskCacheEntry) *hashTable;
static TAILQ_HEAD(LRUCacheList, DiskCacheEntry) lruList;
#define CACHESIZE (16*1024*1024)
#define HASHTABLEENTRIES 128
#define BLOCKSIZE (16*1024)
void
DiskCache_Init()
{
int i;
Spinlock_Init(&cacheLock, "DiskCache Lock");
diskBuf = XMem_New();
if (!diskBuf)
Panic("DiskCache: Cannot create XMem region");
if (!XMem_Allocate(diskBuf, CACHESIZE))
Panic("DiskCache: Cannot back XMem region");
TAILQ_INIT(&lruList);
hashTable = PAlloc_AllocPage();
if (!hashTable)
Panic("DiskCache: Cannot allocate hash table");
for (i = 0; i < HASHTABLEENTRIES; i++) {
TAILQ_INIT(&hashTable[i]);
}
// Initialize cache
uintptr_t bufBase = XMem_GetBase(diskBuf);
for (i = 0; i < CACHESIZE/BLOCKSIZE; i++) {
DiskCacheEntry *e = PAlloc_AllocPage();
if (!e)
Panic("DiskCache: Cannot allocate cache entry");
memset(e, 0, sizeof(*e));
e->disk = NULL;
e->buffer = (void *)(bufBase + BLOCKSIZE * i);
TAILQ_INSERT_TAIL(&lruList, e, lruEntry);
}
}
int
DiskCacheLookup(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry)
{
struct CacheHashTable *table;
DiskCacheEntry *e;
// Check hash table
table = &hashTable[diskOffset % HASHTABLEENTRIES];
TAILQ_FOREACH(e, table, htEntry) {
if (e->disk == disk && e->diskOffset == diskOffset) {
e->refCount++;
if (e->refCount == 1) {
TAILQ_REMOVE(&lruList, e, lruEntry);
}
*entry = e;
return 0;
}
}
*entry = NULL;
return 0;
}
int
DiskCacheAlloc(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry)
{
struct CacheHashTable *table;
DiskCacheEntry *e;
// Allocate from LRU list
e = TAILQ_FIRST(&lruList);
if (e == NULL) {
kprintf("DiskCache: No space left!\n");
return -1;
}
TAILQ_REMOVE(&lruList, e, lruEntry);
// Remove from hash table
if (e->disk != NULL) {
table = &hashTable[e->diskOffset % HASHTABLEENTRIES];
TAILQ_REMOVE(table, e, htEntry);
}
// Initialize
e->disk = disk;
e->diskOffset = diskOffset;
e->refCount = 1;
// Reinsert into hash table
table = &hashTable[diskOffset % HASHTABLEENTRIES];
TAILQ_INSERT_HEAD(table, e, htEntry);
*entry = e;
return 0;
}
int
DiskCache_Alloc(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry)
{
int status;
Spinlock_Lock(&cacheLock);
status = DiskCacheLookup(disk, diskOffset, entry);
if (*entry == NULL) {
status = DiskCacheAlloc(disk, diskOffset, entry);
}
Spinlock_Unlock(&cacheLock);
return status;
}
void
DiskCache_Release(DiskCacheEntry *entry)
{
Spinlock_Lock(&cacheLock);
entry->refCount--;
if (entry->refCount == 0) {
TAILQ_INSERT_TAIL(&lruList, entry, lruEntry);
}
Spinlock_Unlock(&cacheLock);
}
int
DiskCache_Read(Disk *disk, uint64_t diskOffset, DiskCacheEntry **entry)
{
int status;
void *buf;
SGArray sga;
Spinlock_Lock(&cacheLock);
status = DiskCacheLookup(disk, diskOffset, entry);
if (*entry != NULL) {
Spinlock_Unlock(&cacheLock);
return status;
}
status = DiskCacheAlloc(disk, diskOffset, entry);
if (status != 0) {
Spinlock_Unlock(&cacheLock);
return status;
}
buf = (*entry)->buffer;
SGArray_Init(&sga);
SGArray_Append(&sga, diskOffset, BLOCKSIZE);
/*
* XXX: Need to avoid holding cacheLock while reading from the disk, but
* need ensure other cores doesn't issue a read to the same block.
*/
status = Disk_Read(disk, buf, &sga, NULL, NULL);
Spinlock_Unlock(&cacheLock);
return status;
}
int
DiskCache_Write(DiskCacheEntry *entry)
{
void *buf = entry->buffer;
SGArray sga;
SGArray_Init(&sga);
SGArray_Append(&sga, entry->diskOffset, BLOCKSIZE);
return Disk_Write(entry->disk, buf, &sga, NULL, NULL);
}

38
sys/kern/sga.c Normal file
View File

@ -0,0 +1,38 @@
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/sga.h>
void
SGArray_Init(SGArray *sga)
{
sga->len = 0;
}
int
SGArray_Append(SGArray *sga, uint64_t off, uint64_t len)
{
ASSERT(sga->len < SGARRAY_MAX_ENTRIES)
sga->entries[sga->len].offset = off;
sga->entries[sga->len].length = len;
sga->len++;
return sga->len;
}
void
SGArray_Dump(SGArray *sga)
{
int i;
kprintf("--- SGArray Begin ---\n");
for (i = 0; i < sga->len; i++)
{
kprintf("%d: %016llx %016llx\n", i, sga->entries[i].offset,
sga->entries[i].length);
}
kprintf("--- SGArray End ---\n");
}