summaryrefslogtreecommitdiff
path: root/kernel/fs/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fs/buffer.c')
-rw-r--r--kernel/fs/buffer.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/kernel/fs/buffer.c b/kernel/fs/buffer.c
new file mode 100644
index 0000000..7405738
--- /dev/null
+++ b/kernel/fs/buffer.c
@@ -0,0 +1,82 @@
+#include <kernel/con.h>
+#include <kernel/fs.h>
+#include <stdint.h>
+#include <string.h>
+
+/* memory dedicated to the block cache */
+#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);
+
+void buffer_init(void) {
+ int c = 0;
+ struct buffer *last = NULL;
+ struct buffer *b = (struct buffer*) BSTART;
+ void *d = (void*) (BEND - BLOCK_SIZE);
+
+ while(d > (void*) b) {
+ memset(b, 0, sizeof(struct buffer));
+
+ b->b_data = d;
+ b->b_prev = last;
+
+ if(last)
+ last->b_next = b;
+
+ last = b;
+
+ b = (struct buffer*) ((void*) b + sizeof(struct buffer));
+ d = (void*) (d - (void*) BLOCK_SIZE);
+
+ c++;
+ }
+
+ lru = (struct buffer*) BSTART;
+ mru = last;
+
+ 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;
+}