ref: d7284d15564fc5cb4123671ab343480984dbcad2
parent: c5ea10075711ba4814084b7ef3bc56c537fd91b0
author: ngkaho1234 <[email protected]>
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;
};