ref: e0720c64b73449e31a960d09e2f06cfce3b2bdeb
parent: 13b86cb3c22b6a08638bd87c4b7f31e070d60dc1
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Sat Nov 28 23:09:27 EST 2015
ext4_journal: initial journal replay support.
--- a/lwext4/ext4_journal.c
+++ b/lwext4/ext4_journal.c
@@ -29,6 +29,11 @@
RB_HEAD(jbd_revoke, revoke_entry) revoke_root;
};
+struct replay_arg {
+ struct recover_info *info;
+ uint32_t *this_block;
+};
+
static int
jbd_revoke_entry_cmp(struct revoke_entry *a, struct revoke_entry *b)
{
@@ -120,6 +125,9 @@
int jbd_put_fs(struct jbd_fs *jbd_fs)
{
int rc;
+ if (jbd_fs->dirty)
+ jbd_sb_write(jbd_fs, &jbd_fs->sb);
+
rc = ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
return rc;
}
@@ -324,6 +332,47 @@
return RB_FIND(jbd_revoke, &info->revoke_root, &tmp);
}
+static void jbd_replay_block_tags(struct jbd_fs *jbd_fs,
+ ext4_fsblk_t block,
+ uint8_t *uuid __unused,
+ void *__arg)
+{
+ int r;
+ struct replay_arg *arg = __arg;
+ struct recover_info *info = arg->info;
+ uint32_t *this_block = arg->this_block;
+ struct revoke_entry *revoke_entry;
+ struct ext4_block journal_block, ext4_block;
+ ext4_dbg(DEBUG_JBD,
+ "Replaying block in block_tag: %" PRIu64 "\n",
+ block);
+ (*this_block)++;
+
+ revoke_entry = jbd_revoke_entry_lookup(info, block);
+ if (revoke_entry)
+ return;
+
+ r = jbd_block_get(jbd_fs, &journal_block, *this_block);
+ if (r != EOK)
+ return;
+
+ r = ext4_block_get_noread(jbd_fs->bdev, &ext4_block, block);
+ if (r != EOK) {
+ jbd_block_set(jbd_fs, &journal_block);
+ return;
+ }
+
+ memcpy(ext4_block.data,
+ journal_block.data,
+ jbd_get32(&jbd_fs->sb, blocksize));
+
+ ext4_block.dirty = true;
+ ext4_block_set(jbd_fs->bdev, &ext4_block);
+ jbd_block_set(jbd_fs, &journal_block);
+
+ return;
+}
+
static void jbd_add_revoke_block_tags(struct recover_info *info,
ext4_fsblk_t block)
{
@@ -412,6 +461,18 @@
iblock);
}
+static void jbd_replay_descriptor_block(struct jbd_fs *jbd_fs,
+ struct jbd_bhdr *header,
+ struct replay_arg *arg)
+{
+ jbd_iterate_block_table(jbd_fs,
+ header + 1,
+ jbd_get32(&jbd_fs->sb, blocksize) -
+ sizeof(struct jbd_bhdr),
+ jbd_replay_block_tags,
+ arg);
+}
+
int jbd_iterate_log(struct jbd_fs *jbd_fs,
struct recover_info *info,
int action)
@@ -465,6 +526,14 @@
if (action == ACTION_SCAN)
jbd_debug_descriptor_block(jbd_fs,
header, &this_block);
+ else if (action == ACTION_RECOVER) {
+ struct replay_arg replay_arg;
+ replay_arg.info = info;
+ replay_arg.this_block = &this_block;
+ jbd_replay_descriptor_block(jbd_fs,
+ header, &replay_arg);
+ }
+
break;
case JBD_COMMIT_BLOCK:
ext4_dbg(DEBUG_JBD, "Commit block: %u, "
@@ -520,6 +589,14 @@
return r;
r = jbd_iterate_log(jbd_fs, &info, ACTION_REVOKE);
+ if (r != EOK)
+ return r;
+
+ r = jbd_iterate_log(jbd_fs, &info, ACTION_RECOVER);
+ if (r == EOK) {
+ jbd_set32(&jbd_fs->sb, start, 0);
+ jbd_fs->dirty = true;
+ }
jbd_destroy_revoke_tree(&info);
return r;
}
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -1089,6 +1089,8 @@
struct ext4_blockdev *bdev;
struct ext4_inode_ref inode_ref;
struct jbd_sb sb;
+
+ bool dirty;
};
/*****************************************************************************/