shithub: lwext4

Download patch

ref: d7284d15564fc5cb4123671ab343480984dbcad2
parent: c5ea10075711ba4814084b7ef3bc56c537fd91b0
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Tue Dec 29 20:45:46 EST 2015

ext4_journal: improve transaction handling

Keep track on transactions not being the first entry on cp_queue.

--- a/lwext4/ext4_journal.c
+++ b/lwext4/ext4_journal.c
@@ -1014,16 +1014,18 @@
 
 static void jbd_journal_flush_all_trans(struct jbd_journal *journal)
 {
-	struct jbd_trans *trans;
-	while ((trans = TAILQ_FIRST(&journal->cp_queue))) {
+	struct jbd_trans *trans, *tmp;
+	TAILQ_FOREACH_SAFE(trans, &journal->cp_queue, trans_node,
+			  tmp) {
 		if (!trans->data_cnt) {
 			TAILQ_REMOVE(&journal->cp_queue,
 					trans,
 					trans_node);
 			jbd_journal_skip_pure_revoke(journal, trans);
-		} else
+		} else {
+			ext4_assert(trans->data_cnt != trans->written_cnt);
 			jbd_journal_flush_trans(trans);
-
+		}
 	}
 }
 
@@ -1103,6 +1105,7 @@
 	 * once it has been committed.*/
 	trans->journal = journal;
 	trans->error = EOK;
+	TAILQ_INIT(&trans->buf_queue);
 	return trans;
 }
 
@@ -1157,9 +1160,11 @@
 	struct jbd_block_rec *block_rec;
 	block_rec = jbd_trans_block_rec_lookup(trans->journal, lba);
 	if (block_rec) {
+		LIST_REMOVE(block_rec, tbrec_node);
 		/* Data should be flushed to disk already. */
 		ext4_assert(!block_rec->buf);
 		/* Now this block record belongs to this transaction. */
+		LIST_INSERT_HEAD(&trans->tbrec_list, block_rec, tbrec_node);
 		block_rec->trans = trans;
 		return block_rec;
 	}
@@ -1170,6 +1175,7 @@
 	block_rec->lba = lba;
 	block_rec->buf = buf;
 	block_rec->trans = trans;
+	LIST_INSERT_HEAD(&trans->tbrec_list, block_rec, tbrec_node);
 	RB_INSERT(jbd_block, &trans->journal->block_rec_root, block_rec);
 	return block_rec;
 }
@@ -1176,12 +1182,13 @@
 
 static inline void
 jbd_trans_remove_block_rec(struct jbd_journal *journal,
-			   struct jbd_buf *jbd_buf)
+			   struct jbd_block_rec *block_rec,
+			   struct jbd_trans *trans)
 {
-	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) {
+	if (block_rec->trans == trans) {
+		LIST_REMOVE(block_rec, tbrec_node);
 		RB_REMOVE(jbd_block,
 				&journal->block_rec_root,
 				block_rec);
@@ -1289,6 +1296,7 @@
 {
 	struct jbd_buf *jbd_buf, *tmp;
 	struct jbd_revoke_rec *rec, *tmp2;
+	struct jbd_block_rec *block_rec, *tmp3;
 	struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
 	TAILQ_FOREACH_SAFE(jbd_buf, &trans->buf_queue, buf_node,
 			  tmp) {
@@ -1299,7 +1307,6 @@
 			ext4_block_set(fs->bdev, &jbd_buf->block);
 		}
 
-		jbd_trans_remove_block_rec(journal, jbd_buf);
 		TAILQ_REMOVE(&trans->buf_queue, jbd_buf, buf_node);
 		free(jbd_buf);
 	}
@@ -1308,6 +1315,10 @@
 		LIST_REMOVE(rec, revoke_node);
 		free(rec);
 	}
+	LIST_FOREACH_SAFE(block_rec, &trans->tbrec_list, tbrec_node,
+			  tmp3) {
+		jbd_trans_remove_block_rec(journal, block_rec, trans);
+	}
 
 	free(trans);
 }
