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