ext4_bcache.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. /**@brief The block cache this buffer belongs to. */
  72. struct ext4_bcache *bc;
  73. /**@brief Whether or not buffer is on dirty list.*/
  74. bool on_dirty_list;
  75. /**@brief LBA tree node*/
  76. RB_ENTRY(ext4_buf) lba_node;
  77. /**@brief LRU tree node*/
  78. RB_ENTRY(ext4_buf) lru_node;
  79. /**@brief Dirty list node*/
  80. SLIST_ENTRY(ext4_buf) dirty_node;
  81. /**@brief Callback routine after a disk-write operation.
  82. * @param bc block cache descriptor
  83. * @param buf buffer descriptor
  84. * @param standard error code returned by bdev->bwrite()
  85. * @param arg argument passed to this routine*/
  86. void (*end_write)(struct ext4_bcache *bc,
  87. struct ext4_buf *buf,
  88. int res,
  89. void *arg);
  90. /**@brief argument passed to end_write() callback.*/
  91. void *end_write_arg;
  92. };
  93. /**@brief Block cache descriptor*/
  94. struct ext4_bcache {
  95. /**@brief Item count in block cache*/
  96. uint32_t cnt;
  97. /**@brief Item size in block cache*/
  98. uint32_t itemsize;
  99. /**@brief Last recently used counter*/
  100. uint32_t lru_ctr;
  101. /**@brief Currently referenced datablocks*/
  102. uint32_t ref_blocks;
  103. /**@brief Maximum referenced datablocks*/
  104. uint32_t max_ref_blocks;
  105. /**@brief The blockdev binded to this block cache*/
  106. struct ext4_blockdev *bdev;
  107. /**@brief The cache should not be shaked */
  108. bool dont_shake;
  109. /**@brief A tree holding all bufs*/
  110. RB_HEAD(ext4_buf_lba, ext4_buf) lba_root;
  111. /**@brief A tree holding unreferenced bufs*/
  112. RB_HEAD(ext4_buf_lru, ext4_buf) lru_root;
  113. /**@brief A singly-linked list holding dirty buffers*/
  114. SLIST_HEAD(ext4_buf_dirty, ext4_buf) dirty_list;
  115. };
  116. /**@brief buffer state bits
  117. *
  118. * - BC♡UPTODATE: Buffer contains valid data.
  119. * - BC_DIRTY: Buffer is dirty.
  120. * - BC_FLUSH: Buffer will be immediately flushed,
  121. * when no one references it.
  122. * - BC_TMP: Buffer will be dropped once its refctr
  123. * reaches zero.
  124. */
  125. enum bcache_state_bits {
  126. BC_UPTODATE,
  127. BC_DIRTY,
  128. BC_FLUSH,
  129. BC_TMP
  130. };
  131. #define ext4_bcache_set_flag(buf, b) \
  132. (buf)->flags |= 1 << (b)
  133. #define ext4_bcache_clear_flag(buf, b) \
  134. (buf)->flags &= ~(1 << (b))
  135. #define ext4_bcache_test_flag(buf, b) \
  136. (((buf)->flags & (1 << (b))) >> (b))
  137. static inline void ext4_bcache_set_dirty(struct ext4_buf *buf) {
  138. ext4_bcache_set_flag(buf, BC_UPTODATE);
  139. ext4_bcache_set_flag(buf, BC_DIRTY);
  140. }
  141. static inline void ext4_bcache_clear_dirty(struct ext4_buf *buf) {
  142. ext4_bcache_clear_flag(buf, BC_UPTODATE);
  143. ext4_bcache_clear_flag(buf, BC_DIRTY);
  144. }
  145. /**@brief Increment reference counter of buf by 1.*/
  146. #define ext4_bcache_inc_ref(buf) ((buf)->refctr++)
  147. /**@brief Decrement reference counter of buf by 1.*/
  148. #define ext4_bcache_dec_ref(buf) ((buf)->refctr--)
  149. /**@brief Insert buffer to dirty cache list
  150. * @param bc block cache descriptor
  151. * @param buf buffer descriptor */
  152. static inline void
  153. ext4_bcache_insert_dirty_node(struct ext4_bcache *bc, struct ext4_buf *buf) {
  154. if (!buf->on_dirty_list) {
  155. SLIST_INSERT_HEAD(&bc->dirty_list, buf, dirty_node);
  156. buf->on_dirty_list = true;
  157. }
  158. }
  159. /**@brief Remove buffer to dirty cache list
  160. * @param bc block cache descriptor
  161. * @param buf buffer descriptor */
  162. static inline void
  163. ext4_bcache_remove_dirty_node(struct ext4_bcache *bc, struct ext4_buf *buf) {
  164. if (buf->on_dirty_list) {
  165. SLIST_REMOVE(&bc->dirty_list, buf, ext4_buf, dirty_node);
  166. buf->on_dirty_list = false;
  167. }
  168. }
  169. /**@brief Dynamic initialization of block cache.
  170. * @param bc block cache descriptor
  171. * @param cnt items count in block cache
  172. * @param itemsize single item size (in bytes)
  173. * @return standard error code*/
  174. int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
  175. uint32_t itemsize);
  176. /**@brief Do cleanup works on block cache.
  177. * @param bc block cache descriptor.*/
  178. void ext4_bcache_cleanup(struct ext4_bcache *bc);
  179. /**@brief Dynamic de-initialization of block cache.
  180. * @param bc block cache descriptor
  181. * @return standard error code*/
  182. int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
  183. /**@brief Get a buffer with the lowest LRU counter in bcache.
  184. * @param bc block cache descriptor
  185. * @return buffer with the lowest LRU counter*/
  186. struct ext4_buf *ext4_buf_lowest_lru(struct ext4_bcache *bc);
  187. /**@brief Drop unreferenced buffer from bcache.
  188. * @param bc block cache descriptor
  189. * @param buf buffer*/
  190. void ext4_bcache_drop_buf(struct ext4_bcache *bc, struct ext4_buf *buf);
  191. /**@brief Invalidate a range of buffers.
  192. * @param bc block cache descriptor
  193. * @param from starting lba
  194. * @param cnt block counts
  195. * @param buf buffer*/
  196. void ext4_bcache_invalidate_lba(struct ext4_bcache *bc,
  197. uint64_t from,
  198. uint32_t cnt);
  199. /**@brief Find existing buffer from block cache memory.
  200. * Unreferenced block allocation is based on LRU
  201. * (Last Recently Used) algorithm.
  202. * @param bc block cache descriptor
  203. * @param b block to alloc
  204. * @param lba logical block address
  205. * @return block cache buffer */
  206. struct ext4_buf *
  207. ext4_bcache_find_get(struct ext4_bcache *bc, struct ext4_block *b,
  208. uint64_t lba);
  209. /**@brief Allocate block from block cache memory.
  210. * Unreferenced block allocation is based on LRU
  211. * (Last Recently Used) algorithm.
  212. * @param bc block cache descriptor
  213. * @param b block to alloc
  214. * @param is_new block is new (needs to be read)
  215. * @return standard error code*/
  216. int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
  217. bool *is_new);
  218. /**@brief Free block from cache memory (decrement reference counter).
  219. * @param bc block cache descriptor
  220. * @param b block to free
  221. * @return standard error code*/
  222. int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b);
  223. /**@brief Return a full status of block cache.
  224. * @param bc block cache descriptor
  225. * @return full status*/
  226. bool ext4_bcache_is_full(struct ext4_bcache *bc);
  227. #ifdef __cplusplus
  228. }
  229. #endif
  230. #endif /* EXT4_BCACHE_H_ */
  231. /**
  232. * @}
  233. */