bd8fbd8a13
JOURNAL is optional for EXT4 (and EXT3) filesystems, so add support for skipping it. This fixes corrupting EXT4 volumes without JOURNAL after using uboot's 'ext4write' command. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Lukasz Majewski <lukma@denx.de>
667 lines
17 KiB
C
667 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2011 - 2012 Samsung Electronics
|
|
* EXT4 filesystem implementation in Uboot by
|
|
* Uma Shankar <uma.shankar@samsung.com>
|
|
* Manjunatha C Achar <a.manjunatha@samsung.com>
|
|
*
|
|
* Journal data structures and headers for Journaling feature of ext4
|
|
* have been referred from JBD2 (Journaling Block device 2)
|
|
* implementation in Linux Kernel.
|
|
* Written by Stephen C. Tweedie <sct@redhat.com>
|
|
*
|
|
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <ext4fs.h>
|
|
#include <malloc.h>
|
|
#include <ext_common.h>
|
|
#include "ext4_common.h"
|
|
|
|
static struct revoke_blk_list *revk_blk_list;
|
|
static struct revoke_blk_list *prev_node;
|
|
static int first_node = true;
|
|
|
|
int gindex;
|
|
int gd_index;
|
|
int jrnl_blk_idx;
|
|
struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
|
|
struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
|
|
|
|
int ext4fs_init_journal(void)
|
|
{
|
|
int i;
|
|
char *temp = NULL;
|
|
struct ext_filesystem *fs = get_fs();
|
|
|
|
/* init globals */
|
|
revk_blk_list = NULL;
|
|
prev_node = NULL;
|
|
gindex = 0;
|
|
gd_index = 0;
|
|
jrnl_blk_idx = 1;
|
|
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
journal_ptr[i] = zalloc(sizeof(struct journal_log));
|
|
if (!journal_ptr[i])
|
|
goto fail;
|
|
dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
|
|
if (!dirty_block_ptr[i])
|
|
goto fail;
|
|
journal_ptr[i]->buf = NULL;
|
|
journal_ptr[i]->blknr = -1;
|
|
|
|
dirty_block_ptr[i]->buf = NULL;
|
|
dirty_block_ptr[i]->blknr = -1;
|
|
}
|
|
|
|
if (fs->blksz == 4096) {
|
|
temp = zalloc(fs->blksz);
|
|
if (!temp)
|
|
goto fail;
|
|
journal_ptr[gindex]->buf = zalloc(fs->blksz);
|
|
if (!journal_ptr[gindex]->buf)
|
|
goto fail;
|
|
ext4fs_devread(0, 0, fs->blksz, temp);
|
|
memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
|
|
memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
|
|
journal_ptr[gindex++]->blknr = 0;
|
|
free(temp);
|
|
} else {
|
|
journal_ptr[gindex]->buf = zalloc(fs->blksz);
|
|
if (!journal_ptr[gindex]->buf)
|
|
goto fail;
|
|
memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
|
|
journal_ptr[gindex++]->blknr = 1;
|
|
}
|
|
|
|
/* Check the file system state using journal super block */
|
|
if (ext4fs_check_journal_state(SCAN))
|
|
goto fail;
|
|
/* Check the file system state using journal super block */
|
|
if (ext4fs_check_journal_state(RECOVER))
|
|
goto fail;
|
|
|
|
return 0;
|
|
fail:
|
|
return -1;
|
|
}
|
|
|
|
void ext4fs_dump_metadata(void)
|
|
{
|
|
struct ext_filesystem *fs = get_fs();
|
|
int i;
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (dirty_block_ptr[i]->blknr == -1)
|
|
break;
|
|
put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
|
|
(uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
|
|
fs->blksz);
|
|
}
|
|
}
|
|
|
|
void ext4fs_free_journal(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (dirty_block_ptr[i]->blknr == -1)
|
|
break;
|
|
if (dirty_block_ptr[i]->buf)
|
|
free(dirty_block_ptr[i]->buf);
|
|
}
|
|
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (journal_ptr[i]->blknr == -1)
|
|
break;
|
|
if (journal_ptr[i]->buf)
|
|
free(journal_ptr[i]->buf);
|
|
}
|
|
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (journal_ptr[i])
|
|
free(journal_ptr[i]);
|
|
if (dirty_block_ptr[i])
|
|
free(dirty_block_ptr[i]);
|
|
}
|
|
gindex = 0;
|
|
gd_index = 0;
|
|
jrnl_blk_idx = 1;
|
|
}
|
|
|
|
int ext4fs_log_gdt(char *gd_table)
|
|
{
|
|
struct ext_filesystem *fs = get_fs();
|
|
short i;
|
|
long int var = fs->gdtable_blkno;
|
|
for (i = 0; i < fs->no_blk_pergdt; i++) {
|
|
journal_ptr[gindex]->buf = zalloc(fs->blksz);
|
|
if (!journal_ptr[gindex]->buf)
|
|
return -ENOMEM;
|
|
memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
|
|
gd_table += fs->blksz;
|
|
journal_ptr[gindex++]->blknr = var++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This function stores the backup copy of meta data in RAM
|
|
* journal_buffer -- Buffer containing meta data
|
|
* blknr -- Block number on disk of the meta data buffer
|
|
*/
|
|
int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
|
|
{
|
|
struct ext_filesystem *fs = get_fs();
|
|
short i;
|
|
|
|
if (!journal_buffer) {
|
|
printf("Invalid input arguments %s\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (journal_ptr[i]->blknr == -1)
|
|
break;
|
|
if (journal_ptr[i]->blknr == blknr)
|
|
return 0;
|
|
}
|
|
|
|
journal_ptr[gindex]->buf = zalloc(fs->blksz);
|
|
if (!journal_ptr[gindex]->buf)
|
|
return -ENOMEM;
|
|
|
|
memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
|
|
journal_ptr[gindex++]->blknr = blknr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This function stores the modified meta data in RAM
|
|
* metadata_buffer -- Buffer containing meta data
|
|
* blknr -- Block number on disk of the meta data buffer
|
|
*/
|
|
int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
|
|
{
|
|
struct ext_filesystem *fs = get_fs();
|
|
if (!metadata_buffer) {
|
|
printf("Invalid input arguments %s\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (dirty_block_ptr[gd_index]->buf)
|
|
assert(dirty_block_ptr[gd_index]->blknr == blknr);
|
|
else
|
|
dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
|
|
|
|
if (!dirty_block_ptr[gd_index]->buf)
|
|
return -ENOMEM;
|
|
memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
|
|
dirty_block_ptr[gd_index++]->blknr = blknr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void print_revoke_blks(char *revk_blk)
|
|
{
|
|
int offset;
|
|
int max;
|
|
long int blocknr;
|
|
struct journal_revoke_header_t *header;
|
|
|
|
if (revk_blk == NULL)
|
|
return;
|
|
|
|
header = (struct journal_revoke_header_t *) revk_blk;
|
|
offset = sizeof(struct journal_revoke_header_t);
|
|
max = be32_to_cpu(header->r_count);
|
|
printf("total bytes %d\n", max);
|
|
|
|
while (offset < max) {
|
|
blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
|
|
printf("revoke blknr is %ld\n", blocknr);
|
|
offset += 4;
|
|
}
|
|
}
|
|
|
|
static struct revoke_blk_list *_get_node(void)
|
|
{
|
|
struct revoke_blk_list *tmp_node;
|
|
tmp_node = zalloc(sizeof(struct revoke_blk_list));
|
|
if (tmp_node == NULL)
|
|
return NULL;
|
|
tmp_node->content = NULL;
|
|
tmp_node->next = NULL;
|
|
|
|
return tmp_node;
|
|
}
|
|
|
|
void ext4fs_push_revoke_blk(char *buffer)
|
|
{
|
|
struct revoke_blk_list *node = NULL;
|
|
struct ext_filesystem *fs = get_fs();
|
|
if (buffer == NULL) {
|
|
printf("buffer ptr is NULL\n");
|
|
return;
|
|
}
|
|
node = _get_node();
|
|
if (!node) {
|
|
printf("_get_node: malloc failed\n");
|
|
return;
|
|
}
|
|
|
|
node->content = zalloc(fs->blksz);
|
|
if (node->content == NULL)
|
|
return;
|
|
memcpy(node->content, buffer, fs->blksz);
|
|
|
|
if (first_node == true) {
|
|
revk_blk_list = node;
|
|
prev_node = node;
|
|
first_node = false;
|
|
} else {
|
|
prev_node->next = node;
|
|
prev_node = node;
|
|
}
|
|
}
|
|
|
|
void ext4fs_free_revoke_blks(void)
|
|
{
|
|
struct revoke_blk_list *tmp_node = revk_blk_list;
|
|
struct revoke_blk_list *next_node = NULL;
|
|
|
|
while (tmp_node != NULL) {
|
|
if (tmp_node->content)
|
|
free(tmp_node->content);
|
|
tmp_node = tmp_node->next;
|
|
}
|
|
|
|
tmp_node = revk_blk_list;
|
|
while (tmp_node != NULL) {
|
|
next_node = tmp_node->next;
|
|
free(tmp_node);
|
|
tmp_node = next_node;
|
|
}
|
|
|
|
revk_blk_list = NULL;
|
|
prev_node = NULL;
|
|
first_node = true;
|
|
}
|
|
|
|
int check_blknr_for_revoke(long int blknr, int sequence_no)
|
|
{
|
|
struct journal_revoke_header_t *header;
|
|
int offset;
|
|
int max;
|
|
long int blocknr;
|
|
char *revk_blk;
|
|
struct revoke_blk_list *tmp_revk_node = revk_blk_list;
|
|
while (tmp_revk_node != NULL) {
|
|
revk_blk = tmp_revk_node->content;
|
|
|
|
header = (struct journal_revoke_header_t *) revk_blk;
|
|
if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
|
|
offset = sizeof(struct journal_revoke_header_t);
|
|
max = be32_to_cpu(header->r_count);
|
|
|
|
while (offset < max) {
|
|
blocknr = be32_to_cpu(*((__be32 *)
|
|
(revk_blk + offset)));
|
|
if (blocknr == blknr)
|
|
goto found;
|
|
offset += 4;
|
|
}
|
|
}
|
|
tmp_revk_node = tmp_revk_node->next;
|
|
}
|
|
|
|
return -1;
|
|
|
|
found:
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This function parses the journal blocks and replays the
|
|
* suceessful transactions. A transaction is successfull
|
|
* if commit block is found for a descriptor block
|
|
* The tags in descriptor block contain the disk block
|
|
* numbers of the metadata to be replayed
|
|
*/
|
|
void recover_transaction(int prev_desc_logical_no)
|
|
{
|
|
struct ext2_inode inode_journal;
|
|
struct ext_filesystem *fs = get_fs();
|
|
struct journal_header_t *jdb;
|
|
long int blknr;
|
|
char *p_jdb;
|
|
int ofs, flags;
|
|
int i;
|
|
struct ext3_journal_block_tag *tag;
|
|
char *temp_buff = zalloc(fs->blksz);
|
|
char *metadata_buff = zalloc(fs->blksz);
|
|
if (!temp_buff || !metadata_buff)
|
|
goto fail;
|
|
i = prev_desc_logical_no;
|
|
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
|
|
(struct ext2_inode *)&inode_journal);
|
|
blknr = read_allocated_block((struct ext2_inode *)
|
|
&inode_journal, i, NULL);
|
|
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
|
|
temp_buff);
|
|
p_jdb = (char *)temp_buff;
|
|
jdb = (struct journal_header_t *) temp_buff;
|
|
ofs = sizeof(struct journal_header_t);
|
|
|
|
do {
|
|
tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
|
|
ofs += sizeof(struct ext3_journal_block_tag);
|
|
|
|
if (ofs > fs->blksz)
|
|
break;
|
|
|
|
flags = be32_to_cpu(tag->flags);
|
|
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
|
|
ofs += 16;
|
|
|
|
i++;
|
|
debug("\t\ttag %u\n", be32_to_cpu(tag->block));
|
|
if (revk_blk_list != NULL) {
|
|
if (check_blknr_for_revoke(be32_to_cpu(tag->block),
|
|
be32_to_cpu(jdb->h_sequence)) == 0)
|
|
continue;
|
|
}
|
|
blknr = read_allocated_block(&inode_journal, i, NULL);
|
|
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
|
|
fs->blksz, metadata_buff);
|
|
put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
|
|
metadata_buff, (uint32_t) fs->blksz);
|
|
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
|
|
fail:
|
|
free(temp_buff);
|
|
free(metadata_buff);
|
|
}
|
|
|
|
void print_jrnl_status(int recovery_flag)
|
|
{
|
|
if (recovery_flag == RECOVER)
|
|
printf("Journal Recovery Completed\n");
|
|
else
|
|
printf("Journal Scan Completed\n");
|
|
}
|
|
|
|
int ext4fs_check_journal_state(int recovery_flag)
|
|
{
|
|
int i;
|
|
int DB_FOUND = NO;
|
|
long int blknr;
|
|
int transaction_state = TRANSACTION_COMPLETE;
|
|
int prev_desc_logical_no = 0;
|
|
int curr_desc_logical_no = 0;
|
|
int ofs, flags;
|
|
struct ext2_inode inode_journal;
|
|
struct journal_superblock_t *jsb = NULL;
|
|
struct journal_header_t *jdb = NULL;
|
|
char *p_jdb = NULL;
|
|
struct ext3_journal_block_tag *tag = NULL;
|
|
char *temp_buff = NULL;
|
|
char *temp_buff1 = NULL;
|
|
struct ext_filesystem *fs = get_fs();
|
|
|
|
temp_buff = zalloc(fs->blksz);
|
|
if (!temp_buff)
|
|
return -ENOMEM;
|
|
temp_buff1 = zalloc(fs->blksz);
|
|
if (!temp_buff1) {
|
|
free(temp_buff);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
|
|
blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
|
|
NULL);
|
|
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
|
|
temp_buff);
|
|
jsb = (struct journal_superblock_t *) temp_buff;
|
|
|
|
if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
|
|
if (recovery_flag == RECOVER)
|
|
printf("Recovery required\n");
|
|
} else {
|
|
if (recovery_flag == RECOVER)
|
|
printf("File System is consistent\n");
|
|
goto end;
|
|
}
|
|
|
|
if (be32_to_cpu(jsb->s_start) == 0)
|
|
goto end;
|
|
|
|
if (!(jsb->s_feature_compat &
|
|
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
|
|
jsb->s_feature_compat |=
|
|
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
|
|
|
|
i = be32_to_cpu(jsb->s_first);
|
|
while (1) {
|
|
blknr = read_allocated_block(&inode_journal, i, NULL);
|
|
memset(temp_buff1, '\0', fs->blksz);
|
|
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
|
|
0, fs->blksz, temp_buff1);
|
|
jdb = (struct journal_header_t *) temp_buff1;
|
|
|
|
if (be32_to_cpu(jdb->h_blocktype) ==
|
|
EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
|
|
if (be32_to_cpu(jdb->h_sequence) !=
|
|
be32_to_cpu(jsb->s_sequence)) {
|
|
print_jrnl_status(recovery_flag);
|
|
break;
|
|
}
|
|
|
|
curr_desc_logical_no = i;
|
|
if (transaction_state == TRANSACTION_COMPLETE)
|
|
transaction_state = TRANSACTION_RUNNING;
|
|
else
|
|
return -1;
|
|
p_jdb = (char *)temp_buff1;
|
|
ofs = sizeof(struct journal_header_t);
|
|
do {
|
|
tag = (struct ext3_journal_block_tag *)
|
|
(p_jdb + ofs);
|
|
ofs += sizeof(struct ext3_journal_block_tag);
|
|
if (ofs > fs->blksz)
|
|
break;
|
|
flags = be32_to_cpu(tag->flags);
|
|
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
|
|
ofs += 16;
|
|
i++;
|
|
debug("\t\ttag %u\n", be32_to_cpu(tag->block));
|
|
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
|
|
i++;
|
|
DB_FOUND = YES;
|
|
} else if (be32_to_cpu(jdb->h_blocktype) ==
|
|
EXT3_JOURNAL_COMMIT_BLOCK) {
|
|
if (be32_to_cpu(jdb->h_sequence) !=
|
|
be32_to_cpu(jsb->s_sequence)) {
|
|
print_jrnl_status(recovery_flag);
|
|
break;
|
|
}
|
|
|
|
if (transaction_state == TRANSACTION_RUNNING ||
|
|
(DB_FOUND == NO)) {
|
|
transaction_state = TRANSACTION_COMPLETE;
|
|
i++;
|
|
jsb->s_sequence =
|
|
cpu_to_be32(be32_to_cpu(
|
|
jsb->s_sequence) + 1);
|
|
}
|
|
prev_desc_logical_no = curr_desc_logical_no;
|
|
if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
|
|
recover_transaction(prev_desc_logical_no);
|
|
|
|
DB_FOUND = NO;
|
|
} else if (be32_to_cpu(jdb->h_blocktype) ==
|
|
EXT3_JOURNAL_REVOKE_BLOCK) {
|
|
if (be32_to_cpu(jdb->h_sequence) !=
|
|
be32_to_cpu(jsb->s_sequence)) {
|
|
print_jrnl_status(recovery_flag);
|
|
break;
|
|
}
|
|
if (recovery_flag == SCAN)
|
|
ext4fs_push_revoke_blk((char *)jdb);
|
|
i++;
|
|
} else {
|
|
debug("Else Case\n");
|
|
if (be32_to_cpu(jdb->h_sequence) !=
|
|
be32_to_cpu(jsb->s_sequence)) {
|
|
print_jrnl_status(recovery_flag);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
end:
|
|
if (recovery_flag == RECOVER) {
|
|
uint32_t new_feature_incompat;
|
|
jsb->s_start = cpu_to_be32(1);
|
|
jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
|
|
/* get the superblock */
|
|
ext4_read_superblock((char *)fs->sb);
|
|
new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
|
|
new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
|
|
fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
|
|
|
|
/* Update the super block */
|
|
put_ext4((uint64_t) (SUPERBLOCK_SIZE),
|
|
(struct ext2_sblock *)fs->sb,
|
|
(uint32_t) SUPERBLOCK_SIZE);
|
|
ext4_read_superblock((char *)fs->sb);
|
|
|
|
blknr = read_allocated_block(&inode_journal,
|
|
EXT2_JOURNAL_SUPERBLOCK, NULL);
|
|
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
|
|
(struct journal_superblock_t *)temp_buff,
|
|
(uint32_t) fs->blksz);
|
|
ext4fs_free_revoke_blks();
|
|
}
|
|
free(temp_buff);
|
|
free(temp_buff1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void update_descriptor_block(long int blknr)
|
|
{
|
|
int i;
|
|
long int jsb_blknr;
|
|
struct journal_header_t jdb;
|
|
struct ext3_journal_block_tag tag;
|
|
struct ext2_inode inode_journal;
|
|
struct journal_superblock_t *jsb = NULL;
|
|
char *buf = NULL;
|
|
char *temp = NULL;
|
|
struct ext_filesystem *fs = get_fs();
|
|
char *temp_buff = zalloc(fs->blksz);
|
|
if (!temp_buff)
|
|
return;
|
|
|
|
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
|
|
jsb_blknr = read_allocated_block(&inode_journal,
|
|
EXT2_JOURNAL_SUPERBLOCK, NULL);
|
|
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
|
|
temp_buff);
|
|
jsb = (struct journal_superblock_t *) temp_buff;
|
|
|
|
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
|
|
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
|
|
jdb.h_sequence = jsb->s_sequence;
|
|
buf = zalloc(fs->blksz);
|
|
if (!buf) {
|
|
free(temp_buff);
|
|
return;
|
|
}
|
|
temp = buf;
|
|
memcpy(buf, &jdb, sizeof(struct journal_header_t));
|
|
temp += sizeof(struct journal_header_t);
|
|
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (journal_ptr[i]->blknr == -1)
|
|
break;
|
|
|
|
tag.block = cpu_to_be32(journal_ptr[i]->blknr);
|
|
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
|
|
memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
|
|
temp = temp + sizeof(struct ext3_journal_block_tag);
|
|
}
|
|
|
|
tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
|
|
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
|
|
memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
|
|
sizeof(struct ext3_journal_block_tag));
|
|
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
|
|
|
|
free(temp_buff);
|
|
free(buf);
|
|
}
|
|
|
|
static void update_commit_block(long int blknr)
|
|
{
|
|
struct journal_header_t jdb;
|
|
struct ext_filesystem *fs = get_fs();
|
|
char *buf = NULL;
|
|
struct ext2_inode inode_journal;
|
|
struct journal_superblock_t *jsb;
|
|
long int jsb_blknr;
|
|
char *temp_buff = zalloc(fs->blksz);
|
|
if (!temp_buff)
|
|
return;
|
|
|
|
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
|
|
&inode_journal);
|
|
jsb_blknr = read_allocated_block(&inode_journal,
|
|
EXT2_JOURNAL_SUPERBLOCK, NULL);
|
|
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
|
|
temp_buff);
|
|
jsb = (struct journal_superblock_t *) temp_buff;
|
|
|
|
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
|
|
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
|
|
jdb.h_sequence = jsb->s_sequence;
|
|
buf = zalloc(fs->blksz);
|
|
if (!buf) {
|
|
free(temp_buff);
|
|
return;
|
|
}
|
|
memcpy(buf, &jdb, sizeof(struct journal_header_t));
|
|
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
|
|
|
|
free(temp_buff);
|
|
free(buf);
|
|
}
|
|
|
|
void ext4fs_update_journal(void)
|
|
{
|
|
struct ext2_inode inode_journal;
|
|
struct ext_filesystem *fs = get_fs();
|
|
long int blknr;
|
|
int i;
|
|
|
|
if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
|
|
return;
|
|
|
|
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
|
|
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
|
|
update_descriptor_block(blknr);
|
|
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
|
|
if (journal_ptr[i]->blknr == -1)
|
|
break;
|
|
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
|
|
NULL);
|
|
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
|
|
journal_ptr[i]->buf, fs->blksz);
|
|
}
|
|
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
|
|
update_commit_block(blknr);
|
|
printf("update journal finished\n");
|
|
}
|