ref: 764793f1afc98c2819e03aa06c2d449dc693df4e
parent: 03bd7774082c8a04cf1aa0d1d4d8b3991f55e891
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Sat Dec 26 15:58:57 EST 2015
ext4_journal: a more efficient way to track journalled blocks. Now we build a RB-Tree in jbd_journal session to track journalled blocks instead of the one in jbd_trans.
--- a/lwext4/ext4_journal.c
+++ b/lwext4/ext4_journal.c
@@ -982,6 +982,7 @@
TAILQ_INIT(&journal->trans_queue);
TAILQ_INIT(&journal->cp_queue);
+ RB_INIT(&journal->block_rec_root);
journal->jbd_fs = jbd_fs;
jbd_journal_write_sb(journal);
return jbd_write_sb(jbd_fs);
@@ -1043,6 +1044,13 @@
* the disk.*/
jbd_journal_flush_all_trans(journal);
+ /* There should be no block record in this journal
+ * session. */
+ if (!RB_EMPTY(&journal->block_rec_root))
+ ext4_dbg(DEBUG_JBD,
+ DBG_WARN "There are still block records "
+ "in this journal session!\n");
+
features_incompatible =
ext4_get32(&jbd_fs->inode_ref.fs->sb,
features_incompatible);
@@ -1092,8 +1100,6 @@
if (!trans)
return NULL;
- RB_INIT(&trans->block_rec_root);
-
/* We will assign a trans_id to this transaction,
* once it has been committed.*/
trans->journal = journal;
@@ -1128,22 +1134,8 @@
return r;
}
-static inline int
-jbd_trans_insert_block_rec(struct jbd_trans *trans,
- ext4_fsblk_t lba)
-{
- struct jbd_block_rec *block_rec;
- block_rec = calloc(1, sizeof(struct jbd_block_rec));
- if (!block_rec)
- return ENOMEM;
-
- block_rec->lba = lba;
- RB_INSERT(jbd_block, &trans->block_rec_root, block_rec);
- return EOK;
-}
-
static struct jbd_block_rec *
-jbd_trans_block_rec_lookup(struct jbd_trans *trans,
+jbd_trans_block_rec_lookup(struct jbd_journal *journal,
ext4_fsblk_t lba)
{
struct jbd_block_rec tmp = {
@@ -1150,20 +1142,47 @@
.lba = lba
};
- return RB_FIND(jbd_block, &trans->block_rec_root, &tmp);
+ return RB_FIND(jbd_block,
+ &journal->block_rec_root,
+ &tmp);
}
+static inline struct jbd_block_rec *
+jbd_trans_insert_block_rec(struct jbd_trans *trans,
+ ext4_fsblk_t lba,
+ struct ext4_buf *buf)
+{
+ struct jbd_block_rec *block_rec;
+ block_rec = jbd_trans_block_rec_lookup(trans->journal, lba);
+ if (block_rec) {
+ /* Data should be flushed to disk already. */
+ ext4_assert(!block_rec->buf);
+ /* Now this block record belongs to this transaction. */
+ block_rec->trans = trans;
+ return block_rec;
+ }
+ block_rec = calloc(1, sizeof(struct jbd_block_rec));
+ if (!block_rec)
+ return NULL;
+
+ block_rec->lba = lba;
+ block_rec->buf = buf;
+ block_rec->trans = trans;
+ RB_INSERT(jbd_block, &trans->journal->block_rec_root, block_rec);
+ return block_rec;
+}
+
static inline void
-jbd_trans_remove_block_recs(struct jbd_trans *trans)
+jbd_trans_remove_block_rec(struct jbd_journal *journal,
+ struct jbd_buf *jbd_buf)
{
- struct jbd_block_rec *block_rec, *tmp;
- RB_FOREACH_SAFE(block_rec,
- jbd_block,
- &trans->block_rec_root,
- tmp) {
+ struct jbd_block_rec *block_rec = jbd_buf->block_rec;
+ /* If this block record doesn't belong to this transaction,
+ * give up.*/
+ if (block_rec->trans == jbd_buf->trans) {
RB_REMOVE(jbd_block,
- &trans->block_rec_root,
- block_rec);
+ &journal->block_rec_root,
+ block_rec);
free(block_rec);
}
}
@@ -1179,15 +1198,19 @@
if (!ext4_bcache_test_flag(block->buf, BC_DIRTY) &&
block->buf->end_write != jbd_trans_end_write) {
+ struct jbd_block_rec *block_rec;
buf = calloc(1, sizeof(struct jbd_buf));
if (!buf)
return ENOMEM;
- if (jbd_trans_insert_block_rec(trans, block->lb_id) != EOK) {
+ if ((block_rec = jbd_trans_insert_block_rec(trans,
+ block->lb_id,
+ block->buf)) == NULL) {
free(buf);
return ENOMEM;
}
+ buf->block_rec = block_rec;
buf->trans = trans;
buf->block = *block;
ext4_bcache_inc_ref(block->buf);
@@ -1232,16 +1255,25 @@
ext4_fsblk_t lba)
{
int r = EOK;
- struct jbd_trans *tmp;
struct jbd_journal *journal = trans->journal;
- TAILQ_FOREACH(tmp, &journal->cp_queue, trans_node) {
- struct jbd_block_rec *block_rec =
- jbd_trans_block_rec_lookup(trans, lba);
- if (block_rec)
- jbd_trans_revoke_block(trans, lba);
+ struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
+ struct jbd_block_rec *block_rec =
+ jbd_trans_block_rec_lookup(journal, lba);
+ /* Make sure we don't flush any buffers belong to this transaction. */
+ if (block_rec && block_rec->trans != trans) {
+ /* If the buffer has not been flushed yet, flush it now. */
+ if (block_rec->buf) {
+ r = ext4_block_flush_buf(fs->bdev, block_rec->buf);
+ if (r != EOK)
+ return r;
+
+ }
+
+ jbd_trans_revoke_block(trans, lba);
}
- return r;
+
+ return EOK;
}
/**@brief Free a transaction
@@ -1265,6 +1297,7 @@
ext4_block_set(fs->bdev, &jbd_buf->block);
}
+ jbd_trans_remove_block_rec(journal, jbd_buf);
LIST_REMOVE(jbd_buf, buf_node);
free(jbd_buf);
}
@@ -1274,7 +1307,6 @@
free(rec);
}
- jbd_trans_remove_block_recs(trans);
free(trans);
}
@@ -1534,6 +1566,8 @@
trans->error = res;
LIST_REMOVE(jbd_buf, buf_node);
+ jbd_buf->block_rec->buf = NULL;
+ jbd_trans_remove_block_rec(journal, jbd_buf);
free(jbd_buf);
/* Clear the end_write and end_write_arg fields. */
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -1096,6 +1096,7 @@
struct jbd_buf {
struct ext4_block block;
struct jbd_trans *trans;
+ struct jbd_block_rec *block_rec;
LIST_ENTRY(jbd_buf) buf_node;
};
@@ -1106,6 +1107,8 @@
struct jbd_block_rec {
ext4_fsblk_t lba;
+ struct ext4_buf *buf;
+ struct jbd_trans *trans;
RB_ENTRY(jbd_block_rec) block_rec_node;
};
@@ -1122,7 +1125,6 @@
LIST_HEAD(jbd_trans_buf, jbd_buf) buf_list;
LIST_HEAD(jbd_revoke_list, jbd_revoke_rec) revoke_list;
- RB_HEAD(jbd_block, jbd_block_rec) block_rec_root;
TAILQ_ENTRY(jbd_trans) trans_node;
};
@@ -1137,6 +1139,7 @@
TAILQ_HEAD(jbd_trans_queue, jbd_trans) trans_queue;
TAILQ_HEAD(jbd_cp_queue, jbd_trans) cp_queue;
+ RB_HEAD(jbd_block, jbd_block_rec) block_rec_root;
struct jbd_fs *jbd_fs;
};