| // 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 <blk.h> | |
| #include <ext4fs.h> | |
| #include <log.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; | |
| free(dirty_block_ptr[i]->buf); | |
| } | |
| for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { | |
| if (journal_ptr[i]->blknr == -1) | |
| break; | |
| free(journal_ptr[i]->buf); | |
| } | |
| for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { | |
| free(journal_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) { | |
| 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(); | |
| if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) | |
| return 0; | |
| 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) | |
| log_debug("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"); | |
| } |