shithub: lwext4

Download patch

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;
 };