1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2011 - 2012 Samsung Electronics
4 * EXT4 filesystem implementation in Uboot by
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.
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 free(dirty_block_ptr[i]->buf);
113 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
114 if (journal_ptr[i]->blknr == -1)
116 free(journal_ptr[i]->buf);
119 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
120 free(journal_ptr[i]);
121 free(dirty_block_ptr[i]);
128 int ext4fs_log_gdt(char *gd_table)
130 struct ext_filesystem *fs = get_fs();
132 long int var = fs->gdtable_blkno;
133 for (i = 0; i < fs->no_blk_pergdt; i++) {
134 journal_ptr[gindex]->buf = zalloc(fs->blksz);
135 if (!journal_ptr[gindex]->buf)
137 memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
138 gd_table += fs->blksz;
139 journal_ptr[gindex++]->blknr = var++;
146 * This function stores the backup copy of meta data in RAM
147 * journal_buffer -- Buffer containing meta data
148 * blknr -- Block number on disk of the meta data buffer
150 int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
152 struct ext_filesystem *fs = get_fs();
155 if (!journal_buffer) {
156 printf("Invalid input arguments %s\n", __func__);
160 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
161 if (journal_ptr[i]->blknr == -1)
163 if (journal_ptr[i]->blknr == blknr)
167 journal_ptr[gindex]->buf = zalloc(fs->blksz);
168 if (!journal_ptr[gindex]->buf)
171 memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
172 journal_ptr[gindex++]->blknr = blknr;
178 * This function stores the modified meta data in RAM
179 * metadata_buffer -- Buffer containing meta data
180 * blknr -- Block number on disk of the meta data buffer
182 int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
184 struct ext_filesystem *fs = get_fs();
185 if (!metadata_buffer) {
186 printf("Invalid input arguments %s\n", __func__);
189 if (dirty_block_ptr[gd_index]->buf)
190 assert(dirty_block_ptr[gd_index]->blknr == blknr);
192 dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
194 if (!dirty_block_ptr[gd_index]->buf)
196 memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
197 dirty_block_ptr[gd_index++]->blknr = blknr;
202 void print_revoke_blks(char *revk_blk)
207 struct journal_revoke_header_t *header;
209 if (revk_blk == NULL)
212 header = (struct journal_revoke_header_t *) revk_blk;
213 offset = sizeof(struct journal_revoke_header_t);
214 max = be32_to_cpu(header->r_count);
215 printf("total bytes %d\n", max);
217 while (offset < max) {
218 blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
219 printf("revoke blknr is %ld\n", blocknr);
224 static struct revoke_blk_list *_get_node(void)
226 struct revoke_blk_list *tmp_node;
227 tmp_node = zalloc(sizeof(struct revoke_blk_list));
228 if (tmp_node == NULL)
230 tmp_node->content = NULL;
231 tmp_node->next = NULL;
236 void ext4fs_push_revoke_blk(char *buffer)
238 struct revoke_blk_list *node = NULL;
239 struct ext_filesystem *fs = get_fs();
240 if (buffer == NULL) {
241 printf("buffer ptr is NULL\n");
246 printf("_get_node: malloc failed\n");
250 node->content = zalloc(fs->blksz);
251 if (node->content == NULL)
253 memcpy(node->content, buffer, fs->blksz);
255 if (first_node == true) {
256 revk_blk_list = node;
260 prev_node->next = node;
265 void ext4fs_free_revoke_blks(void)
267 struct revoke_blk_list *tmp_node = revk_blk_list;
268 struct revoke_blk_list *next_node = NULL;
270 while (tmp_node != NULL) {
271 free(tmp_node->content);
272 tmp_node = tmp_node->next;
275 tmp_node = revk_blk_list;
276 while (tmp_node != NULL) {
277 next_node = tmp_node->next;
279 tmp_node = next_node;
282 revk_blk_list = NULL;
287 int check_blknr_for_revoke(long int blknr, int sequence_no)
289 struct journal_revoke_header_t *header;
294 struct revoke_blk_list *tmp_revk_node = revk_blk_list;
295 while (tmp_revk_node != NULL) {
296 revk_blk = tmp_revk_node->content;
298 header = (struct journal_revoke_header_t *) revk_blk;
299 if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
300 offset = sizeof(struct journal_revoke_header_t);
301 max = be32_to_cpu(header->r_count);
303 while (offset < max) {
304 blocknr = be32_to_cpu(*((__be32 *)
305 (revk_blk + offset)));
306 if (blocknr == blknr)
311 tmp_revk_node = tmp_revk_node->next;
321 * This function parses the journal blocks and replays the
322 * suceessful transactions. A transaction is successfull
323 * if commit block is found for a descriptor block
324 * The tags in descriptor block contain the disk block
325 * numbers of the metadata to be replayed
327 void recover_transaction(int prev_desc_logical_no)
329 struct ext2_inode inode_journal;
330 struct ext_filesystem *fs = get_fs();
331 struct journal_header_t *jdb;
336 struct ext3_journal_block_tag *tag;
337 char *temp_buff = zalloc(fs->blksz);
338 char *metadata_buff = zalloc(fs->blksz);
339 if (!temp_buff || !metadata_buff)
341 i = prev_desc_logical_no;
342 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
343 (struct ext2_inode *)&inode_journal);
344 blknr = read_allocated_block((struct ext2_inode *)
345 &inode_journal, i, NULL);
346 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
348 p_jdb = (char *)temp_buff;
349 jdb = (struct journal_header_t *) temp_buff;
350 ofs = sizeof(struct journal_header_t);
353 tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
354 ofs += sizeof(struct ext3_journal_block_tag);
359 flags = be32_to_cpu(tag->flags);
360 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
364 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
365 if (revk_blk_list != NULL) {
366 if (check_blknr_for_revoke(be32_to_cpu(tag->block),
367 be32_to_cpu(jdb->h_sequence)) == 0)
370 blknr = read_allocated_block(&inode_journal, i, NULL);
371 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
372 fs->blksz, metadata_buff);
373 put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
374 metadata_buff, (uint32_t) fs->blksz);
375 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
381 void print_jrnl_status(int recovery_flag)
383 if (recovery_flag == RECOVER)
384 printf("Journal Recovery Completed\n");
386 printf("Journal Scan Completed\n");
389 int ext4fs_check_journal_state(int recovery_flag)
394 int transaction_state = TRANSACTION_COMPLETE;
395 int prev_desc_logical_no = 0;
396 int curr_desc_logical_no = 0;
398 struct ext2_inode inode_journal;
399 struct journal_superblock_t *jsb = NULL;
400 struct journal_header_t *jdb = NULL;
402 struct ext3_journal_block_tag *tag = NULL;
403 char *temp_buff = NULL;
404 char *temp_buff1 = NULL;
405 struct ext_filesystem *fs = get_fs();
407 if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
410 temp_buff = zalloc(fs->blksz);
413 temp_buff1 = zalloc(fs->blksz);
419 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
420 blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
422 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
424 jsb = (struct journal_superblock_t *) temp_buff;
426 if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
427 if (recovery_flag == RECOVER)
428 printf("Recovery required\n");
430 if (recovery_flag == RECOVER)
431 printf("File System is consistent\n");
435 if (be32_to_cpu(jsb->s_start) == 0)
438 if (!(jsb->s_feature_compat &
439 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
440 jsb->s_feature_compat |=
441 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
443 i = be32_to_cpu(jsb->s_first);
445 blknr = read_allocated_block(&inode_journal, i, NULL);
446 memset(temp_buff1, '\0', fs->blksz);
447 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
448 0, fs->blksz, temp_buff1);
449 jdb = (struct journal_header_t *) temp_buff1;
451 if (be32_to_cpu(jdb->h_blocktype) ==
452 EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
453 if (be32_to_cpu(jdb->h_sequence) !=
454 be32_to_cpu(jsb->s_sequence)) {
455 print_jrnl_status(recovery_flag);
459 curr_desc_logical_no = i;
460 if (transaction_state == TRANSACTION_COMPLETE)
461 transaction_state = TRANSACTION_RUNNING;
464 p_jdb = (char *)temp_buff1;
465 ofs = sizeof(struct journal_header_t);
467 tag = (struct ext3_journal_block_tag *)
469 ofs += sizeof(struct ext3_journal_block_tag);
472 flags = be32_to_cpu(tag->flags);
473 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
476 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
477 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
480 } else if (be32_to_cpu(jdb->h_blocktype) ==
481 EXT3_JOURNAL_COMMIT_BLOCK) {
482 if (be32_to_cpu(jdb->h_sequence) !=
483 be32_to_cpu(jsb->s_sequence)) {
484 print_jrnl_status(recovery_flag);
488 if (transaction_state == TRANSACTION_RUNNING ||
490 transaction_state = TRANSACTION_COMPLETE;
493 cpu_to_be32(be32_to_cpu(
494 jsb->s_sequence) + 1);
496 prev_desc_logical_no = curr_desc_logical_no;
497 if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
498 recover_transaction(prev_desc_logical_no);
501 } else if (be32_to_cpu(jdb->h_blocktype) ==
502 EXT3_JOURNAL_REVOKE_BLOCK) {
503 if (be32_to_cpu(jdb->h_sequence) !=
504 be32_to_cpu(jsb->s_sequence)) {
505 print_jrnl_status(recovery_flag);
508 if (recovery_flag == SCAN)
509 ext4fs_push_revoke_blk((char *)jdb);
512 debug("Else Case\n");
513 if (be32_to_cpu(jdb->h_sequence) !=
514 be32_to_cpu(jsb->s_sequence)) {
515 print_jrnl_status(recovery_flag);
522 if (recovery_flag == RECOVER) {
523 uint32_t new_feature_incompat;
524 jsb->s_start = cpu_to_be32(1);
525 jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
526 /* get the superblock */
527 ext4_read_superblock((char *)fs->sb);
528 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
529 new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
530 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
532 /* Update the super block */
533 put_ext4((uint64_t) (SUPERBLOCK_SIZE),
534 (struct ext2_sblock *)fs->sb,
535 (uint32_t) SUPERBLOCK_SIZE);
536 ext4_read_superblock((char *)fs->sb);
538 blknr = read_allocated_block(&inode_journal,
539 EXT2_JOURNAL_SUPERBLOCK, NULL);
540 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
541 (struct journal_superblock_t *)temp_buff,
542 (uint32_t) fs->blksz);
543 ext4fs_free_revoke_blks();
551 static void update_descriptor_block(long int blknr)
555 struct journal_header_t jdb;
556 struct ext3_journal_block_tag tag;
557 struct ext2_inode inode_journal;
558 struct journal_superblock_t *jsb = NULL;
561 struct ext_filesystem *fs = get_fs();
562 char *temp_buff = zalloc(fs->blksz);
566 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
567 jsb_blknr = read_allocated_block(&inode_journal,
568 EXT2_JOURNAL_SUPERBLOCK, NULL);
569 ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
571 jsb = (struct journal_superblock_t *) temp_buff;
573 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
574 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
575 jdb.h_sequence = jsb->s_sequence;
576 buf = zalloc(fs->blksz);
582 memcpy(buf, &jdb, sizeof(struct journal_header_t));
583 temp += sizeof(struct journal_header_t);
585 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
586 if (journal_ptr[i]->blknr == -1)
589 tag.block = cpu_to_be32(journal_ptr[i]->blknr);
590 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
591 memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
592 temp = temp + sizeof(struct ext3_journal_block_tag);
595 tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
596 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
597 memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
598 sizeof(struct ext3_journal_block_tag));
599 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
605 static void update_commit_block(long int blknr)
607 struct journal_header_t jdb;
608 struct ext_filesystem *fs = get_fs();
610 struct ext2_inode inode_journal;
611 struct journal_superblock_t *jsb;
613 char *temp_buff = zalloc(fs->blksz);
617 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
619 jsb_blknr = read_allocated_block(&inode_journal,
620 EXT2_JOURNAL_SUPERBLOCK, NULL);
621 ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
623 jsb = (struct journal_superblock_t *) temp_buff;
625 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
626 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
627 jdb.h_sequence = jsb->s_sequence;
628 buf = zalloc(fs->blksz);
633 memcpy(buf, &jdb, sizeof(struct journal_header_t));
634 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
640 void ext4fs_update_journal(void)
642 struct ext2_inode inode_journal;
643 struct ext_filesystem *fs = get_fs();
647 if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
650 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
651 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
652 update_descriptor_block(blknr);
653 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
654 if (journal_ptr[i]->blknr == -1)
656 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
658 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
659 journal_ptr[i]->buf, fs->blksz);
661 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
662 update_commit_block(blknr);
663 printf("update journal finished\n");