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; 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 blknr = read_allocated_block(&inode_journal, i); 457 memset(temp_buff1, '\0', fs->blksz); 458 ext4fs_devread(blknr * fs->sect_perblk, 459 0, fs->blksz, temp_buff1); 460 jdb = (struct journal_header_t *) temp_buff1; 461 462 if (be32_to_cpu(jdb->h_blocktype) == 463 EXT3_JOURNAL_DESCRIPTOR_BLOCK) { 464 if (be32_to_cpu(jdb->h_sequence) != 465 be32_to_cpu(jsb->s_sequence)) { 466 print_jrnl_status(recovery_flag); 467 break; 468 } 469 470 curr_desc_logical_no = i; 471 if (transaction_state == TRANSACTION_COMPLETE) 472 transaction_state = TRANSACTION_RUNNING; 473 else 474 return -1; 475 p_jdb = (char *)temp_buff1; 476 ofs = sizeof(struct journal_header_t); 477 do { 478 tag = (struct ext3_journal_block_tag *) 479 &p_jdb[ofs]; 480 ofs += sizeof(struct ext3_journal_block_tag); 481 if (ofs > fs->blksz) 482 break; 483 flags = be32_to_cpu(tag->flags); 484 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) 485 ofs += 16; 486 i++; 487 debug("\t\ttag %u\n", be32_to_cpu(tag->block)); 488 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); 489 i++; 490 DB_FOUND = YES; 491 } else if (be32_to_cpu(jdb->h_blocktype) == 492 EXT3_JOURNAL_COMMIT_BLOCK) { 493 if (be32_to_cpu(jdb->h_sequence) != 494 be32_to_cpu(jsb->s_sequence)) { 495 print_jrnl_status(recovery_flag); 496 break; 497 } 498 499 if (transaction_state == TRANSACTION_RUNNING || 500 (DB_FOUND == NO)) { 501 transaction_state = TRANSACTION_COMPLETE; 502 i++; 503 jsb->s_sequence = 504 cpu_to_be32(be32_to_cpu( 505 jsb->s_sequence) + 1); 506 } 507 prev_desc_logical_no = curr_desc_logical_no; 508 if ((recovery_flag == RECOVER) && (DB_FOUND == YES)) 509 recover_transaction(prev_desc_logical_no); 510 511 DB_FOUND = NO; 512 } else if (be32_to_cpu(jdb->h_blocktype) == 513 EXT3_JOURNAL_REVOKE_BLOCK) { 514 if (be32_to_cpu(jdb->h_sequence) != 515 be32_to_cpu(jsb->s_sequence)) { 516 print_jrnl_status(recovery_flag); 517 break; 518 } 519 if (recovery_flag == SCAN) 520 ext4fs_push_revoke_blk((char *)jdb); 521 i++; 522 } else { 523 debug("Else Case\n"); 524 if (be32_to_cpu(jdb->h_sequence) != 525 be32_to_cpu(jsb->s_sequence)) { 526 print_jrnl_status(recovery_flag); 527 break; 528 } 529 } 530 } 531 532 end: 533 if (recovery_flag == RECOVER) { 534 jsb->s_start = cpu_to_be32(1); 535 jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); 536 /* get the superblock */ 537 ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, 538 (char *)fs->sb); 539 fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; 540 541 /* Update the super block */ 542 put_ext4((uint64_t) (SUPERBLOCK_SIZE), 543 (struct ext2_sblock *)fs->sb, 544 (uint32_t) SUPERBLOCK_SIZE); 545 ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, 546 (char *)fs->sb); 547 548 blknr = read_allocated_block(&inode_journal, 549 EXT2_JOURNAL_SUPERBLOCK); 550 put_ext4((uint64_t) (blknr * fs->blksz), 551 (struct journal_superblock_t *)temp_buff, 552 (uint32_t) fs->blksz); 553 ext4fs_free_revoke_blks(); 554 } 555 free(temp_buff); 556 free(temp_buff1); 557 558 return 0; 559 } 560 561 static void update_descriptor_block(long int blknr) 562 { 563 int i; 564 long int jsb_blknr; 565 struct journal_header_t jdb; 566 struct ext3_journal_block_tag tag; 567 struct ext2_inode inode_journal; 568 struct journal_superblock_t *jsb = NULL; 569 char *buf = NULL; 570 char *temp = NULL; 571 struct ext_filesystem *fs = get_fs(); 572 char *temp_buff = zalloc(fs->blksz); 573 if (!temp_buff) 574 return; 575 576 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 577 jsb_blknr = read_allocated_block(&inode_journal, 578 EXT2_JOURNAL_SUPERBLOCK); 579 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); 580 jsb = (struct journal_superblock_t *) temp_buff; 581 582 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); 583 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); 584 jdb.h_sequence = jsb->s_sequence; 585 buf = zalloc(fs->blksz); 586 if (!buf) { 587 free(temp_buff); 588 return; 589 } 590 temp = buf; 591 memcpy(buf, &jdb, sizeof(struct journal_header_t)); 592 temp += sizeof(struct journal_header_t); 593 594 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 595 if (journal_ptr[i]->blknr == -1) 596 break; 597 598 tag.block = cpu_to_be32(journal_ptr[i]->blknr); 599 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); 600 memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); 601 temp = temp + sizeof(struct ext3_journal_block_tag); 602 } 603 604 tag.block = cpu_to_be32(journal_ptr[--i]->blknr); 605 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); 606 memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, 607 sizeof(struct ext3_journal_block_tag)); 608 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); 609 610 free(temp_buff); 611 free(buf); 612 } 613 614 static void update_commit_block(long int blknr) 615 { 616 struct journal_header_t jdb; 617 struct ext_filesystem *fs = get_fs(); 618 char *buf = NULL; 619 struct ext2_inode inode_journal; 620 struct journal_superblock_t *jsb; 621 long int jsb_blknr; 622 char *temp_buff = zalloc(fs->blksz); 623 if (!temp_buff) 624 return; 625 626 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 627 jsb_blknr = read_allocated_block(&inode_journal, 628 EXT2_JOURNAL_SUPERBLOCK); 629 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); 630 jsb = (struct journal_superblock_t *) temp_buff; 631 632 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); 633 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); 634 jdb.h_sequence = jsb->s_sequence; 635 buf = zalloc(fs->blksz); 636 if (!buf) { 637 free(temp_buff); 638 return; 639 } 640 memcpy(buf, &jdb, sizeof(struct journal_header_t)); 641 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); 642 643 free(temp_buff); 644 free(buf); 645 } 646 647 void ext4fs_update_journal(void) 648 { 649 struct ext2_inode inode_journal; 650 struct ext_filesystem *fs = get_fs(); 651 long int blknr; 652 int i; 653 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); 654 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); 655 update_descriptor_block(blknr); 656 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { 657 if (journal_ptr[i]->blknr == -1) 658 break; 659 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); 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++); 664 update_commit_block(blknr); 665 printf("update journal finished\n"); 666 } 667