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