embox

Форк
0
/
bcache.c 
162 строки · 3.5 Кб
1
/**
2
 * @file
3
 * @brief Buffer cache
4
 *
5
 * @author  Alexander Kalmuk
6
 * @date    22.07.2013
7
 */
8

9
#include <string.h>
10
#include <stdbool.h>
11
#include <stdlib.h>
12

13
#include <lib/libds/hashtable.h>
14

15
#include <mem/misc/pool.h>
16
#include <mem/sysmalloc.h>
17

18
#include <fs/bcache.h>
19

20
#include <embox/unit.h>
21
EMBOX_UNIT_INIT(bcache_init);
22

23
#define BCACHE_SIZE   OPTION_GET(NUMBER, bcache_size)
24
#define BCACHE_ALIGN  OPTION_GET(NUMBER, bcache_align)
25

26
POOL_DEF(buffer_head_pool, struct buffer_head, BCACHE_SIZE);
27
static DLIST_DEFINE(bh_list);
28

29

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);
34

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);
39

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;
43

44
	assert(bdev);
45

46
	mutex_lock(&bcache_mutex);
47
	while (1) {
48
		bh = (struct buffer_head *)hashtable_get(bcache, &key);
49

50
		if (bh) {
51
			assert(size == bh->blocksize);
52
			bcache_buffer_lock(bh);
53
			mutex_unlock(&bcache_mutex);
54
			return bh;
55
		}
56

57
		while (-1 == graw_buffers(bdev, block, size)) {
58
			free_more_memory(size);
59
		}
60
	}
61
	mutex_unlock(&bcache_mutex);
62

63
	assert(0); /* UNREACHABLE */
64
	return NULL;
65
}
66

67
static void free_more_memory(size_t size) {
68
	struct buffer_head *bh = NULL;
69
	struct hashtable_item *ht_item;
70

71
	/* Free everything that we can free */
72
	dlist_foreach_entry(bh, &bh_list, bh_next) {
73
		if (buffer_locked(bh)) {
74
			continue;
75
		}
76

77
		bcache_buffer_lock(bh);
78
		{
79
			if (buffer_journal(bh)) {
80
				bcache_buffer_unlock(bh);
81
				continue;
82
			}
83

84
			if (buffer_dirty(bh)) {
85
				assert(bh->bdev && bh->bdev->driver);
86
				assert(bh->bdev->driver->bdo_write);
87
				/* Write directly to disk */
88
				bh->bdev->driver->bdo_write(bh->bdev, bh->data, bh->blocksize, bh->block);
89
			}
90

91
			dlist_del(&bh->bh_next);
92
			ht_item = hashtable_del(bcache, bh);
93
		}
94
		bcache_buffer_unlock(bh);
95

96
		sysfree(bh->data);
97
		pool_free(&bcach_ht_item_pool, ht_item);
98
		pool_free(&buffer_head_pool, bh);
99
	}
100
}
101

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;
105

106
	bh = pool_alloc(&buffer_head_pool);
107

108
	if (!bh) {
109
		return -1;
110
	}
111

112
	memset(bh, 0, sizeof(struct buffer_head));
113

114
	buffer_set_flag(bh, BH_NEW);
115
	mutex_init(&bh->mutex);
116
	dlist_head_init(&bh->bh_next);
117
	bh->bdev = bdev;
118
	bh->block = block;
119
	bh->blocksize = size;
120
	bh->data = sysmemalign(BCACHE_ALIGN, size);
121

122
	if (!bh->data) {
123
		pool_free(&buffer_head_pool, bh);
124
		return -1;
125
	}
126
	ht_item = pool_alloc(&bcach_ht_item_pool);
127
	if (!ht_item) {
128
		sysfree(bh->data);
129
		pool_free(&buffer_head_pool, bh);
130
		return -1;
131
	}
132
	ht_item = hashtable_item_init(ht_item, bh, bh);
133
	hashtable_put(bcache, ht_item);
134

135
	dlist_add_next(&bh->bh_next, &bh_list);
136

137
	return 0;
138
}
139

140
static size_t bh_hash(void *key) {
141
	return ((struct buffer_head *)key)->block;
142
}
143

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;
147
	int cmp_bdev;
148

149
	cmp_bdev = bh1->bdev < bh2->bdev ? -1 : bh1->bdev > bh2->bdev;
150
	if (!cmp_bdev) {
151
		return (bh1->block < bh2->block ? -1 : bh1->block > bh2->block);
152
	}
153

154
	return cmp_bdev;
155
}
156

157
static int bcache_init(void) {
158

159
	mutex_init(&bcache_mutex);
160

161
	return 0;
162
}
163

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.