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