ext4_journal: a more efficient way to track journalled blocks.
authorngkaho1234 <ngkaho1234@gmail.com>
Sat, 26 Dec 2015 12:58:57 +0000 (20:58 +0800)
committerngkaho1234 <ngkaho1234@gmail.com>
Sat, 26 Dec 2015 13:08:40 +0000 (21:08 +0800)
Now we build a RB-Tree in jbd_journal session to track journalled
blocks instead of the one in jbd_trans.

lwext4/ext4_journal.c
lwext4/ext4_types.h

index 7eea7d6045a8fb2b6640c34fb00abb9ccea9ddc6..f291722c76d54a18c67b7079760526ca88e99bb4 100644 (file)
@@ -982,6 +982,7 @@ int jbd_journal_start(struct jbd_fs *jbd_fs,
 
        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 @@ int jbd_journal_stop(struct jbd_journal *journal)
         * 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 @@ jbd_journal_new_trans(struct jbd_journal *journal)
        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,42 +1134,55 @@ int jbd_trans_get_access(struct jbd_journal *journal,
        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 = {
                .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 @@ int jbd_trans_set_block_dirty(struct jbd_trans *trans,
 
        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 @@ int jbd_trans_try_revoke_block(struct jbd_trans *trans,
                               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 @@ void jbd_journal_free_trans(struct jbd_journal *journal,
                        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 @@ void jbd_journal_free_trans(struct jbd_journal *journal,
                free(rec);
        }
 
-       jbd_trans_remove_block_recs(trans);
        free(trans);
 }
 
@@ -1534,6 +1566,8 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
                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. */
index 9220b291caca4116112a8ac296c34cd48fa5e705..45b203f4fe515de73185ba30cc142163f307963d 100644 (file)
@@ -1096,6 +1096,7 @@ struct jbd_fs {
 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_revoke_rec {
 
 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 @@ struct jbd_trans {
 
        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 @@ struct jbd_journal {
 
        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;
 };