Fix: stale dnode caching instance cause locked-up upon accessing (#52)
[lunaix-os.git] / lunaix-os / includes / lunaix / bcache.h
1 #ifndef __LUNAIX_BCACHE_H
2 #define __LUNAIX_BCACHE_H
3
4 #include <lunaix/ds/btrie.h>
5 #include <lunaix/ds/lru.h>
6 #include <lunaix/ds/spinlock.h>
7 #include <lunaix/ds/llist.h>
8 #include <lunaix/spike.h>
9
10 /*
11    Block cache. A cache built on top of
12    sparse array (trie tree) allow caching
13    any blocks that have spatial structure
14    attach to them. With intention to unify
15    all the existing caching construct, as
16    well as potential future use case.
17    
18    NB. block is not necessarily
19    equivalence to disk sector nor filesystem 
20    logical block. block can be anything 
21    discrete.
22
23    NB2. not to be confused with page cahce
24    (pcache), which is a special case of
25    bcache.
26 */
27
28 struct bcache;
29 struct bcache_ops
30 {
31     void (*release_on_evict)(struct bcache*, void* data);
32     void (*sync_cached)(struct bcache*, unsigned long tag, void* data);
33 };
34
35 struct bcache
36 {
37     struct {
38         unsigned int blksz;
39     };
40     
41     struct btrie root;
42     struct lru_zone* lru;
43     struct bcache_ops ops;
44     struct llist_header objs;
45     struct spinlock lock;
46 };  // block cache
47
48 struct bcache_node
49 {
50     void* data;
51
52     unsigned long tag;
53     
54     struct bcache* holder;
55     unsigned int refs;
56     struct lru_node lru_node;
57     struct llist_header objs;
58 };
59
60 typedef void * bcobj_t;
61 typedef struct lru_zone* bcache_zone_t;
62
63 static inline void*
64 bcached_data(bcobj_t obj)
65 {
66     return ((struct bcache_node*)obj)->data;
67 }
68
69 #define to_bcache_node(cobj) \
70     ((struct bcache_node*)(cobj))
71
72 #define bcache_holder_embed(cobj, type, member)   \
73     container_of(to_bcache_node(cobj)->holder, type, member)
74
75 /**
76  * @brief Create a block cache with shared bcache zone
77  * 
78  * @param cache to be initialized
79  * @param name name of this cache
80  * @param log_ways ways-associative of this cache
81  * @param cap capacity of this cache, -1 for 'infinity' cache
82  * @param blk_size size of each cached object
83  * @param ops block cache operation
84  */
85 void
86 bcache_init_zone(struct bcache* cache, bcache_zone_t zone, 
87                  unsigned int log_ways, int cap, 
88                  unsigned int blk_size, struct bcache_ops* ops);
89
90 bcache_zone_t
91 bcache_create_zone(char* name);
92
93 bcobj_t
94 bcache_put_and_ref(struct bcache* cache, unsigned long tag, void* block);
95
96 /**
97  * @brief Try look for a hit and return the reference to block.
98  * Now, this create a unmanaged pointer that could end up in
99  * everywhere and unsafe to evict. One should called `bcache_tryhit_unref`
100  * when the reference is no longer needed.
101  * 
102  * @param cache 
103  * @param tag 
104  * @param block_out 
105  * @return true 
106  * @return false 
107  */
108 bool
109 bcache_tryget(struct bcache* cache, unsigned long tag, bcobj_t* result);
110
111 /**
112  * @brief Unreference a cached block that is returned 
113  * by `bcache_tryhit_ref`
114  * 
115  * @param cache 
116  * @param tag 
117  * @param block_out 
118  * @return true 
119  * @return false 
120  */
121 void
122 bcache_return(bcobj_t obj);
123
124 static inline void
125 bcache_refonce(bcobj_t obj)
126 {
127     struct bcache_node* b_node;
128     b_node = to_bcache_node(obj);
129
130     assert(b_node->refs);
131     b_node->refs++;
132 }
133
134 void
135 bcache_promote(bcobj_t obj);
136
137 void
138 bcache_evict(struct bcache* cache, unsigned long tag);
139
140 static inline void
141 bcache_evict_one(struct bcache* cache)
142 {
143     lru_evict_one(cache->lru);
144 }
145
146 void
147 bcache_flush(struct bcache* cache);
148
149 void
150 bcache_free(struct bcache* cache);
151
152 void
153 bcache_zone_free(bcache_zone_t zone);
154
155 /**
156  * @brief Create a block cache
157  * 
158  * @param cache to be initialized
159  * @param name name of this cache
160  * @param log_ways ways-associative of this cache
161  * @param cap capacity of this cache, -1 for 'infinity' cache
162  * @param blk_size size of each cached object
163  * @param ops block cache operation
164  */
165 static inline void
166 bcache_init(struct bcache* cache, char* name, unsigned int log_ways, 
167             int cap, unsigned int blk_size, struct bcache_ops* ops)
168 {
169     bcache_init_zone(cache, bcache_create_zone(name), 
170                      log_ways, cap, blk_size, ops);
171 }
172
173 static inline void
174 bcache_put(struct bcache* cache, unsigned long tag, void* block)
175 {
176     bcache_return(bcache_put_and_ref(cache, tag, block));
177 }
178
179 #endif /* __LUNAIX_BCACHE_H */