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();
648 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
, &inode_journal
);
649 blknr
= read_allocated_block(&inode_journal
, jrnl_blk_idx
++, NULL
);
650 update_descriptor_block(blknr
);
651 for (i
= 0; i
< MAX_JOURNAL_ENTRIES
; i
++) {
652 if (journal_ptr
[i
]->blknr
== -1)
654 blknr
= read_allocated_block(&inode_journal
, jrnl_blk_idx
++,
656 put_ext4((uint64_t) ((uint64_t)blknr
* (uint64_t)fs
->blksz
),
657 journal_ptr
[i
]->buf
, fs
->blksz
);
659 blknr
= read_allocated_block(&inode_journal
, jrnl_blk_idx
++, NULL
);
660 update_commit_block(blknr
);
661 printf("update journal finished\n");