Merge pull request #49 from sirocyl/patch-1
[lwext4.git] / src / ext4_journal.c
index b4fe24a0e216f8d72a466af099f38560d82bde9d..9d998a1af047ad4ec52f591233e46f3efc6bb320 100644 (file)
  * @brief Journal handle functions
  */
 
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_misc.h"
-#include "ext4_errno.h"
-#include "ext4_debug.h"
-
-#include "ext4_fs.h"
-#include "ext4_super.h"
-#include "ext4_journal.h"
-#include "ext4_blockdev.h"
-#include "ext4_crc32.h"
-#include "ext4_journal.h"
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_misc.h>
+#include <ext4_errno.h>
+#include <ext4_debug.h>
+
+#include <ext4_fs.h>
+#include <ext4_super.h>
+#include <ext4_journal.h>
+#include <ext4_blockdev.h>
+#include <ext4_crc32.h>
+#include <ext4_journal.h>
 
 #include <string.h>
 #include <stdlib.h>
@@ -267,9 +267,9 @@ static uint32_t jbd_commit_csum(struct jbd_fs *jbd_fs,
        uint32_t checksum = 0;
 
        if (jbd_has_csum(&jbd_fs->sb)) {
-               uint32_t orig_checksum_type = header->chksum_type,
-                        orig_checksum_size = header->chksum_size,
-                        orig_checksum = header->chksum[0];
+               uint8_t orig_checksum_type = header->chksum_type,
+                        orig_checksum_size = header->chksum_size;
+               uint32_t orig_checksum = header->chksum[0];
                uint32_t block_size = jbd_get32(&jbd_fs->sb, blocksize);
                header->chksum_type = 0;
                header->chksum_size = 0;
@@ -458,25 +458,26 @@ int jbd_get_fs(struct ext4_fs *fs,
        rc = ext4_fs_get_inode_ref(fs,
                                   journal_ino,
                                   &jbd_fs->inode_ref);
-       if (rc != EOK) {
-               memset(jbd_fs, 0, sizeof(struct jbd_fs));
+       if (rc != EOK)
                return rc;
-       }
+
        rc = jbd_sb_read(jbd_fs, &jbd_fs->sb);
-       if (rc != EOK) {
-               memset(jbd_fs, 0, sizeof(struct jbd_fs));
-               ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
-               return rc;
-       }
+       if (rc != EOK)
+               goto Error;
+
        if (!jbd_verify_sb(&jbd_fs->sb)) {
-               memset(jbd_fs, 0, sizeof(struct jbd_fs));
-               ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
                rc = EIO;
+               goto Error;
        }
 
        if (rc == EOK)
                jbd_fs->bdev = fs->bdev;
 
+       return rc;
+Error:
+       ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
+       memset(jbd_fs, 0, sizeof(struct jbd_fs));
+
        return rc;
 }
 
@@ -1157,11 +1158,13 @@ static int jbd_iterate_log(struct jbd_fs *jbd_fs,
                        ext4_dbg(DEBUG_JBD, "Commit block: %" PRIu32", "
                                            "trans_id: %" PRIu32"\n",
                                            this_block, this_trans_id);
-                       /* This is the end of a transaction,
+                       /*
+                        * This is the end of a transaction,
                         * we may now proceed to the next transaction.
                         */
                        this_trans_id++;
-                       info->trans_cnt++;
+                       if (action == ACTION_SCAN)
+                               info->trans_cnt++;
                        break;
                case JBD_REVOKE_BLOCK:
                        if (!jbd_verify_meta_csum(jbd_fs, header)) {
@@ -1236,6 +1239,7 @@ int jbd_recover(struct jbd_fs *jbd_fs)
                        ext4_get32(&jbd_fs->inode_ref.fs->sb,
                                   features_incompatible);
                jbd_set32(&jbd_fs->sb, start, 0);
+               jbd_set32(&jbd_fs->sb, sequence, info.last_trans_id);
                features_incompatible &= ~EXT4_FINCOM_RECOVER;
                ext4_set32(&jbd_fs->inode_ref.fs->sb,
                           features_incompatible,
@@ -1267,7 +1271,6 @@ int jbd_journal_start(struct jbd_fs *jbd_fs,
        uint32_t features_incompatible =
                        ext4_get32(&jbd_fs->inode_ref.fs->sb,
                                   features_incompatible);
-       struct ext4_block block = EXT4_BLOCK_ZERO();
        features_incompatible |= EXT4_FINCOM_RECOVER;
        ext4_set32(&jbd_fs->inode_ref.fs->sb,
                        features_incompatible,
@@ -1280,26 +1283,16 @@ int jbd_journal_start(struct jbd_fs *jbd_fs,
        journal->first = jbd_get32(&jbd_fs->sb, first);
        journal->start = journal->first;
        journal->last = journal->first;
-       journal->trans_id = 1;
-       journal->alloc_trans_id = 1;
+       /*
+        * To invalidate any stale records we need to start from
+        * the checkpoint transaction ID of the previous journalling session
+        * plus 1.
+        */
+       journal->trans_id = jbd_get32(&jbd_fs->sb, sequence) + 1;
+       journal->alloc_trans_id = journal->trans_id;
 
        journal->block_size = jbd_get32(&jbd_fs->sb, blocksize);
 
-       r = jbd_block_get_noread(jbd_fs,
-                        &block,
-                        journal->start);
-       if (r != EOK) {
-               memset(journal, 0, sizeof(struct jbd_journal));
-               return r;
-       }
-       memset(block.data, 0, journal->block_size);
-       ext4_bcache_set_dirty(block.buf);
-       r = jbd_block_set(jbd_fs, &block);
-       if (r != EOK) {
-               memset(journal, 0, sizeof(struct jbd_journal));
-               return r;
-       }
-
        TAILQ_INIT(&journal->cp_queue);
        RB_INIT(&journal->block_rec_root);
        journal->jbd_fs = jbd_fs;
@@ -1338,9 +1331,10 @@ static void jbd_journal_flush_trans(struct jbd_trans *trans)
                      jbd_buf->block_rec->trans == trans)) {
                        int r;
                        struct ext4_block jbd_block = EXT4_BLOCK_ZERO();
-                       ext4_assert(jbd_block_get(journal->jbd_fs,
+                       r = jbd_block_get(journal->jbd_fs,
                                                &jbd_block,
-                                               jbd_buf->jbd_lba) == EOK);
+                                               jbd_buf->jbd_lba);
+                       ext4_assert(r == EOK);
                        memcpy(tmp_data, jbd_block.data,
                                        journal->block_size);
                        ext4_block_set(fs->bdev, &jbd_block);
@@ -1467,10 +1461,12 @@ static uint32_t jbd_journal_alloc_block(struct jbd_journal *journal,
        trans->alloc_blocks++;
        wrap(&journal->jbd_fs->sb, journal->last);
        
-       /* If there is no space left, flush all journalled
-        * blocks to disk first.*/
-       if (journal->last == journal->start)
-               jbd_journal_purge_cp_trans(journal, true, false);
+       /* If there is no space left, flush just one journalled
+        * transaction.*/
+       if (journal->last == journal->start) {
+               jbd_journal_purge_cp_trans(journal, true, true);
+               ext4_assert(journal->last != journal->start);
+       }
 
        return start_block;
 }
@@ -1559,12 +1555,15 @@ jbd_trans_finish_callback(struct jbd_journal *journal,
                                jbd_buf_dirty);
                if (jbd_buf) {
                        if (!revoke) {
-                               ext4_assert(ext4_block_get_noread(fs->bdev,
+                               int r;
+                               r = ext4_block_get_noread(fs->bdev,
                                                        &block,
-                                                       block_rec->lba) == EOK);
-                               ext4_assert(jbd_block_get(journal->jbd_fs,
+                                                       block_rec->lba);
+                               ext4_assert(r == EOK);
+                               r = jbd_block_get(journal->jbd_fs,
                                                        &jbd_block,
-                                                       jbd_buf->jbd_lba) == EOK);
+                                                       jbd_buf->jbd_lba);
+                               ext4_assert(r == EOK);
                                memcpy(block.data, jbd_block.data,
                                                journal->block_size);
 
@@ -1773,29 +1772,12 @@ static int jbd_trans_write_commit_block(struct jbd_trans *trans)
        int rc;
        struct ext4_block block;
        struct jbd_commit_header *header;
-       uint32_t commit_iblock, orig_commit_iblock;
+       uint32_t commit_iblock;
        struct jbd_journal *journal = trans->journal;
 
        commit_iblock = jbd_journal_alloc_block(journal, trans);
-       orig_commit_iblock = commit_iblock;
-       commit_iblock++;
-       wrap(&journal->jbd_fs->sb, commit_iblock);
 
-       /* To prevent accidental reference to stale journalling metadata. */
-       if (orig_commit_iblock < commit_iblock) {
-               rc = jbd_block_get_noread(journal->jbd_fs, &block, commit_iblock);
-               if (rc != EOK)
-                       return rc;
-
-               memset(block.data, 0, journal->block_size);
-               ext4_bcache_set_dirty(block.buf);
-               ext4_bcache_set_flag(block.buf, BC_TMP);
-               rc = jbd_block_set(journal->jbd_fs, &block);
-               if (rc != EOK)
-                       return rc;
-       }
-
-       rc = jbd_block_get_noread(journal->jbd_fs, &block, orig_commit_iblock);
+       rc = jbd_block_get_noread(journal->jbd_fs, &block, commit_iblock);
        if (rc != EOK)
                return rc;
 
@@ -1806,8 +1788,8 @@ static int jbd_trans_write_commit_block(struct jbd_trans *trans)
 
        if (JBD_HAS_INCOMPAT_FEATURE(&journal->jbd_fs->sb,
                                JBD_FEATURE_COMPAT_CHECKSUM)) {
-               jbd_set32(header, chksum_type, JBD_CRC32_CHKSUM);
-               jbd_set32(header, chksum_size, JBD_CRC32_CHKSUM_SIZE);
+               header->chksum_type = JBD_CRC32_CHKSUM;
+               header->chksum_size = JBD_CRC32_CHKSUM_SIZE;
                jbd_set32(header, chksum[0], trans->data_csum);
        }
        jbd_commit_csum_set(journal->jbd_fs, header);
@@ -1980,6 +1962,9 @@ again:
                data = data_block.data;
                memcpy(data, jbd_buf->block.data,
                        journal->block_size);
+               if (is_escape)
+                       ((struct jbd_bhdr *)data)->magic = 0;
+
                ext4_bcache_set_dirty(data_block.buf);
                ext4_bcache_set_flag(data_block.buf, BC_TMP);
                rc = jbd_block_set(journal->jbd_fs, &data_block);
@@ -2160,7 +2145,7 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
                        TAILQ_REMOVE(&journal->cp_queue, trans, trans_node);
                        jbd_journal_free_trans(journal, trans, false);
 
-                       jbd_journal_purge_cp_trans(journal, false, true);
+                       jbd_journal_purge_cp_trans(journal, false, false);
                        jbd_journal_write_sb(journal);
                        jbd_write_sb(journal->jbd_fs);
                }