return EOK;
}
+void ext4_bcache_cleanup(struct ext4_bcache *bc)
+{
+ struct ext4_buf *buf, *tmp;
+ RB_FOREACH_SAFE(buf, ext4_buf_lba, &bc->lba_root, tmp) {
+ ext4_block_flush_buf(bc->bdev, buf);
+ ext4_bcache_drop_buf(bc, buf);
+ }
+}
+
int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
{
memset(bc, 0, sizeof(struct ext4_bcache));
void ext4_bcache_drop_buf(struct ext4_bcache *bc, struct ext4_buf *buf)
{
- /*Cannot drop any referenced buffers.*/
- ext4_assert(!buf->refctr);
+ /* Warn on dropping any referenced buffers.*/
+ if (buf->refctr) {
+ ext4_dbg(DEBUG_BCACHE, DBG_WARN "Buffer is still referenced. "
+ "lba: %" PRIu64 ", refctr: %" PRIu32 "\n",
+ buf->lba, buf->refctr);
+ } else
+ RB_REMOVE(ext4_buf_lru, &bc->lru_root, buf);
RB_REMOVE(ext4_buf_lba, &bc->lba_root, buf);
- RB_REMOVE(ext4_buf_lru, &bc->lru_root, buf);
/*Forcibly drop dirty buffer.*/
if (ext4_bcache_test_flag(buf, BC_DIRTY))
bc->ref_blocks--;
}
-int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
- bool *is_new)
+void ext4_bcache_invalidate_lba(struct ext4_bcache *bc,
+ uint64_t from,
+ uint32_t cnt)
{
- /* Try to search the buffer with exaxt LBA. */
- struct ext4_buf *buf = ext4_buf_lookup(bc, b->lb_id);
+ uint64_t end = from + cnt - 1;
+ struct ext4_buf *tmp = ext4_buf_lookup(bc, from), *buf;
+ RB_FOREACH_FROM(buf, ext4_buf_lba, tmp) {
+ if (buf->lba > end)
+ break;
+
+ /* Clear both dirty and up-to-date flags. */
+ if (ext4_bcache_test_flag(buf, BC_DIRTY))
+ ext4_bcache_remove_dirty_node(bc, buf);
+
+ ext4_bcache_clear_dirty(buf);
+ }
+}
+
+struct ext4_buf *
+ext4_bcache_find_get(struct ext4_bcache *bc, struct ext4_block *b,
+ uint64_t lba)
+{
+ struct ext4_buf *buf = ext4_buf_lookup(bc, lba);
if (buf) {
/* If buffer is not referenced. */
if (!buf->refctr) {
b->buf = buf;
b->data = buf->data;
+ }
+ return buf;
+}
+int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
+ bool *is_new)
+{
+ /* Try to search the buffer with exaxt LBA. */
+ struct ext4_buf *buf = ext4_bcache_find_get(bc, b, b->lb_id);
+ if (buf) {
*is_new = false;
return EOK;
}
if (!buf->refctr) {
RB_INSERT(ext4_buf_lru, &bc->lru_root, buf);
/* This buffer is ready to be flushed. */
- if (ext4_bcache_test_flag(buf, BC_DIRTY)) {
- if (bc->bdev->cache_write_back)
+ if (ext4_bcache_test_flag(buf, BC_DIRTY) &&
+ ext4_bcache_test_flag(buf, BC_UPTODATE)) {
+ if (bc->bdev->cache_write_back &&
+ !ext4_bcache_test_flag(buf, BC_FLUSH))
ext4_bcache_insert_dirty_node(bc, buf);
- else
+ else {
ext4_block_flush_buf(bc->bdev, buf);
+ ext4_bcache_clear_flag(buf, BC_FLUSH);
+ }
}
/* The buffer is invalidated...drop it. */
return (bc->cnt <= bc->ref_blocks);
}
+
/**
* @}
*/