13
#include <lib/libds/hashtable.h>
15
#include <mem/misc/pool.h>
16
#include <mem/sysmalloc.h>
20
#include <embox/unit.h>
21
EMBOX_UNIT_INIT(bcache_init);
23
#define BCACHE_SIZE OPTION_GET(NUMBER, bcache_size)
24
#define BCACHE_ALIGN OPTION_GET(NUMBER, bcache_align)
26
POOL_DEF(buffer_head_pool, struct buffer_head, BCACHE_SIZE);
27
static DLIST_DEFINE(bh_list);
30
static size_t bh_hash(void *key);
31
static int bh_cmp(void *key1, void *key2);
32
HASHTABLE_DEF(bcache_ht, BCACHE_SIZE / 10, bh_hash, bh_cmp);
33
POOL_DEF(bcach_ht_item_pool, struct hashtable_item, BCACHE_SIZE);
35
static struct hashtable *bcache = &bcache_ht;
36
static struct mutex bcache_mutex;
37
static int graw_buffers(struct block_dev *bdev, int block, size_t size);
38
static void free_more_memory(size_t size);
40
struct buffer_head *bcache_getblk_locked(struct block_dev *bdev, int block, size_t size) {
41
struct buffer_head key = { .bdev = bdev, .block = block };
42
struct buffer_head *bh;
46
mutex_lock(&bcache_mutex);
48
bh = (struct buffer_head *)hashtable_get(bcache, &key);
51
assert(size == bh->blocksize);
52
bcache_buffer_lock(bh);
53
mutex_unlock(&bcache_mutex);
57
while (-1 == graw_buffers(bdev, block, size)) {
58
free_more_memory(size);
61
mutex_unlock(&bcache_mutex);
67
static void free_more_memory(size_t size) {
68
struct buffer_head *bh = NULL;
69
struct hashtable_item *ht_item;
72
dlist_foreach_entry(bh, &bh_list, bh_next) {
73
if (buffer_locked(bh)) {
77
bcache_buffer_lock(bh);
79
if (buffer_journal(bh)) {
80
bcache_buffer_unlock(bh);
84
if (buffer_dirty(bh)) {
85
assert(bh->bdev && bh->bdev->driver);
86
assert(bh->bdev->driver->bdo_write);
88
bh->bdev->driver->bdo_write(bh->bdev, bh->data, bh->blocksize, bh->block);
91
dlist_del(&bh->bh_next);
92
ht_item = hashtable_del(bcache, bh);
94
bcache_buffer_unlock(bh);
97
pool_free(&bcach_ht_item_pool, ht_item);
98
pool_free(&buffer_head_pool, bh);
102
static int graw_buffers(struct block_dev *bdev, int block, size_t size) {
103
struct buffer_head *bh;
104
struct hashtable_item *ht_item;
106
bh = pool_alloc(&buffer_head_pool);
112
memset(bh, 0, sizeof(struct buffer_head));
114
buffer_set_flag(bh, BH_NEW);
115
mutex_init(&bh->mutex);
116
dlist_head_init(&bh->bh_next);
119
bh->blocksize = size;
120
bh->data = sysmemalign(BCACHE_ALIGN, size);
123
pool_free(&buffer_head_pool, bh);
126
ht_item = pool_alloc(&bcach_ht_item_pool);
129
pool_free(&buffer_head_pool, bh);
132
ht_item = hashtable_item_init(ht_item, bh, bh);
133
hashtable_put(bcache, ht_item);
135
dlist_add_next(&bh->bh_next, &bh_list);
140
static size_t bh_hash(void *key) {
141
return ((struct buffer_head *)key)->block;
144
static int bh_cmp(void *key1, void *key2) {
145
struct buffer_head *bh1 = (struct buffer_head *)key1;
146
struct buffer_head *bh2 = (struct buffer_head *)key2;
149
cmp_bdev = bh1->bdev < bh2->bdev ? -1 : bh1->bdev > bh2->bdev;
151
return (bh1->block < bh2->block ? -1 : bh1->block > bh2->block);
157
static int bcache_init(void) {
159
mutex_init(&bcache_mutex);