diff options
Diffstat (limited to 'kernel/fs/buffer.c')
| -rw-r--r-- | kernel/fs/buffer.c | 102 |
1 files changed, 61 insertions, 41 deletions
diff --git a/kernel/fs/buffer.c b/kernel/fs/buffer.c index 7405738..99c3161 100644 --- a/kernel/fs/buffer.c +++ b/kernel/fs/buffer.c @@ -1,16 +1,76 @@ +#include <asm/interrupt.h> +#include <errno.h> #include <kernel/con.h> #include <kernel/fs.h> #include <stdint.h> #include <string.h> /* memory dedicated to the block cache */ +/* TODO: start buffers at kernel end not 512K */ #define BSTART 0x80000 #define BEND 0xA0000 static struct buffer *lru; static struct buffer *mru; -struct buffer *buffer_get_block(uint16_t device, uint16_t block); +struct buffer *buffer_get_block(uint16_t device, uint16_t block) { + struct buffer **p = &mru; + struct buffer *b; + + if(!device) + return NULL; + + /* check if the requested block is already in the cache */ + while(b = *p) { + if(b->b_device != device || b->b_block != block) + goto next; + /* remove the buffer from the list */ + if(lru == b && b->b_next) lru = b->b_next; + if(b->b_next) b->b_next->b_prev = b->b_prev; + if(b->b_prev) b->b_prev->b_next = b->b_next; + /* put the buffer back at the MRU end of the list */ + b->b_next = NULL; + b->b_prev = mru; + if(mru != b) + mru->b_next = b; + mru = b; + cli(); + /* if the buffer exists but isn't populated. wait on it */ + if(!b->b_present) { + sleep_on(&b->b_wait); + printk("[buf] Waiting for buffer %04x:%04x to be populated...\n", b->b_device, b->b_block); + } + sti(); + printk("[buf] Fetched block %04x:%04x from cache\n", b->b_device, b->b_block); + return b->b_device ? b : NULL; +next: + p = &b->b_prev; + } + + /* + * otherwise, iterate through the least recently used + * buffers, to find a buffer that isn't pending an + * I/O operation, and read into it. + */ + + p = &lru; + while(b = *p) { + if(b->b_present || !b->b_device) + break; + p = &(*p)->b_next; + } + + if(!b) + return NULL; + + b->b_device = device; + b->b_block = block; + b->b_present = 0; + block_read(b); + wake_up(&b->b_wait); + printk("[buf] Called driver to read block %04x:%04x\n", b->b_device, b->b_block); + return b->b_device ? b : NULL; +} void buffer_init(void) { int c = 0; @@ -40,43 +100,3 @@ void buffer_init(void) { printk("[buf] Buffers initialized (0x%x buffers in pool)\n", c); } - -struct buffer *buffer_get_block(uint16_t device, uint16_t block) { - int ret; - struct buffer **p = &mru; - struct buffer *b; - - /* check if the requested block is already in the cache */ - while(*p) { - if((*p)->b_device == device && (*p)->b_block == block) { - /* put the buffer back at the MRU end of the list */ - (*p)->b_next = NULL; - (*p)->b_prev = mru; - mru = *p; - return *p; - } - p = &(*p)->b_prev; - } - - /* find a buffer at the end of the LRU list */ - b = lru; - lru = lru->b_next; - lru->b_prev = NULL; - ret = block_read(b->b_data, block); - /* abort if we failed to read in the block */ - if(ret < 0) { - /* release the allocated buffer to the pool */ - lru->b_prev = b; - b->b_next = lru; - b->b_prev = NULL; - lru = b; - return NULL; - } - b->b_device = device; - b->b_block = block; - /* put the buffer back at the MRU end of the list */ - b->b_next = NULL; - b->b_prev = mru; - mru = b; - return b; -} |
