Implement disk cache and improve other related parts of the kernel.
This commit is contained in:
parent
e42e159f13
commit
e901bdc7ce
@ -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",
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
23
sys/include/diskcache.h
Normal 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__ */
|
||||
|
@ -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__ */
|
||||
|
||||
|
@ -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
190
sys/kern/diskcache.c
Normal 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
38
sys/kern/sga.c
Normal 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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user