1ed34f34dSUma Shankar /* 2ed34f34dSUma Shankar * (C) Copyright 2011 - 2012 Samsung Electronics 3ed34f34dSUma Shankar * EXT4 filesystem implementation in Uboot by 4ed34f34dSUma Shankar * Uma Shankar <uma.shankar@samsung.com> 5ed34f34dSUma Shankar * Manjunatha C Achar <a.manjunatha@samsung.com> 6ed34f34dSUma Shankar * 7ed34f34dSUma Shankar * Journal data structures and headers for Journaling feature of ext4 8ed34f34dSUma Shankar * have been referred from JBD2 (Journaling Block device 2) 9ed34f34dSUma Shankar * implementation in Linux Kernel. 10ed34f34dSUma Shankar * Written by Stephen C. Tweedie <sct@redhat.com> 11ed34f34dSUma Shankar * 12ed34f34dSUma Shankar * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved 13ed34f34dSUma Shankar * This file is part of the Linux kernel and is made available under 14ed34f34dSUma Shankar * the terms of the GNU General Public License, version 2, or at your 15ed34f34dSUma Shankar * option, any later version, incorporated herein by reference. 16ed34f34dSUma Shankar * 17ed34f34dSUma Shankar * This program is free software; you can redistribute it and/or modify 18ed34f34dSUma Shankar * it under the terms of the GNU General Public License as published by 19ed34f34dSUma Shankar * the Free Software Foundation; either version 2 of the License, or 20ed34f34dSUma Shankar * (at your option) any later version. 21ed34f34dSUma Shankar * 22ed34f34dSUma Shankar * This program is distributed in the hope that it will be useful, 23ed34f34dSUma Shankar * but WITHOUT ANY WARRANTY; without even the implied warranty of 24ed34f34dSUma Shankar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25ed34f34dSUma Shankar * GNU General Public License for more details. 26ed34f34dSUma Shankar * 27ed34f34dSUma Shankar * You should have received a copy of the GNU General Public License 28ed34f34dSUma Shankar * along with this program; if not, write to the Free Software 29ed34f34dSUma Shankar * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 30ed34f34dSUma Shankar */ 31ed34f34dSUma Shankar 32ed34f34dSUma Shankar #include <common.h> 33ed34f34dSUma Shankar #include <ext4fs.h> 34ed34f34dSUma Shankar #include <malloc.h> 35ed34f34dSUma Shankar #include <ext_common.h> 36ed34f34dSUma Shankar #include "ext4_common.h" 37ed34f34dSUma Shankar 38ed34f34dSUma Shankar static struct revoke_blk_list *revk_blk_list; 39ed34f34dSUma Shankar static struct revoke_blk_list *prev_node; 40472d5460SYork Sun static int first_node = true; 41ed34f34dSUma Shankar 42ed34f34dSUma Shankar int gindex; 43ed34f34dSUma Shankar int gd_index; 44ed34f34dSUma Shankar int jrnl_blk_idx; 45ed34f34dSUma Shankar struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES]; 46ed34f34dSUma Shankar struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES]; 47ed34f34dSUma Shankar 48ed34f34dSUma Shankar int ext4fs_init_journal(void) 49ed34f34dSUma Shankar { 50ed34f34dSUma Shankar int i; 51ed34f34dSUma Shankar char *temp = NULL; 52ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 53ed34f34dSUma Shankar 54ed34f34dSUma Shankar /* init globals */ 55ed34f34dSUma Shankar revk_blk_list = NULL; 56ed34f34dSUma Shankar prev_node = NULL; 57ed34f34dSUma Shankar gindex = 0; 58ed34f34dSUma Shankar gd_index = 0; 59ed34f34dSUma Shankar jrnl_blk_idx = 1; 60ed34f34dSUma Shankar 61ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 62ed34f34dSUma Shankar journal_ptr[i] = zalloc(sizeof(struct journal_log)); 63ed34f34dSUma Shankar if (!journal_ptr[i]) 64ed34f34dSUma Shankar goto fail; 65ed34f34dSUma Shankar dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks)); 66ed34f34dSUma Shankar if (!dirty_block_ptr[i]) 67ed34f34dSUma Shankar goto fail; 68ed34f34dSUma Shankar journal_ptr[i]->buf = NULL; 69ed34f34dSUma Shankar journal_ptr[i]->blknr = -1; 70ed34f34dSUma Shankar 71ed34f34dSUma Shankar dirty_block_ptr[i]->buf = NULL; 72ed34f34dSUma Shankar dirty_block_ptr[i]->blknr = -1; 73ed34f34dSUma Shankar } 74ed34f34dSUma Shankar 75ed34f34dSUma Shankar if (fs->blksz == 4096) { 76ed34f34dSUma Shankar temp = zalloc(fs->blksz); 77ed34f34dSUma Shankar if (!temp) 78ed34f34dSUma Shankar goto fail; 79ed34f34dSUma Shankar journal_ptr[gindex]->buf = zalloc(fs->blksz); 80ed34f34dSUma Shankar if (!journal_ptr[gindex]->buf) 81ed34f34dSUma Shankar goto fail; 82ed34f34dSUma Shankar ext4fs_devread(0, 0, fs->blksz, temp); 83ed34f34dSUma Shankar memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE); 84ed34f34dSUma Shankar memcpy(journal_ptr[gindex]->buf, temp, fs->blksz); 85ed34f34dSUma Shankar journal_ptr[gindex++]->blknr = 0; 86ed34f34dSUma Shankar free(temp); 87ed34f34dSUma Shankar } else { 88ed34f34dSUma Shankar journal_ptr[gindex]->buf = zalloc(fs->blksz); 89ed34f34dSUma Shankar if (!journal_ptr[gindex]->buf) 90ed34f34dSUma Shankar goto fail; 91ed34f34dSUma Shankar memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE); 92ed34f34dSUma Shankar journal_ptr[gindex++]->blknr = 1; 93ed34f34dSUma Shankar } 94ed34f34dSUma Shankar 95ed34f34dSUma Shankar /* Check the file system state using journal super block */ 96ed34f34dSUma Shankar if (ext4fs_check_journal_state(SCAN)) 97ed34f34dSUma Shankar goto fail; 98ed34f34dSUma Shankar /* Check the file system state using journal super block */ 99ed34f34dSUma Shankar if (ext4fs_check_journal_state(RECOVER)) 100ed34f34dSUma Shankar goto fail; 101ed34f34dSUma Shankar 102ed34f34dSUma Shankar return 0; 103ed34f34dSUma Shankar fail: 104ed34f34dSUma Shankar return -1; 105ed34f34dSUma Shankar } 106ed34f34dSUma Shankar 107ed34f34dSUma Shankar void ext4fs_dump_metadata(void) 108ed34f34dSUma Shankar { 109ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 110ed34f34dSUma Shankar int i; 111ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 112ed34f34dSUma Shankar if (dirty_block_ptr[i]->blknr == -1) 113ed34f34dSUma Shankar break; 114ed34f34dSUma Shankar put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr * 115ed34f34dSUma Shankar (uint64_t)fs->blksz), dirty_block_ptr[i]->buf, 116ed34f34dSUma Shankar fs->blksz); 117ed34f34dSUma Shankar } 118ed34f34dSUma Shankar } 119ed34f34dSUma Shankar 120ed34f34dSUma Shankar void ext4fs_free_journal(void) 121ed34f34dSUma Shankar { 122ed34f34dSUma Shankar int i; 123ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 124ed34f34dSUma Shankar if (dirty_block_ptr[i]->blknr == -1) 125ed34f34dSUma Shankar break; 126ed34f34dSUma Shankar if (dirty_block_ptr[i]->buf) 127ed34f34dSUma Shankar free(dirty_block_ptr[i]->buf); 128ed34f34dSUma Shankar } 129ed34f34dSUma Shankar 130ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 131ed34f34dSUma Shankar if (journal_ptr[i]->blknr == -1) 132ed34f34dSUma Shankar break; 133ed34f34dSUma Shankar if (journal_ptr[i]->buf) 134ed34f34dSUma Shankar free(journal_ptr[i]->buf); 135ed34f34dSUma Shankar } 136ed34f34dSUma Shankar 137ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 138ed34f34dSUma Shankar if (journal_ptr[i]) 139ed34f34dSUma Shankar free(journal_ptr[i]); 140ed34f34dSUma Shankar if (dirty_block_ptr[i]) 141ed34f34dSUma Shankar free(dirty_block_ptr[i]); 142ed34f34dSUma Shankar } 143ed34f34dSUma Shankar gindex = 0; 144ed34f34dSUma Shankar gd_index = 0; 145ed34f34dSUma Shankar jrnl_blk_idx = 1; 146ed34f34dSUma Shankar } 147ed34f34dSUma Shankar 148ed34f34dSUma Shankar int ext4fs_log_gdt(char *gd_table) 149ed34f34dSUma Shankar { 150ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 151ed34f34dSUma Shankar short i; 152ed34f34dSUma Shankar long int var = fs->gdtable_blkno; 153ed34f34dSUma Shankar for (i = 0; i < fs->no_blk_pergdt; i++) { 154ed34f34dSUma Shankar journal_ptr[gindex]->buf = zalloc(fs->blksz); 155ed34f34dSUma Shankar if (!journal_ptr[gindex]->buf) 156ed34f34dSUma Shankar return -ENOMEM; 157ed34f34dSUma Shankar memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz); 158ed34f34dSUma Shankar gd_table += fs->blksz; 159ed34f34dSUma Shankar journal_ptr[gindex++]->blknr = var++; 160ed34f34dSUma Shankar } 161ed34f34dSUma Shankar 162ed34f34dSUma Shankar return 0; 163ed34f34dSUma Shankar } 164ed34f34dSUma Shankar 165ed34f34dSUma Shankar /* 166ed34f34dSUma Shankar * This function stores the backup copy of meta data in RAM 167ed34f34dSUma Shankar * journal_buffer -- Buffer containing meta data 168ed34f34dSUma Shankar * blknr -- Block number on disk of the meta data buffer 169ed34f34dSUma Shankar */ 170ed34f34dSUma Shankar int ext4fs_log_journal(char *journal_buffer, long int blknr) 171ed34f34dSUma Shankar { 172ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 173ed34f34dSUma Shankar short i; 174ed34f34dSUma Shankar 175ed34f34dSUma Shankar if (!journal_buffer) { 176ed34f34dSUma Shankar printf("Invalid input arguments %s\n", __func__); 177ed34f34dSUma Shankar return -EINVAL; 178ed34f34dSUma Shankar } 179ed34f34dSUma Shankar 180ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 181ed34f34dSUma Shankar if (journal_ptr[i]->blknr == -1) 182ed34f34dSUma Shankar break; 183ed34f34dSUma Shankar if (journal_ptr[i]->blknr == blknr) 184ed34f34dSUma Shankar return 0; 185ed34f34dSUma Shankar } 186ed34f34dSUma Shankar 187ed34f34dSUma Shankar journal_ptr[gindex]->buf = zalloc(fs->blksz); 188ed34f34dSUma Shankar if (!journal_ptr[gindex]->buf) 189ed34f34dSUma Shankar return -ENOMEM; 190ed34f34dSUma Shankar 191ed34f34dSUma Shankar memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz); 192ed34f34dSUma Shankar journal_ptr[gindex++]->blknr = blknr; 193ed34f34dSUma Shankar 194ed34f34dSUma Shankar return 0; 195ed34f34dSUma Shankar } 196ed34f34dSUma Shankar 197ed34f34dSUma Shankar /* 198ed34f34dSUma Shankar * This function stores the modified meta data in RAM 199ed34f34dSUma Shankar * metadata_buffer -- Buffer containing meta data 200ed34f34dSUma Shankar * blknr -- Block number on disk of the meta data buffer 201ed34f34dSUma Shankar */ 202ed34f34dSUma Shankar int ext4fs_put_metadata(char *metadata_buffer, long int blknr) 203ed34f34dSUma Shankar { 204ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 205ed34f34dSUma Shankar if (!metadata_buffer) { 206ed34f34dSUma Shankar printf("Invalid input arguments %s\n", __func__); 207ed34f34dSUma Shankar return -EINVAL; 208ed34f34dSUma Shankar } 209ed34f34dSUma Shankar dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz); 210ed34f34dSUma Shankar if (!dirty_block_ptr[gd_index]->buf) 211ed34f34dSUma Shankar return -ENOMEM; 212ed34f34dSUma Shankar memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz); 213ed34f34dSUma Shankar dirty_block_ptr[gd_index++]->blknr = blknr; 214ed34f34dSUma Shankar 215ed34f34dSUma Shankar return 0; 216ed34f34dSUma Shankar } 217ed34f34dSUma Shankar 218ed34f34dSUma Shankar void print_revoke_blks(char *revk_blk) 219ed34f34dSUma Shankar { 220ed34f34dSUma Shankar int offset; 221ed34f34dSUma Shankar int max; 222ed34f34dSUma Shankar long int blocknr; 223ed34f34dSUma Shankar struct journal_revoke_header_t *header; 224ed34f34dSUma Shankar 225ed34f34dSUma Shankar if (revk_blk == NULL) 226ed34f34dSUma Shankar return; 227ed34f34dSUma Shankar 228ed34f34dSUma Shankar header = (struct journal_revoke_header_t *) revk_blk; 229ed34f34dSUma Shankar offset = sizeof(struct journal_revoke_header_t); 230ed34f34dSUma Shankar max = be32_to_cpu(header->r_count); 231ed34f34dSUma Shankar printf("total bytes %d\n", max); 232ed34f34dSUma Shankar 233ed34f34dSUma Shankar while (offset < max) { 234ed34f34dSUma Shankar blocknr = be32_to_cpu(*((long int *)(revk_blk + offset))); 235ed34f34dSUma Shankar printf("revoke blknr is %ld\n", blocknr); 236ed34f34dSUma Shankar offset += 4; 237ed34f34dSUma Shankar } 238ed34f34dSUma Shankar } 239ed34f34dSUma Shankar 240ed34f34dSUma Shankar static struct revoke_blk_list *_get_node(void) 241ed34f34dSUma Shankar { 242ed34f34dSUma Shankar struct revoke_blk_list *tmp_node; 243ed34f34dSUma Shankar tmp_node = zalloc(sizeof(struct revoke_blk_list)); 244ed34f34dSUma Shankar if (tmp_node == NULL) 245ed34f34dSUma Shankar return NULL; 246ed34f34dSUma Shankar tmp_node->content = NULL; 247ed34f34dSUma Shankar tmp_node->next = NULL; 248ed34f34dSUma Shankar 249ed34f34dSUma Shankar return tmp_node; 250ed34f34dSUma Shankar } 251ed34f34dSUma Shankar 252ed34f34dSUma Shankar void ext4fs_push_revoke_blk(char *buffer) 253ed34f34dSUma Shankar { 254ed34f34dSUma Shankar struct revoke_blk_list *node = NULL; 255ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 256ed34f34dSUma Shankar if (buffer == NULL) { 257ed34f34dSUma Shankar printf("buffer ptr is NULL\n"); 258ed34f34dSUma Shankar return; 259ed34f34dSUma Shankar } 260ed34f34dSUma Shankar node = _get_node(); 261ed34f34dSUma Shankar if (!node) { 262ed34f34dSUma Shankar printf("_get_node: malloc failed\n"); 263ed34f34dSUma Shankar return; 264ed34f34dSUma Shankar } 265ed34f34dSUma Shankar 266ed34f34dSUma Shankar node->content = zalloc(fs->blksz); 267ed34f34dSUma Shankar if (node->content == NULL) 268ed34f34dSUma Shankar return; 269ed34f34dSUma Shankar memcpy(node->content, buffer, fs->blksz); 270ed34f34dSUma Shankar 271472d5460SYork Sun if (first_node == true) { 272ed34f34dSUma Shankar revk_blk_list = node; 273ed34f34dSUma Shankar prev_node = node; 274472d5460SYork Sun first_node = false; 275ed34f34dSUma Shankar } else { 276ed34f34dSUma Shankar prev_node->next = node; 277ed34f34dSUma Shankar prev_node = node; 278ed34f34dSUma Shankar } 279ed34f34dSUma Shankar } 280ed34f34dSUma Shankar 281ed34f34dSUma Shankar void ext4fs_free_revoke_blks(void) 282ed34f34dSUma Shankar { 283ed34f34dSUma Shankar struct revoke_blk_list *tmp_node = revk_blk_list; 284ed34f34dSUma Shankar struct revoke_blk_list *next_node = NULL; 285ed34f34dSUma Shankar 286ed34f34dSUma Shankar while (tmp_node != NULL) { 287ed34f34dSUma Shankar if (tmp_node->content) 288ed34f34dSUma Shankar free(tmp_node->content); 289ed34f34dSUma Shankar tmp_node = tmp_node->next; 290ed34f34dSUma Shankar } 291ed34f34dSUma Shankar 292ed34f34dSUma Shankar tmp_node = revk_blk_list; 293ed34f34dSUma Shankar while (tmp_node != NULL) { 294ed34f34dSUma Shankar next_node = tmp_node->next; 295ed34f34dSUma Shankar free(tmp_node); 296ed34f34dSUma Shankar tmp_node = next_node; 297ed34f34dSUma Shankar } 298ed34f34dSUma Shankar 299ed34f34dSUma Shankar revk_blk_list = NULL; 300ed34f34dSUma Shankar prev_node = NULL; 301472d5460SYork Sun first_node = true; 302ed34f34dSUma Shankar } 303ed34f34dSUma Shankar 304ed34f34dSUma Shankar int check_blknr_for_revoke(long int blknr, int sequence_no) 305ed34f34dSUma Shankar { 306ed34f34dSUma Shankar struct journal_revoke_header_t *header; 307ed34f34dSUma Shankar int offset; 308ed34f34dSUma Shankar int max; 309ed34f34dSUma Shankar long int blocknr; 310ed34f34dSUma Shankar char *revk_blk; 311ed34f34dSUma Shankar struct revoke_blk_list *tmp_revk_node = revk_blk_list; 312ed34f34dSUma Shankar while (tmp_revk_node != NULL) { 313ed34f34dSUma Shankar revk_blk = tmp_revk_node->content; 314ed34f34dSUma Shankar 315ed34f34dSUma Shankar header = (struct journal_revoke_header_t *) revk_blk; 316ed34f34dSUma Shankar if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) { 317ed34f34dSUma Shankar offset = sizeof(struct journal_revoke_header_t); 318ed34f34dSUma Shankar max = be32_to_cpu(header->r_count); 319ed34f34dSUma Shankar 320ed34f34dSUma Shankar while (offset < max) { 321ed34f34dSUma Shankar blocknr = be32_to_cpu(*((long int *) 322ed34f34dSUma Shankar (revk_blk + offset))); 323ed34f34dSUma Shankar if (blocknr == blknr) 324ed34f34dSUma Shankar goto found; 325ed34f34dSUma Shankar offset += 4; 326ed34f34dSUma Shankar } 327ed34f34dSUma Shankar } 328ed34f34dSUma Shankar tmp_revk_node = tmp_revk_node->next; 329ed34f34dSUma Shankar } 330ed34f34dSUma Shankar 331ed34f34dSUma Shankar return -1; 332ed34f34dSUma Shankar 333ed34f34dSUma Shankar found: 334ed34f34dSUma Shankar return 0; 335ed34f34dSUma Shankar } 336ed34f34dSUma Shankar 337ed34f34dSUma Shankar /* 338ed34f34dSUma Shankar * This function parses the journal blocks and replays the 339ed34f34dSUma Shankar * suceessful transactions. A transaction is successfull 340ed34f34dSUma Shankar * if commit block is found for a descriptor block 341ed34f34dSUma Shankar * The tags in descriptor block contain the disk block 342ed34f34dSUma Shankar * numbers of the metadata to be replayed 343ed34f34dSUma Shankar */ 344ed34f34dSUma Shankar void recover_transaction(int prev_desc_logical_no) 345ed34f34dSUma Shankar { 346ed34f34dSUma Shankar struct ext2_inode inode_journal; 347ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 348ed34f34dSUma Shankar struct journal_header_t *jdb; 349ed34f34dSUma Shankar long int blknr; 350ed34f34dSUma Shankar char *p_jdb; 351ed34f34dSUma Shankar int ofs, flags; 352ed34f34dSUma Shankar int i; 353ed34f34dSUma Shankar struct ext3_journal_block_tag *tag; 354ed34f34dSUma Shankar char *temp_buff = zalloc(fs->blksz); 355ed34f34dSUma Shankar char *metadata_buff = zalloc(fs->blksz); 356ed34f34dSUma Shankar if (!temp_buff || !metadata_buff) 357ed34f34dSUma Shankar goto fail; 358ed34f34dSUma Shankar i = prev_desc_logical_no; 359ed34f34dSUma Shankar ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 360ed34f34dSUma Shankar (struct ext2_inode *)&inode_journal); 361ed34f34dSUma Shankar blknr = read_allocated_block((struct ext2_inode *) 362ed34f34dSUma Shankar &inode_journal, i); 363*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 364*04735e9cSFrederic Leroy temp_buff); 365ed34f34dSUma Shankar p_jdb = (char *)temp_buff; 366ed34f34dSUma Shankar jdb = (struct journal_header_t *) temp_buff; 367ed34f34dSUma Shankar ofs = sizeof(struct journal_header_t); 368ed34f34dSUma Shankar 369ed34f34dSUma Shankar do { 370ed34f34dSUma Shankar tag = (struct ext3_journal_block_tag *)&p_jdb[ofs]; 371ed34f34dSUma Shankar ofs += sizeof(struct ext3_journal_block_tag); 372ed34f34dSUma Shankar 373ed34f34dSUma Shankar if (ofs > fs->blksz) 374ed34f34dSUma Shankar break; 375ed34f34dSUma Shankar 376ed34f34dSUma Shankar flags = be32_to_cpu(tag->flags); 377ed34f34dSUma Shankar if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) 378ed34f34dSUma Shankar ofs += 16; 379ed34f34dSUma Shankar 380ed34f34dSUma Shankar i++; 381ed34f34dSUma Shankar debug("\t\ttag %u\n", be32_to_cpu(tag->block)); 382ed34f34dSUma Shankar if (revk_blk_list != NULL) { 383ed34f34dSUma Shankar if (check_blknr_for_revoke(be32_to_cpu(tag->block), 384ed34f34dSUma Shankar be32_to_cpu(jdb->h_sequence)) == 0) 385ed34f34dSUma Shankar continue; 386ed34f34dSUma Shankar } 387ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, i); 388*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, 389ed34f34dSUma Shankar fs->blksz, metadata_buff); 390ed34f34dSUma Shankar put_ext4((uint64_t)(be32_to_cpu(tag->block) * fs->blksz), 391ed34f34dSUma Shankar metadata_buff, (uint32_t) fs->blksz); 392ed34f34dSUma Shankar } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); 393ed34f34dSUma Shankar fail: 394ed34f34dSUma Shankar free(temp_buff); 395ed34f34dSUma Shankar free(metadata_buff); 396ed34f34dSUma Shankar } 397ed34f34dSUma Shankar 398ed34f34dSUma Shankar void print_jrnl_status(int recovery_flag) 399ed34f34dSUma Shankar { 400ed34f34dSUma Shankar if (recovery_flag == RECOVER) 401ed34f34dSUma Shankar printf("Journal Recovery Completed\n"); 402ed34f34dSUma Shankar else 403ed34f34dSUma Shankar printf("Journal Scan Completed\n"); 404ed34f34dSUma Shankar } 405ed34f34dSUma Shankar 406ed34f34dSUma Shankar int ext4fs_check_journal_state(int recovery_flag) 407ed34f34dSUma Shankar { 408ed34f34dSUma Shankar int i; 409ed34f34dSUma Shankar int DB_FOUND = NO; 410ed34f34dSUma Shankar long int blknr; 411ed34f34dSUma Shankar int transaction_state = TRANSACTION_COMPLETE; 412ed34f34dSUma Shankar int prev_desc_logical_no = 0; 413ed34f34dSUma Shankar int curr_desc_logical_no = 0; 414d429ca0dSŁukasz Majewski int ofs, flags; 415ed34f34dSUma Shankar struct ext2_inode inode_journal; 416ed34f34dSUma Shankar struct journal_superblock_t *jsb = NULL; 417ed34f34dSUma Shankar struct journal_header_t *jdb = NULL; 418ed34f34dSUma Shankar char *p_jdb = NULL; 419ed34f34dSUma Shankar struct ext3_journal_block_tag *tag = NULL; 420ed34f34dSUma Shankar char *temp_buff = NULL; 421ed34f34dSUma Shankar char *temp_buff1 = NULL; 422ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 423ed34f34dSUma Shankar 424ed34f34dSUma Shankar temp_buff = zalloc(fs->blksz); 425ed34f34dSUma Shankar if (!temp_buff) 426ed34f34dSUma Shankar return -ENOMEM; 427ed34f34dSUma Shankar temp_buff1 = zalloc(fs->blksz); 428ed34f34dSUma Shankar if (!temp_buff1) { 429ed34f34dSUma Shankar free(temp_buff); 430ed34f34dSUma Shankar return -ENOMEM; 431ed34f34dSUma Shankar } 432ed34f34dSUma Shankar 433ed34f34dSUma Shankar ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 434ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK); 435*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 436*04735e9cSFrederic Leroy temp_buff); 437ed34f34dSUma Shankar jsb = (struct journal_superblock_t *) temp_buff; 438ed34f34dSUma Shankar 439ed34f34dSUma Shankar if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { 440ed34f34dSUma Shankar if (recovery_flag == RECOVER) 441ed34f34dSUma Shankar printf("Recovery required\n"); 442ed34f34dSUma Shankar } else { 443ed34f34dSUma Shankar if (recovery_flag == RECOVER) 444ed34f34dSUma Shankar printf("File System is consistent\n"); 445ed34f34dSUma Shankar goto end; 446ed34f34dSUma Shankar } 447ed34f34dSUma Shankar 448ed34f34dSUma Shankar if (be32_to_cpu(jsb->s_start) == 0) 449ed34f34dSUma Shankar goto end; 450ed34f34dSUma Shankar 451ed34f34dSUma Shankar if (!(jsb->s_feature_compat & 452ed34f34dSUma Shankar cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM))) 453ed34f34dSUma Shankar jsb->s_feature_compat |= 454ed34f34dSUma Shankar cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); 455ed34f34dSUma Shankar 456ed34f34dSUma Shankar i = be32_to_cpu(jsb->s_first); 457ed34f34dSUma Shankar while (1) { 458ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, i); 459ed34f34dSUma Shankar memset(temp_buff1, '\0', fs->blksz); 460*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 461ed34f34dSUma Shankar 0, fs->blksz, temp_buff1); 462ed34f34dSUma Shankar jdb = (struct journal_header_t *) temp_buff1; 463ed34f34dSUma Shankar 464ed34f34dSUma Shankar if (be32_to_cpu(jdb->h_blocktype) == 465ed34f34dSUma Shankar EXT3_JOURNAL_DESCRIPTOR_BLOCK) { 466ed34f34dSUma Shankar if (be32_to_cpu(jdb->h_sequence) != 467ed34f34dSUma Shankar be32_to_cpu(jsb->s_sequence)) { 468ed34f34dSUma Shankar print_jrnl_status(recovery_flag); 469ed34f34dSUma Shankar break; 470ed34f34dSUma Shankar } 471ed34f34dSUma Shankar 472ed34f34dSUma Shankar curr_desc_logical_no = i; 473ed34f34dSUma Shankar if (transaction_state == TRANSACTION_COMPLETE) 474ed34f34dSUma Shankar transaction_state = TRANSACTION_RUNNING; 475ed34f34dSUma Shankar else 476ed34f34dSUma Shankar return -1; 477ed34f34dSUma Shankar p_jdb = (char *)temp_buff1; 478ed34f34dSUma Shankar ofs = sizeof(struct journal_header_t); 479ed34f34dSUma Shankar do { 480ed34f34dSUma Shankar tag = (struct ext3_journal_block_tag *) 481ed34f34dSUma Shankar &p_jdb[ofs]; 482ed34f34dSUma Shankar ofs += sizeof(struct ext3_journal_block_tag); 483ed34f34dSUma Shankar if (ofs > fs->blksz) 484ed34f34dSUma Shankar break; 485ed34f34dSUma Shankar flags = be32_to_cpu(tag->flags); 486ed34f34dSUma Shankar if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) 487ed34f34dSUma Shankar ofs += 16; 488ed34f34dSUma Shankar i++; 489ed34f34dSUma Shankar debug("\t\ttag %u\n", be32_to_cpu(tag->block)); 490ed34f34dSUma Shankar } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); 491ed34f34dSUma Shankar i++; 492ed34f34dSUma Shankar DB_FOUND = YES; 493ed34f34dSUma Shankar } else if (be32_to_cpu(jdb->h_blocktype) == 494ed34f34dSUma Shankar EXT3_JOURNAL_COMMIT_BLOCK) { 495ed34f34dSUma Shankar if (be32_to_cpu(jdb->h_sequence) != 496ed34f34dSUma Shankar be32_to_cpu(jsb->s_sequence)) { 497ed34f34dSUma Shankar print_jrnl_status(recovery_flag); 498ed34f34dSUma Shankar break; 499ed34f34dSUma Shankar } 500ed34f34dSUma Shankar 501ed34f34dSUma Shankar if (transaction_state == TRANSACTION_RUNNING || 502ed34f34dSUma Shankar (DB_FOUND == NO)) { 503ed34f34dSUma Shankar transaction_state = TRANSACTION_COMPLETE; 504ed34f34dSUma Shankar i++; 505ed34f34dSUma Shankar jsb->s_sequence = 506ed34f34dSUma Shankar cpu_to_be32(be32_to_cpu( 507ed34f34dSUma Shankar jsb->s_sequence) + 1); 508ed34f34dSUma Shankar } 509ed34f34dSUma Shankar prev_desc_logical_no = curr_desc_logical_no; 510ed34f34dSUma Shankar if ((recovery_flag == RECOVER) && (DB_FOUND == YES)) 511ed34f34dSUma Shankar recover_transaction(prev_desc_logical_no); 512ed34f34dSUma Shankar 513ed34f34dSUma Shankar DB_FOUND = NO; 514ed34f34dSUma Shankar } else if (be32_to_cpu(jdb->h_blocktype) == 515ed34f34dSUma Shankar EXT3_JOURNAL_REVOKE_BLOCK) { 516ed34f34dSUma Shankar if (be32_to_cpu(jdb->h_sequence) != 517ed34f34dSUma Shankar be32_to_cpu(jsb->s_sequence)) { 518ed34f34dSUma Shankar print_jrnl_status(recovery_flag); 519ed34f34dSUma Shankar break; 520ed34f34dSUma Shankar } 521ed34f34dSUma Shankar if (recovery_flag == SCAN) 522ed34f34dSUma Shankar ext4fs_push_revoke_blk((char *)jdb); 523ed34f34dSUma Shankar i++; 524ed34f34dSUma Shankar } else { 525ed34f34dSUma Shankar debug("Else Case\n"); 526ed34f34dSUma Shankar if (be32_to_cpu(jdb->h_sequence) != 527ed34f34dSUma Shankar be32_to_cpu(jsb->s_sequence)) { 528ed34f34dSUma Shankar print_jrnl_status(recovery_flag); 529ed34f34dSUma Shankar break; 530ed34f34dSUma Shankar } 531ed34f34dSUma Shankar } 532ed34f34dSUma Shankar } 533ed34f34dSUma Shankar 534ed34f34dSUma Shankar end: 535ed34f34dSUma Shankar if (recovery_flag == RECOVER) { 536ed34f34dSUma Shankar jsb->s_start = cpu_to_be32(1); 537ed34f34dSUma Shankar jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); 538ed34f34dSUma Shankar /* get the superblock */ 53950ce4c07SEgbert Eich ext4_read_superblock((char *)fs->sb); 540ed34f34dSUma Shankar fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; 541ed34f34dSUma Shankar 542ed34f34dSUma Shankar /* Update the super block */ 543ed34f34dSUma Shankar put_ext4((uint64_t) (SUPERBLOCK_SIZE), 544ed34f34dSUma Shankar (struct ext2_sblock *)fs->sb, 545ed34f34dSUma Shankar (uint32_t) SUPERBLOCK_SIZE); 54650ce4c07SEgbert Eich ext4_read_superblock((char *)fs->sb); 547ed34f34dSUma Shankar 548ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, 549ed34f34dSUma Shankar EXT2_JOURNAL_SUPERBLOCK); 550ed34f34dSUma Shankar put_ext4((uint64_t) (blknr * fs->blksz), 551ed34f34dSUma Shankar (struct journal_superblock_t *)temp_buff, 552ed34f34dSUma Shankar (uint32_t) fs->blksz); 553ed34f34dSUma Shankar ext4fs_free_revoke_blks(); 554ed34f34dSUma Shankar } 555ed34f34dSUma Shankar free(temp_buff); 556ed34f34dSUma Shankar free(temp_buff1); 557ed34f34dSUma Shankar 558ed34f34dSUma Shankar return 0; 559ed34f34dSUma Shankar } 560ed34f34dSUma Shankar 561ed34f34dSUma Shankar static void update_descriptor_block(long int blknr) 562ed34f34dSUma Shankar { 563ed34f34dSUma Shankar int i; 564ed34f34dSUma Shankar long int jsb_blknr; 565ed34f34dSUma Shankar struct journal_header_t jdb; 566ed34f34dSUma Shankar struct ext3_journal_block_tag tag; 567ed34f34dSUma Shankar struct ext2_inode inode_journal; 568ed34f34dSUma Shankar struct journal_superblock_t *jsb = NULL; 569ed34f34dSUma Shankar char *buf = NULL; 570ed34f34dSUma Shankar char *temp = NULL; 571ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 572ed34f34dSUma Shankar char *temp_buff = zalloc(fs->blksz); 573ed34f34dSUma Shankar if (!temp_buff) 574ed34f34dSUma Shankar return; 575ed34f34dSUma Shankar 576ed34f34dSUma Shankar ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 577ed34f34dSUma Shankar jsb_blknr = read_allocated_block(&inode_journal, 578ed34f34dSUma Shankar EXT2_JOURNAL_SUPERBLOCK); 579*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, 580*04735e9cSFrederic Leroy temp_buff); 581ed34f34dSUma Shankar jsb = (struct journal_superblock_t *) temp_buff; 582ed34f34dSUma Shankar 583ed34f34dSUma Shankar jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); 584ed34f34dSUma Shankar jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); 585ed34f34dSUma Shankar jdb.h_sequence = jsb->s_sequence; 586ed34f34dSUma Shankar buf = zalloc(fs->blksz); 587ed34f34dSUma Shankar if (!buf) { 588ed34f34dSUma Shankar free(temp_buff); 589ed34f34dSUma Shankar return; 590ed34f34dSUma Shankar } 591ed34f34dSUma Shankar temp = buf; 592ed34f34dSUma Shankar memcpy(buf, &jdb, sizeof(struct journal_header_t)); 593ed34f34dSUma Shankar temp += sizeof(struct journal_header_t); 594ed34f34dSUma Shankar 595ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 596ed34f34dSUma Shankar if (journal_ptr[i]->blknr == -1) 597ed34f34dSUma Shankar break; 598ed34f34dSUma Shankar 599ed34f34dSUma Shankar tag.block = cpu_to_be32(journal_ptr[i]->blknr); 600ed34f34dSUma Shankar tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); 601ed34f34dSUma Shankar memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); 602ed34f34dSUma Shankar temp = temp + sizeof(struct ext3_journal_block_tag); 603ed34f34dSUma Shankar } 604ed34f34dSUma Shankar 605ed34f34dSUma Shankar tag.block = cpu_to_be32(journal_ptr[--i]->blknr); 606ed34f34dSUma Shankar tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); 607ed34f34dSUma Shankar memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, 608ed34f34dSUma Shankar sizeof(struct ext3_journal_block_tag)); 609ed34f34dSUma Shankar put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); 610ed34f34dSUma Shankar 611ed34f34dSUma Shankar free(temp_buff); 612ed34f34dSUma Shankar free(buf); 613ed34f34dSUma Shankar } 614ed34f34dSUma Shankar 615ed34f34dSUma Shankar static void update_commit_block(long int blknr) 616ed34f34dSUma Shankar { 617ed34f34dSUma Shankar struct journal_header_t jdb; 618ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 619ed34f34dSUma Shankar char *buf = NULL; 620ed34f34dSUma Shankar struct ext2_inode inode_journal; 621ed34f34dSUma Shankar struct journal_superblock_t *jsb; 622ed34f34dSUma Shankar long int jsb_blknr; 623ed34f34dSUma Shankar char *temp_buff = zalloc(fs->blksz); 624ed34f34dSUma Shankar if (!temp_buff) 625ed34f34dSUma Shankar return; 626ed34f34dSUma Shankar 627*04735e9cSFrederic Leroy ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 628*04735e9cSFrederic Leroy &inode_journal); 629ed34f34dSUma Shankar jsb_blknr = read_allocated_block(&inode_journal, 630ed34f34dSUma Shankar EXT2_JOURNAL_SUPERBLOCK); 631*04735e9cSFrederic Leroy ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, 632*04735e9cSFrederic Leroy temp_buff); 633ed34f34dSUma Shankar jsb = (struct journal_superblock_t *) temp_buff; 634ed34f34dSUma Shankar 635ed34f34dSUma Shankar jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); 636ed34f34dSUma Shankar jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); 637ed34f34dSUma Shankar jdb.h_sequence = jsb->s_sequence; 638ed34f34dSUma Shankar buf = zalloc(fs->blksz); 639ed34f34dSUma Shankar if (!buf) { 640ed34f34dSUma Shankar free(temp_buff); 641ed34f34dSUma Shankar return; 642ed34f34dSUma Shankar } 643ed34f34dSUma Shankar memcpy(buf, &jdb, sizeof(struct journal_header_t)); 644ed34f34dSUma Shankar put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); 645ed34f34dSUma Shankar 646ed34f34dSUma Shankar free(temp_buff); 647ed34f34dSUma Shankar free(buf); 648ed34f34dSUma Shankar } 649ed34f34dSUma Shankar 650ed34f34dSUma Shankar void ext4fs_update_journal(void) 651ed34f34dSUma Shankar { 652ed34f34dSUma Shankar struct ext2_inode inode_journal; 653ed34f34dSUma Shankar struct ext_filesystem *fs = get_fs(); 654ed34f34dSUma Shankar long int blknr; 655ed34f34dSUma Shankar int i; 656ed34f34dSUma Shankar ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 657ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); 658ed34f34dSUma Shankar update_descriptor_block(blknr); 659ed34f34dSUma Shankar for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 660ed34f34dSUma Shankar if (journal_ptr[i]->blknr == -1) 661ed34f34dSUma Shankar break; 662ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); 663ed34f34dSUma Shankar put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), 664ed34f34dSUma Shankar journal_ptr[i]->buf, fs->blksz); 665ed34f34dSUma Shankar } 666ed34f34dSUma Shankar blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); 667ed34f34dSUma Shankar update_commit_block(blknr); 668ed34f34dSUma Shankar printf("update journal finished\n"); 669ed34f34dSUma Shankar } 670