1 // SPDX-License-Identifier: GPL-2.0+
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>
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>
13 * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
19 #include <ext_common.h>
20 #include "ext4_common.h"
22 static struct revoke_blk_list *revk_blk_list;
23 static struct revoke_blk_list *prev_node;
24 static int first_node = true;
29 struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
30 struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
32 int ext4fs_init_journal(void)
36 struct ext_filesystem *fs = get_fs();
45 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
46 journal_ptr[i] = zalloc(sizeof(struct journal_log));
49 dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
50 if (!dirty_block_ptr[i])
52 journal_ptr[i]->buf = NULL;
53 journal_ptr[i]->blknr = -1;
55 dirty_block_ptr[i]->buf = NULL;
56 dirty_block_ptr[i]->blknr = -1;
59 if (fs->blksz == 4096) {
60 temp = zalloc(fs->blksz);
63 journal_ptr[gindex]->buf = zalloc(fs->blksz);
64 if (!journal_ptr[gindex]->buf)
66 ext4fs_devread(0, 0, fs->blksz, temp);
67 memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
68 memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
69 journal_ptr[gindex++]->blknr = 0;
72 journal_ptr[gindex]->buf = zalloc(fs->blksz);
73 if (!journal_ptr[gindex]->buf)
75 memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
76 journal_ptr[gindex++]->blknr = 1;
79 /* Check the file system state using journal super block */
80 if (ext4fs_check_journal_state(SCAN))
82 /* Check the file system state using journal super block */
83 if (ext4fs_check_journal_state(RECOVER))
91 void ext4fs_dump_metadata(void)
93 struct ext_filesystem *fs = get_fs();
95 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
96 if (dirty_block_ptr[i]->blknr == -1)
98 put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
99 (uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
104 void ext4fs_free_journal(void)
107 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
108 if (dirty_block_ptr[i]->blknr == -1)
110 if (dirty_block_ptr[i]->buf)
111 free(dirty_block_ptr[i]->buf);
114 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
115 if (journal_ptr[i]->blknr == -1)
117 if (journal_ptr[i]->buf)
118 free(journal_ptr[i]->buf);
121 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
123 free(journal_ptr[i]);
124 if (dirty_block_ptr[i])
125 free(dirty_block_ptr[i]);
132 int ext4fs_log_gdt(char *gd_table)
134 struct ext_filesystem *fs = get_fs();
136 long int var = fs->gdtable_blkno;
137 for (i = 0; i < fs->no_blk_pergdt; i++) {
138 journal_ptr[gindex]->buf = zalloc(fs->blksz);
139 if (!journal_ptr[gindex]->buf)
141 memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
142 gd_table += fs->blksz;
143 journal_ptr[gindex++]->blknr = var++;
150 * This function stores the backup copy of meta data in RAM
151 * journal_buffer -- Buffer containing meta data
152 * blknr -- Block number on disk of the meta data buffer
154 int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
156 struct ext_filesystem *fs = get_fs();
159 if (!journal_buffer) {
160 printf("Invalid input arguments %s\n", __func__);
164 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
165 if (journal_ptr[i]->blknr == -1)
167 if (journal_ptr[i]->blknr == blknr)
171 journal_ptr[gindex]->buf = zalloc(fs->blksz);
172 if (!journal_ptr[gindex]->buf)
175 memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
176 journal_ptr[gindex++]->blknr = blknr;
182 * This function stores the modified meta data in RAM
183 * metadata_buffer -- Buffer containing meta data
184 * blknr -- Block number on disk of the meta data buffer
186 int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
188 struct ext_filesystem *fs = get_fs();
189 if (!metadata_buffer) {
190 printf("Invalid input arguments %s\n", __func__);
193 if (dirty_block_ptr[gd_index]->buf)
194 assert(dirty_block_ptr[gd_index]->blknr == blknr);
196 dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
198 if (!dirty_block_ptr[gd_index]->buf)
200 memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
201 dirty_block_ptr[gd_index++]->blknr = blknr;
206 void print_revoke_blks(char *revk_blk)
211 struct journal_revoke_header_t *header;
213 if (revk_blk == NULL)
216 header = (struct journal_revoke_header_t *) revk_blk;
217 offset = sizeof(struct journal_revoke_header_t);
218 max = be32_to_cpu(header->r_count);
219 printf("total bytes %d\n", max);
221 while (offset < max) {
222 blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
223 printf("revoke blknr is %ld\n", blocknr);
228 static struct revoke_blk_list *_get_node(void)
230 struct revoke_blk_list *tmp_node;
231 tmp_node = zalloc(sizeof(struct revoke_blk_list));
232 if (tmp_node == NULL)
234 tmp_node->content = NULL;
235 tmp_node->next = NULL;
240 void ext4fs_push_revoke_blk(char *buffer)
242 struct revoke_blk_list *node = NULL;
243 struct ext_filesystem *fs = get_fs();
244 if (buffer == NULL) {
245 printf("buffer ptr is NULL\n");
250 printf("_get_node: malloc failed\n");
254 node->content = zalloc(fs->blksz);
255 if (node->content == NULL)
257 memcpy(node->content, buffer, fs->blksz);
259 if (first_node == true) {
260 revk_blk_list = node;
264 prev_node->next = node;
269 void ext4fs_free_revoke_blks(void)
271 struct revoke_blk_list *tmp_node = revk_blk_list;
272 struct revoke_blk_list *next_node = NULL;
274 while (tmp_node != NULL) {
275 if (tmp_node->content)
276 free(tmp_node->content);
277 tmp_node = tmp_node->next;
280 tmp_node = revk_blk_list;
281 while (tmp_node != NULL) {
282 next_node = tmp_node->next;
284 tmp_node = next_node;
287 revk_blk_list = NULL;
292 int check_blknr_for_revoke(long int blknr, int sequence_no)
294 struct journal_revoke_header_t *header;
299 struct revoke_blk_list *tmp_revk_node = revk_blk_list;
300 while (tmp_revk_node != NULL) {
301 revk_blk = tmp_revk_node->content;
303 header = (struct journal_revoke_header_t *) revk_blk;
304 if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
305 offset = sizeof(struct journal_revoke_header_t);
306 max = be32_to_cpu(header->r_count);
308 while (offset < max) {
309 blocknr = be32_to_cpu(*((__be32 *)
310 (revk_blk + offset)));
311 if (blocknr == blknr)
316 tmp_revk_node = tmp_revk_node->next;
326 * This function parses the journal blocks and replays the
327 * suceessful transactions. A transaction is successfull
328 * if commit block is found for a descriptor block
329 * The tags in descriptor block contain the disk block
330 * numbers of the metadata to be replayed
332 void recover_transaction(int prev_desc_logical_no)
334 struct ext2_inode inode_journal;
335 struct ext_filesystem *fs = get_fs();
336 struct journal_header_t *jdb;
341 struct ext3_journal_block_tag *tag;
342 char *temp_buff = zalloc(fs->blksz);
343 char *metadata_buff = zalloc(fs->blksz);
344 if (!temp_buff || !metadata_buff)
346 i = prev_desc_logical_no;
347 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
348 (struct ext2_inode *)&inode_journal);
349 blknr = read_allocated_block((struct ext2_inode *)
350 &inode_journal, i, NULL);
351 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
353 p_jdb = (char *)temp_buff;
354 jdb = (struct journal_header_t *) temp_buff;
355 ofs = sizeof(struct journal_header_t);
358 tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
359 ofs += sizeof(struct ext3_journal_block_tag);
364 flags = be32_to_cpu(tag->flags);
365 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
369 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
370 if (revk_blk_list != NULL) {
371 if (check_blknr_for_revoke(be32_to_cpu(tag->block),
372 be32_to_cpu(jdb->h_sequence)) == 0)
375 blknr = read_allocated_block(&inode_journal, i, NULL);
376 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
377 fs->blksz, metadata_buff);
378 put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
379 metadata_buff, (uint32_t) fs->blksz);
380 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
386 void print_jrnl_status(int recovery_flag)
388 if (recovery_flag == RECOVER)
389 printf("Journal Recovery Completed\n");
391 printf("Journal Scan Completed\n");
394 int ext4fs_check_journal_state(int recovery_flag)
399 int transaction_state = TRANSACTION_COMPLETE;
400 int prev_desc_logical_no = 0;
401 int curr_desc_logical_no = 0;
403 struct ext2_inode inode_journal;
404 struct journal_superblock_t *jsb = NULL;
405 struct journal_header_t *jdb = NULL;
407 struct ext3_journal_block_tag *tag = NULL;
408 char *temp_buff = NULL;
409 char *temp_buff1 = NULL;
410 struct ext_filesystem *fs = get_fs();
412 temp_buff = zalloc(fs->blksz);
415 temp_buff1 = zalloc(fs->blksz);
421 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
422 blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
424 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
426 jsb = (struct journal_superblock_t *) temp_buff;
428 if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
429 if (recovery_flag == RECOVER)
430 printf("Recovery required\n");
432 if (recovery_flag == RECOVER)
433 printf("File System is consistent\n");
437 if (be32_to_cpu(jsb->s_start) == 0)
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);
445 i = be32_to_cpu(jsb->s_first);
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;
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);
461 curr_desc_logical_no = i;
462 if (transaction_state == TRANSACTION_COMPLETE)
463 transaction_state = TRANSACTION_RUNNING;
466 p_jdb = (char *)temp_buff1;
467 ofs = sizeof(struct journal_header_t);
469 tag = (struct ext3_journal_block_tag *)
471 ofs += sizeof(struct ext3_journal_block_tag);
474 flags = be32_to_cpu(tag->flags);
475 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
478 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
479 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
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);
490 if (transaction_state == TRANSACTION_RUNNING ||
492 transaction_state = TRANSACTION_COMPLETE;
495 cpu_to_be32(be32_to_cpu(
496 jsb->s_sequence) + 1);
498 prev_desc_logical_no = curr_desc_logical_no;
499 if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
500 recover_transaction(prev_desc_logical_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);
510 if (recovery_flag == SCAN)
511 ext4fs_push_revoke_blk((char *)jdb);
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);
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);
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);
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();
553 static void update_descriptor_block(long int 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;
563 struct ext_filesystem *fs = get_fs();
564 char *temp_buff = zalloc(fs->blksz);
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,
573 jsb = (struct journal_superblock_t *) temp_buff;
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);
584 memcpy(buf, &jdb, sizeof(struct journal_header_t));
585 temp += sizeof(struct journal_header_t);
587 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
588 if (journal_ptr[i]->blknr == -1)
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);
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);
607 static void update_commit_block(long int blknr)
609 struct journal_header_t jdb;
610 struct ext_filesystem *fs = get_fs();
612 struct ext2_inode inode_journal;
613 struct journal_superblock_t *jsb;
615 char *temp_buff = zalloc(fs->blksz);
619 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
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,
625 jsb = (struct journal_superblock_t *) temp_buff;
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);
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);
642 void ext4fs_update_journal(void)
644 struct ext2_inode inode_journal;
645 struct ext_filesystem *fs = get_fs();
649 if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
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)
658 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);
663 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
664 update_commit_block(blknr);
665 printf("update journal finished\n");