Boot framework rework (#45)
[lunaix-os.git] / lunaix-os / kernel / bcache.c
1 #include <lunaix/bcache.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/spike.h>
4
5 static struct lru_zone* bcache_global_lru;
6
7 #define lock(bc)  spinlock_acquire(&((bc)->lock))
8 #define unlock(bc)  spinlock_release(&((bc)->lock))
9
10 static void 
11 __evict_internal_locked(struct bcache_node* node)
12 {
13     struct bcache* cache;
14
15     cache = node->holder;
16     cache->ops.sync_cached(cache, node->tag, node->data);
17
18     cache->ops.release_on_evict(cache, node->data);
19 }
20
21 static int 
22 __try_evict_bcache(struct lru_node* node)
23 {
24     struct bcache_node* bnode;
25     struct bcache* cache;
26     
27     bnode = container_of(node, struct bcache_node, lru_node);
28     cache = bnode->holder;
29     
30     lock(cache);
31
32     if (bnode->refs) {
33         unlock(cache);
34         return false;
35     }
36     
37     __evict_internal_locked(bnode);
38     btrie_remove(&cache->root, bnode->tag);
39     llist_delete(&bnode->objs);
40
41     vfree(bnode);
42
43     unlock(cache);
44
45     return true;
46 }
47
48 bcache_zone_t
49 bcache_create_zone(char* name)
50 {
51     return lru_new_zone(name, __try_evict_bcache);
52 }
53
54 void
55 bcache_init_zone(struct bcache* cache, bcache_zone_t lru, unsigned int log_ways, 
56                    int cap, unsigned int blk_size, struct bcache_ops* ops)
57 {
58     // TODO handle cap
59     
60     *cache = (struct bcache) {
61         .lru = lru,
62         .ops = *ops,
63         .blksz = blk_size
64     };
65
66     btrie_init(&cache->root, log_ways);
67     llist_init_head(&cache->objs);
68     spinlock_init(&cache->lock);
69 }
70
71 bcobj_t
72 bcache_put_and_ref(struct bcache* cache, unsigned long tag, void* block)
73 {
74     struct bcache_node* node;
75
76     lock(cache);
77
78     node = (struct bcache_node*)btrie_get(&cache->root, tag);
79
80     if (node != NULL) {
81         assert(!node->refs);
82         __evict_internal_locked(node);
83         // Now the node is ready to be reused.
84     }
85     else {
86         node = vzalloc(sizeof(*node));
87         btrie_set(&cache->root, tag, node);
88     }
89     
90     *node = (struct bcache_node) {
91         .data = block,
92         .holder = cache,
93         .tag = tag,
94         .refs = 1
95     };
96
97     lru_use_one(cache->lru, &node->lru_node);
98     llist_append(&cache->objs, &node->objs);
99
100     unlock(cache);
101
102     return (bcobj_t)node;
103 }
104
105 bool
106 bcache_tryget(struct bcache* cache, unsigned long tag, bcobj_t* result)
107 {
108     struct bcache_node* node;
109
110     lock(cache);
111
112     node = (struct bcache_node*)btrie_get(&cache->root, tag);
113     if (!node) {
114         unlock(cache);
115         *result = NULL;
116
117         return false;
118     }
119
120     node->refs++;
121
122     *result = (bcobj_t)node;
123
124     unlock(cache);
125     
126     return true;
127 }
128
129 void
130 bcache_return(bcobj_t obj)
131 {
132     struct bcache_node* node = (struct bcache_node*) obj;
133
134     assert(node->refs);
135
136     // non bisogno bloccare il cache, perche il lru ha la serratura propria.
137     lru_use_one(node->holder->lru, &node->lru_node);
138     node->refs--;
139 }
140
141 void
142 bcache_promote(bcobj_t obj)
143 {
144     struct bcache_node* node;
145     
146     node = (struct bcache_node*) obj;
147     assert(node->refs);
148     lru_use_one(node->holder->lru, &node->lru_node);
149 }
150
151 void
152 bcache_evict(struct bcache* cache, unsigned long tag)
153 {
154     struct bcache_node* node;
155
156     lock(cache);
157
158     node = (struct bcache_node*)btrie_get(&cache->root, tag);
159     
160     if (!node || node->refs) {
161         unlock(cache);
162         return;
163     }
164
165     __evict_internal_locked(node);
166
167     btrie_remove(&cache->root, tag);
168     lru_remove(cache->lru, &node->lru_node);
169     llist_delete(&node->objs);
170
171     vfree(node);
172
173     unlock(cache);
174 }
175
176 static void
177 bcache_flush_locked(struct bcache* cache)
178 {
179     struct bcache_node *pos, *n;
180     llist_for_each(pos, n, &cache->objs, objs) {
181         __evict_internal_locked(pos);
182         btrie_remove(&cache->root, pos->tag);
183         lru_remove(cache->lru, &pos->lru_node);
184         llist_delete(&pos->objs);
185     }
186 }
187
188 void
189 bcache_flush(struct bcache* cache)
190 {
191     lock(cache);
192     
193     bcache_flush_locked(cache);
194
195     unlock(cache);
196 }
197
198 void
199 bcache_free(struct bcache* cache)
200 {
201     lock(cache);
202     
203     bcache_flush_locked(cache);
204     btrie_release(&cache->root);
205
206     unlock(cache);
207
208     vfree(cache);
209 }
210
211 void
212 bcache_zone_free(bcache_zone_t zone)
213 {
214     lru_free_zone(zone);
215 }