ext4_bcache.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * - Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * - Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * - The name of the author may not be used to endorse or promote products
  15. * derived from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. /** @addtogroup lwext4
  29. * @{
  30. */
  31. /**
  32. * @file ext4_bcache.h
  33. * @brief Block cache allocator.
  34. */
  35. #ifndef EXT4_BCACHE_H_
  36. #define EXT4_BCACHE_H_
  37. #ifdef __cplusplus
  38. extern "C" {
  39. #endif
  40. #include <ext4_config.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <misc/tree.h>
  44. #include <misc/queue.h>
  45. #define EXT4_BLOCK_ZERO() \
  46. {.lb_id = 0, .data = 0}
  47. /**@brief Single block descriptor*/
  48. struct ext4_block {
  49. /**@brief Logical block ID*/
  50. uint64_t lb_id;
  51. /**@brief Buffer */
  52. struct ext4_buf *buf;
  53. /**@brief Data buffer.*/
  54. uint8_t *data;
  55. };
  56. struct ext4_bcache;
  57. /**@brief Single block descriptor*/
  58. struct ext4_buf {
  59. /**@brief Flags*/
  60. int flags;
  61. /**@brief Logical block address*/
  62. uint64_t lba;
  63. /**@brief Data buffer.*/
  64. uint8_t *data;
  65. /**@brief LRU priority. (unused) */
  66. uint32_t lru_prio;
  67. /**@brief LRU id.*/
  68. uint32_t lru_id;
  69. /**@brief Reference count table*/
  70. uint32_t refctr;
  71. /* refcount for read */
  72. uint32_t read_refctr;
  73. /**@brief The block cache this buffer belongs to. */
  74. struct ext4_bcache *bc;
  75. /**@brief Whether or not buffer is on dirty list.*/
  76. bool on_dirty_list;
  77. /**@brief LBA tree node*/
  78. RB_ENTRY(ext4_buf) lba_node;
  79. /**@brief LRU tree node*/
  80. RB_ENTRY(ext4_buf) lru_node;
  81. /**@brief Dirty list node*/
  82. SLIST_ENTRY(ext4_buf) dirty_node;
  83. /**@brief Callback routine after a disk-write operation.
  84. * @param bc block cache descriptor
  85. * @param buf buffer descriptor
  86. * @param standard error code returned by bdev->bwrite()
  87. * @param arg argument passed to this routine*/
  88. void (*end_write)(struct ext4_bcache *bc,
  89. struct ext4_buf *buf,
  90. int res,
  91. void *arg);
  92. /**@brief argument passed to end_write() callback.*/
  93. void *end_write_arg;
  94. };
  95. /**@brief Block cache descriptor*/
  96. struct ext4_bcache {
  97. /**@brief Item count in block cache*/
  98. uint32_t cnt;
  99. /**@brief Item size in block cache*/
  100. uint32_t itemsize;
  101. /**@brief Last recently used counter*/
  102. uint32_t lru_ctr;
  103. /**@brief Currently referenced datablocks*/
  104. uint32_t ref_blocks;
  105. /**@brief Maximum referenced datablocks*/
  106. uint32_t max_ref_blocks;
  107. /**@brief The blockdev binded to this block cache*/
  108. struct ext4_blockdev *bdev;
  109. /**@brief The cache should not be shaked */
  110. bool dont_shake;
  111. /**@brief A tree holding all bufs*/
  112. RB_HEAD(ext4_buf_lba, ext4_buf) lba_root;
  113. /**@brief A tree holding unreferenced bufs*/
  114. RB_HEAD(ext4_buf_lru, ext4_buf) lru_root;
  115. /**@brief A singly-linked list holding dirty buffers*/
  116. SLIST_HEAD(ext4_buf_dirty, ext4_buf) dirty_list;
  117. };
  118. /**@brief buffer state bits
  119. *
  120. * - BC♡UPTODATE: Buffer contains valid data.
  121. * - BC_DIRTY: Buffer is dirty.
  122. * - BC_FLUSH: Buffer will be immediately flushed,
  123. * when no one references it.
  124. * - BC_TMP: Buffer will be dropped once its refctr
  125. * reaches zero.
  126. */
  127. enum bcache_state_bits {
  128. BC_UPTODATE,
  129. BC_DIRTY,
  130. BC_FLUSH,
  131. BC_TMP
  132. };
  133. #define ext4_bcache_set_flag(buf, b) \
  134. (buf)->flags |= 1 << (b)
  135. #define ext4_bcache_clear_flag(buf, b) \
  136. (buf)->flags &= ~(1 << (b))
  137. #define ext4_bcache_test_flag(buf, b) \
  138. (((buf)->flags & (1 << (b))) >> (b))
  139. static inline void ext4_bcache_set_dirty(struct ext4_buf *buf) {
  140. ext4_bcache_set_flag(buf, BC_UPTODATE);
  141. ext4_bcache_set_flag(buf, BC_DIRTY);
  142. }
  143. static inline void ext4_bcache_clear_dirty(struct ext4_buf *buf) {
  144. ext4_bcache_clear_flag(buf, BC_UPTODATE);
  145. ext4_bcache_clear_flag(buf, BC_DIRTY);
  146. }
  147. /**@brief Increment reference counter of buf by 1.*/
  148. #define ext4_bcache_inc_ref(buf) ((buf)->refctr++)
  149. #define ext4_bcache_inc_read_ref(buf) ((buf)->read_refctr++)
  150. /**@brief Decrement reference counter of buf by 1.*/
  151. #define ext4_bcache_dec_ref(buf) ((buf)->refctr--)
  152. #define ext4_bcache_dec_read_ref(buf) ((buf)->read_refctr--)
  153. /**@brief Insert buffer to dirty cache list
  154. * @param bc block cache descriptor
  155. * @param buf buffer descriptor */
  156. static inline void
  157. ext4_bcache_insert_dirty_node(struct ext4_bcache *bc, struct ext4_buf *buf) {
  158. if (!buf->on_dirty_list) {
  159. SLIST_INSERT_HEAD(&bc->dirty_list, buf, dirty_node);
  160. buf->on_dirty_list = true;
  161. }
  162. }
  163. /**@brief Remove buffer to dirty cache list
  164. * @param bc block cache descriptor
  165. * @param buf buffer descriptor */
  166. static inline void
  167. ext4_bcache_remove_dirty_node(struct ext4_bcache *bc, struct ext4_buf *buf) {
  168. if (buf->on_dirty_list) {
  169. SLIST_REMOVE(&bc->dirty_list, buf, ext4_buf, dirty_node);
  170. buf->on_dirty_list = false;
  171. }
  172. }
  173. /**@brief Dynamic initialization of block cache.
  174. * @param bc block cache descriptor
  175. * @param cnt items count in block cache
  176. * @param itemsize single item size (in bytes)
  177. * @return standard error code*/
  178. int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
  179. uint32_t itemsize);
  180. /**@brief Do cleanup works on block cache.
  181. * @param bc block cache descriptor.*/
  182. void ext4_bcache_cleanup(struct ext4_bcache *bc);
  183. /**@brief Dynamic de-initialization of block cache.
  184. * @param bc block cache descriptor
  185. * @return standard error code*/
  186. int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
  187. /**@brief Get a buffer with the lowest LRU counter in bcache.
  188. * @param bc block cache descriptor
  189. * @return buffer with the lowest LRU counter*/
  190. struct ext4_buf *ext4_buf_lowest_lru(struct ext4_bcache *bc);
  191. /**@brief Drop unreferenced buffer from bcache.
  192. * @param bc block cache descriptor
  193. * @param buf buffer*/
  194. void ext4_bcache_drop_buf(struct ext4_bcache *bc, struct ext4_buf *buf);
  195. /**@brief Invalidate a buffer.
  196. * @param bc block cache descriptor
  197. * @param buf buffer*/
  198. void ext4_bcache_invalidate_buf(struct ext4_bcache *bc,
  199. struct ext4_buf *buf);
  200. /**@brief Invalidate a range of buffers.
  201. * @param bc block cache descriptor
  202. * @param from starting lba
  203. * @param cnt block counts*/
  204. void ext4_bcache_invalidate_lba(struct ext4_bcache *bc,
  205. uint64_t from,
  206. uint32_t cnt);
  207. /**@brief Find existing buffer from block cache memory.
  208. * Unreferenced block allocation is based on LRU
  209. * (Last Recently Used) algorithm.
  210. * @param bc block cache descriptor
  211. * @param b block to alloc
  212. * @param lba logical block address
  213. * @return block cache buffer */
  214. struct ext4_buf *
  215. ext4_bcache_find_get(struct ext4_bcache *bc, struct ext4_block *b,
  216. uint64_t lba);
  217. /**@brief Allocate block from block cache memory.
  218. * Unreferenced block allocation is based on LRU
  219. * (Last Recently Used) algorithm.
  220. * @param bc block cache descriptor
  221. * @param b block to alloc
  222. * @param is_new block is new (needs to be read)
  223. * @return standard error code*/
  224. int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
  225. bool *is_new);
  226. /**@brief Free block from cache memory (decrement reference counter).
  227. * @param bc block cache descriptor
  228. * @param b block to free
  229. * @return standard error code*/
  230. int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b);
  231. /**@brief Return a full status of block cache.
  232. * @param bc block cache descriptor
  233. * @return full status*/
  234. bool ext4_bcache_is_full(struct ext4_bcache *bc);
  235. #ifdef __cplusplus
  236. }
  237. #endif
  238. #endif /* EXT4_BCACHE_H_ */
  239. /**
  240. * @}
  241. */