@@ -1369,7 +1380,8 @@
 
 		/* The buffer has not been modified, just release
 		 * that jbd_buf. */
-		jbd_trans_remove_block_rec(journal, jbd_buf);
+		jbd_trans_remove_block_rec(journal,
+				jbd_buf->block_rec, trans);
 		trans->data_cnt--;
 
 		jbd_buf->block.buf->end_write = NULL;
@@ -1386,7 +1398,8 @@
 					   BC_DIRTY)) {
 			/* The buffer has not been modified, just release
 			 * that jbd_buf. */
-			jbd_trans_remove_block_rec(journal, jbd_buf);
+			jbd_trans_remove_block_rec(journal,
+					jbd_buf->block_rec, trans);
 			trans->data_cnt--;
 
 			jbd_buf->block.buf->end_write = NULL;
@@ -1595,7 +1608,6 @@
 
 	TAILQ_REMOVE(&trans->buf_queue, 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. */
@@ -1604,17 +1616,19 @@
 
 	trans->written_cnt++;
 	if (trans->written_cnt == trans->data_cnt) {
-		TAILQ_REMOVE(&journal->cp_queue, trans, trans_node);
-
+		/* If it is the first transaction on checkpoint queue,
+		 * we will shift the start of the journal to the next
+		 * transaction, and remove subsequent written
+		 * transactions from checkpoint queue until we find
+		 * an unwritten one. */
 		if (first_in_queue) {
 			journal->start = trans->start_iblock +
 				trans->alloc_blocks;
 			wrap(&journal->jbd_fs->sb, journal->start);
 			journal->trans_id = trans->trans_id + 1;
-		}
-		jbd_journal_free_trans(journal, trans, false);
+			TAILQ_REMOVE(&journal->cp_queue, trans, trans_node);
+			jbd_journal_free_trans(journal, trans, false);
 
-		if (first_in_queue) {
 			while ((trans = TAILQ_FIRST(&journal->cp_queue))) {
 				if (!trans->data_cnt) {
 					TAILQ_REMOVE(&journal->cp_queue,
@@ -1623,10 +1637,30 @@
 					jbd_journal_skip_pure_revoke(journal,
 								     trans);
 				} else {
-					journal->start = trans->start_iblock;
-					wrap(&journal->jbd_fs->sb, journal->start);
-					journal->trans_id = trans->trans_id;
-					break;
+					if (trans->data_cnt ==
+					    trans->written_cnt) {
+						journal->start =
+							trans->start_iblock +
+							trans->alloc_blocks;
+						wrap(&journal->jbd_fs->sb,
+							journal->start);
+						journal->trans_id =
+							trans->trans_id + 1;
+						TAILQ_REMOVE(&journal->cp_queue,
+							     trans,
+							     trans_node);
+						jbd_journal_free_trans(journal,
+								trans,
+								false);
+					} else {
+						journal->start =
+							trans->start_iblock;
+						wrap(&journal->jbd_fs->sb,
+							journal->start);
+						journal->trans_id =
+							trans->trans_id;
+						break;
+					}
 				}
 			}
 			jbd_journal_write_sb(journal);
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -1114,6 +1114,7 @@
 	struct ext4_buf *buf;
 	struct jbd_trans *trans;
 	RB_ENTRY(jbd_block_rec) block_rec_node;
+	LIST_ENTRY(jbd_block_rec) tbrec_node;
 };
 
 struct jbd_trans {
@@ -1129,6 +1130,7 @@
 
 	TAILQ_HEAD(jbd_trans_buf, jbd_buf) buf_queue;
 	LIST_HEAD(jbd_revoke_list, jbd_revoke_rec) revoke_list;
+	LIST_HEAD(jbd_trans_block_rec, jbd_block_rec) tbrec_list;
 	TAILQ_ENTRY(jbd_trans) trans_node;
 };