#include #include #include #include #include #include /* 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 **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; 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 (%d buffers [%dKiB] in pool)\n", c, c * BLOCK_SIZE / 1024); }