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
20 #include <ext_common.h>
21 #include "ext4_common.h"
23 static struct revoke_blk_list *revk_blk_list;
24 static struct revoke_blk_list *prev_node;
25 static int first_node = true;
30 struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
31 struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
33 int ext4fs_init_journal(void)
37 struct ext_filesystem *fs = get_fs();
46 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
47 journal_ptr[i] = zalloc(sizeof(struct journal_log));
50 dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
51 if (!dirty_block_ptr[i])
53 journal_ptr[i]->buf = NULL;
54 journal_ptr[i]->blknr = -1;
56 dirty_block_ptr[i]->buf = NULL;
57 dirty_block_ptr[i]->blknr = -1;
60 if (fs->blksz == 4096) {
61 temp = zalloc(fs->blksz);
64 journal_ptr[gindex]->buf = zalloc(fs->blksz);
65 if (!journal_ptr[gindex]->buf)
67 ext4fs_devread(0, 0, fs->blksz, temp);
68 memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
69 memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
70 journal_ptr[gindex++]->blknr = 0;
73 journal_ptr[gindex]->buf = zalloc(fs->blksz);
74 if (!journal_ptr[gindex]->buf)
76 memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
77 journal_ptr[gindex++]->blknr = 1;
80 /* Check the file system state using journal super block */
81 if (ext4fs_check_journal_state(SCAN))
83 /* Check the file system state using journal super block */
84 if (ext4fs_check_journal_state(RECOVER))
92 void ext4fs_dump_metadata(void)
94 struct ext_filesystem *fs = get_fs();
96 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
97 if (dirty_block_ptr[i]->blknr == -1)
99 put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
100 (uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
105 void ext4fs_free_journal(void)
108 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
109 if (dirty_block_ptr[i]->blknr == -1)
111 free(dirty_block_ptr[i]->buf);
114 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
115 if (journal_ptr[i]->blknr == -1)
117 free(journal_ptr[i]->buf);
120 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
121 free(journal_ptr[i]);
122 free(dirty_block_ptr[i]);
129 int ext4fs_log_gdt(char *gd_table)
131 struct ext_filesystem *fs = get_fs();
133 long int var = fs->gdtable_blkno;
134 for (i = 0; i < fs->no_blk_pergdt; i++) {
135 journal_ptr[gindex]->buf = zalloc(fs->blksz);
136 if (!journal_ptr[gindex]->buf)
138 memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
139 gd_table += fs->blksz;
140 journal_ptr[gindex++]->blknr = var++;
147 * This function stores the backup copy of meta data in RAM
148 * journal_buffer -- Buffer containing meta data
149 * blknr -- Block number on disk of the meta data buffer
151 int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
153 struct ext_filesystem *fs = get_fs();
156 if (!journal_buffer) {
157 printf("Invalid input arguments %s\n", __func__);
161 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
162 if (journal_ptr[i]->blknr == -1)
164 if (journal_ptr[i]->blknr == blknr)
168 journal_ptr[gindex]->buf = zalloc(fs->blksz);
169 if (!journal_ptr[gindex]->buf)
172 memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
173 journal_ptr[gindex++]->blknr = blknr;
179 * This function stores the modified meta data in RAM
180 * metadata_buffer -- Buffer containing meta data
181 * blknr -- Block number on disk of the meta data buffer
183 int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
185 struct ext_filesystem *fs = get_fs();
186 if (!metadata_buffer) {
187 printf("Invalid input arguments %s\n", __func__);
190 if (dirty_block_ptr[gd_index]->buf)
191 assert(dirty_block_ptr[gd_index]->blknr == blknr);
193 dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
195 if (!dirty_block_ptr[gd_index]->buf)
197 memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
198 dirty_block_ptr[gd_index++]->blknr = blknr;
203 void print_revoke_blks(char *revk_blk)
208 struct journal_revoke_header_t *header;
210 if (revk_blk == NULL)
213 header = (struct journal_revoke_header_t *) revk_blk;
214 offset = sizeof(struct journal_revoke_header_t);
215 max = be32_to_cpu(header->r_count);
216 printf("total bytes %d\n", max);
218 while (offset < max) {
219 blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
220 printf("revoke blknr is %ld\n", blocknr);
225 static struct revoke_blk_list *_get_node(void)
227 struct revoke_blk_list *tmp_node;
228 tmp_node = zalloc(sizeof(struct revoke_blk_list));
229 if (tmp_node == NULL)
231 tmp_node->content = NULL;
232 tmp_node->next = NULL;
237 void ext4fs_push_revoke_blk(char *buffer)
239 struct revoke_blk_list *node = NULL;
240 struct ext_filesystem *fs = get_fs();
241 if (buffer == NULL) {
242 printf("buffer ptr is NULL\n");
247 printf("_get_node: malloc failed\n");
251 node->content = zalloc(fs->blksz);
252 if (node->content == NULL)
254 memcpy(node->content, buffer, fs->blksz);
256 if (first_node == true) {
257 revk_blk_list = node;
261 prev_node->next = node;
266 void ext4fs_free_revoke_blks(void)
268 struct revoke_blk_list *tmp_node = revk_blk_list;
269 struct revoke_blk_list *next_node = NULL;
271 while (tmp_node != NULL) {
272 free(tmp_node->content);
273 tmp_node = tmp_node->next;
276 tmp_node = revk_blk_list;
277 while (tmp_node != NULL) {
278 next_node = tmp_node->next;
280 tmp_node = next_node;
283 revk_blk_list = NULL;
288 int check_blknr_for_revoke(long int blknr, int sequence_no)
290 struct journal_revoke_header_t *header;
295 struct revoke_blk_list *tmp_revk_node = revk_blk_list;
296 while (tmp_revk_node != NULL) {
297 revk_blk = tmp_revk_node->content;
299 header = (struct journal_revoke_header_t *) revk_blk;
300 if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
301 offset = sizeof(struct journal_revoke_header_t);
302 max = be32_to_cpu(header->r_count);
304 while (offset < max) {
305 blocknr = be32_to_cpu(*((__be32 *)
306 (revk_blk + offset)));
307 if (blocknr == blknr)
312 tmp_revk_node = tmp_revk_node->next;
322 * This function parses the journal blocks and replays the
323 * suceessful transactions. A transaction is successfull
324 * if commit block is found for a descriptor block
325 * The tags in descriptor block contain the disk block
326 * numbers of the metadata to be replayed
328 void recover_transaction(int prev_desc_logical_no)
330 struct ext2_inode inode_journal;
331 struct ext_filesystem *fs = get_fs();
332 struct journal_header_t *jdb;
337 struct ext3_journal_block_tag *tag;
338 char *temp_buff = zalloc(fs->blksz);
339 char *metadata_buff = zalloc(fs->blksz);
340 if (!temp_buff || !metadata_buff)
342 i = prev_desc_logical_no;
343 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
344 (struct ext2_inode *)&inode_journal);
345 blknr = read_allocated_block((struct ext2_inode *)
346 &inode_journal, i, NULL);
347 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
349 p_jdb = (char *)temp_buff;
350 jdb = (struct journal_header_t *) temp_buff;
351 ofs = sizeof(struct journal_header_t);
354 tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
355 ofs += sizeof(struct ext3_journal_block_tag);
360 flags = be32_to_cpu(tag->flags);
361 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
365 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
366 if (revk_blk_list != NULL) {
367 if (check_blknr_for_revoke(be32_to_cpu(tag->block),
368 be32_to_cpu(jdb->h_sequence)) == 0)
371 blknr = read_allocated_block(&inode_journal, i, NULL);
372 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
373 fs->blksz, metadata_buff);
374 put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
375 metadata_buff, (uint32_t) fs->blksz);
376 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
382 void print_jrnl_status(int recovery_flag)
384 if (recovery_flag == RECOVER)
385 printf("Journal Recovery Completed\n");
387 printf("Journal Scan Completed\n");
390 int ext4fs_check_journal_state(int recovery_flag)
395 int transaction_state = TRANSACTION_COMPLETE;
396 int prev_desc_logical_no = 0;
397 int curr_desc_logical_no = 0;
399 struct ext2_inode inode_journal;
400 struct journal_superblock_t *jsb = NULL;
401 struct journal_header_t *jdb = NULL;
403 struct ext3_journal_block_tag *tag = NULL;
404 char *temp_buff = NULL;
405 char *temp_buff1 = NULL;
406 struct ext_filesystem *fs = get_fs();
408 if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
411 temp_buff = zalloc(fs->blksz);
414 temp_buff1 = zalloc(fs->blksz);
420 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
421 blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
423 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
425 jsb = (struct journal_superblock_t *) temp_buff;
427 if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
428 if (recovery_flag == RECOVER)
429 printf("Recovery required\n");
431 if (recovery_flag == RECOVER)
432 log_debug("File System is consistent\n");
436 if (be32_to_cpu(jsb->s_start) == 0)
439 if (!(jsb->s_feature_compat &
440 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
441 jsb->s_feature_compat |=
442 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
444 i = be32_to_cpu(jsb->s_first);
446 blknr = read_allocated_block(&inode_journal, i, NULL);
447 memset(temp_buff1, '\0', fs->blksz);
448 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
449 0, fs->blksz, temp_buff1);
450 jdb = (struct journal_header_t *) temp_buff1;
452 if (be32_to_cpu(jdb->h_blocktype) ==
453 EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
454 if (be32_to_cpu(jdb->h_sequence) !=
455 be32_to_cpu(jsb->s_sequence)) {
456 print_jrnl_status(recovery_flag);
460 curr_desc_logical_no = i;
461 if (transaction_state == TRANSACTION_COMPLETE)
462 transaction_state = TRANSACTION_RUNNING;
465 p_jdb = (char *)temp_buff1;
466 ofs = sizeof(struct journal_header_t);
468 tag = (struct ext3_journal_block_tag *)
470 ofs += sizeof(struct ext3_journal_block_tag);
473 flags = be32_to_cpu(tag->flags);
474 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
477 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
478 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
481 } else if (be32_to_cpu(jdb->h_blocktype) ==
482 EXT3_JOURNAL_COMMIT_BLOCK) {
483 if (be32_to_cpu(jdb->h_sequence) !=
484 be32_to_cpu(jsb->s_sequence)) {
485 print_jrnl_status(recovery_flag);
489 if (transaction_state == TRANSACTION_RUNNING ||
491 transaction_state = TRANSACTION_COMPLETE;
494 cpu_to_be32(be32_to_cpu(
495 jsb->s_sequence) + 1);
497 prev_desc_logical_no = curr_desc_logical_no;
498 if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
499 recover_transaction(prev_desc_logical_no);
502 } else if (be32_to_cpu(jdb->h_blocktype) ==
503 EXT3_JOURNAL_REVOKE_BLOCK) {
504 if (be32_to_cpu(jdb->h_sequence) !=
505 be32_to_cpu(jsb->s_sequence)) {
506 print_jrnl_status(recovery_flag);
509 if (recovery_flag == SCAN)
510 ext4fs_push_revoke_blk((char *)jdb);
513 debug("Else Case\n");
514 if (be32_to_cpu(jdb->h_sequence) !=
515 be32_to_cpu(jsb->s_sequence)) {
516 print_jrnl_status(recovery_flag);
523 if (recovery_flag == RECOVER) {
524 uint32_t new_feature_incompat;
525 jsb->s_start = cpu_to_be32(1);
526 jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
527 /* get the superblock */
528 ext4_read_superblock((char *)fs->sb);
529 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
530 new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
531 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
533 /* Update the super block */
534 put_ext4((uint64_t) (SUPERBLOCK_SIZE),
535 (struct ext2_sblock *)fs->sb,
536 (uint32_t) SUPERBLOCK_SIZE);
537 ext4_read_superblock((char *)fs->sb);
539 blknr = read_allocated_block(&inode_journal,
540 EXT2_JOURNAL_SUPERBLOCK, NULL);
541 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
542 (struct journal_superblock_t *)temp_buff,
543 (uint32_t) fs->blksz);
544 ext4fs_free_revoke_blks();
552 static void update_descriptor_block(long int blknr)
556 struct journal_header_t jdb;
557 struct ext3_journal_block_tag tag;
558 struct ext2_inode inode_journal;
559 struct journal_superblock_t *jsb = NULL;
562 struct ext_filesystem *fs = get_fs();
563 char *temp_buff = zalloc(fs->blksz);
567 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
568 jsb_blknr = read_allocated_block(&inode_journal,
569 EXT2_JOURNAL_SUPERBLOCK, NULL);
570 ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
572 jsb = (struct journal_superblock_t *) temp_buff;
574 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
575 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
576 jdb.h_sequence = jsb->s_sequence;
577 buf = zalloc(fs->blksz);
583 memcpy(buf, &jdb, sizeof(struct journal_header_t));
584 temp += sizeof(struct journal_header_t);
586 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
587 if (journal_ptr[i]->blknr == -1)
590 tag.block = cpu_to_be32(journal_ptr[i]->blknr);
591 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
592 memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
593 temp = temp + sizeof(struct ext3_journal_block_tag);
596 tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
597 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
598 memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
599 sizeof(struct ext3_journal_block_tag));
600 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
606 static void update_commit_block(long int blknr)
608 struct journal_header_t jdb;
609 struct ext_filesystem *fs = get_fs();
611 struct ext2_inode inode_journal;
612 struct journal_superblock_t *jsb;
614 char *temp_buff = zalloc(fs->blksz);
618 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
620 jsb_blknr = read_allocated_block(&inode_journal,
621 EXT2_JOURNAL_SUPERBLOCK, NULL);
622 ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
624 jsb = (struct journal_superblock_t *) temp_buff;
626 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
627 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
628 jdb.h_sequence = jsb->s_sequence;
629 buf = zalloc(fs->blksz);
634 memcpy(buf, &jdb, sizeof(struct journal_header_t));
635 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
641 void ext4fs_update_journal(void)
643 struct ext2_inode inode_journal;
644 struct ext_filesystem *fs = get_fs();
648 if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
651 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
652 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
653 update_descriptor_block(blknr);
654 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
655 if (journal_ptr[i]->blknr == -1)
657 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
659 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
660 journal_ptr[i]->buf, fs->blksz);
662 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
663 update_commit_block(blknr);
664 printf("update journal finished\n");