2 * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup lwext4
34 * @brief Block cache allocator.
37 #include "ext4_config.h"
38 #include "ext4_bcache.h"
39 #include "ext4_debug.h"
40 #include "ext4_errno.h"
46 ext4_bcache_lba_compare(struct ext4_buf *a,
49 return a->lba - b->lba;
53 ext4_bcache_lru_compare(struct ext4_buf *a,
56 return a->lru_id - b->lru_id;
59 RB_GENERATE_INTERNAL(ext4_buf_lba, ext4_buf, lba_node,
60 ext4_bcache_lba_compare, static inline)
61 RB_GENERATE_INTERNAL(ext4_buf_lru, ext4_buf, lru_node,
62 ext4_bcache_lru_compare, static inline)
64 int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
67 ext4_assert(bc && cnt && itemsize);
69 memset(bc, 0, sizeof(struct ext4_bcache));
72 bc->itemsize = itemsize;
74 bc->max_ref_blocks = 0;
79 int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
81 memset(bc, 0, sizeof(struct ext4_bcache));
85 static struct ext4_buf *
86 ext4_buf_alloc(struct ext4_bcache *bc, uint64_t lba)
90 data = malloc(bc->itemsize);
94 buf = malloc(sizeof(struct ext4_buf));
105 memset(&buf->lba_node, 0, sizeof(buf->lba_node));
106 memset(&buf->lru_node, 0, sizeof(buf->lru_node));
107 memset(&buf->dirty_node, 0, sizeof(buf->dirty_node));
111 static void ext4_buf_free(struct ext4_buf *buf)
117 static struct ext4_buf *
118 ext4_buf_lookup(struct ext4_bcache *bc, uint64_t lba)
120 struct ext4_buf tmp = {
124 return RB_FIND(ext4_buf_lba, &bc->lba_root, &tmp);
127 struct ext4_buf *ext4_buf_lowest_lru(struct ext4_bcache *bc)
129 return RB_MIN(ext4_buf_lba, &bc->lba_root);
132 void ext4_bcache_drop_buf(struct ext4_bcache *bc, struct ext4_buf *buf)
134 /*Cannot drop any referenced buffers.*/
135 ext4_assert(!buf->refctr);
137 RB_REMOVE(ext4_buf_lba, &bc->lba_root, buf);
138 RB_REMOVE(ext4_buf_lru, &bc->lru_root, buf);
140 /*Forcibly drop dirty buffer.*/
141 if (ext4_bcache_test_flag(buf, BC_DIRTY))
142 SLIST_REMOVE(&bc->dirty_list,
151 int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
154 struct ext4_buf *buf = ext4_buf_lookup(bc, b->lb_id);
157 buf->lru_id = ++bc->lru_ctr;
158 RB_REMOVE(ext4_buf_lru, &bc->lru_root, buf);
159 if (ext4_bcache_test_flag(buf, BC_DIRTY))
160 SLIST_REMOVE(&bc->dirty_list,
168 b->uptodate = ext4_bcache_test_flag(buf, BC_UPTODATE);
175 buf = ext4_buf_alloc(bc, b->lb_id);
179 RB_INSERT(ext4_buf_lba, &bc->lba_root, buf);
183 buf->lru_id = ++bc->lru_ctr;
192 int ext4_bcache_free(struct ext4_bcache *bc, struct ext4_block *b,
195 struct ext4_buf *buf = b->buf;
197 ext4_assert(bc && b);
200 ext4_assert(b->lb_id);
202 /*Block should have a valid pointer to ext4_buf.*/
205 /*Check if someone don't try free unreferenced block cache.*/
206 ext4_assert(buf->refctr);
208 /*Just decrease reference counter*/
212 bc->free_delay = free_delay;
215 ext4_bcache_set_flag(buf, BC_DIRTY);
216 ext4_bcache_set_flag(buf, BC_UPTODATE);
220 ext4_bcache_clear_flag(buf, BC_UPTODATE);
223 RB_INSERT(ext4_buf_lru, &bc->lru_root, buf);
224 if (ext4_bcache_test_flag(buf, BC_DIRTY))
225 SLIST_INSERT_HEAD(&bc->dirty_list, buf, dirty_node);
227 if (!ext4_bcache_test_flag(buf, BC_UPTODATE))
228 ext4_bcache_drop_buf(bc, buf);
240 bool ext4_bcache_is_full(struct ext4_bcache *bc)
242 return (bc->cnt <= bc->ref_blocks);