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>
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>
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.
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.
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.
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.
35 #include <ext_common.h>
36 #include "ext4_common.h"
38 typedef enum _bool{false,true} bool;
40 static struct revoke_blk_list *revk_blk_list;
41 static struct revoke_blk_list *prev_node;
42 static int first_node = true;
47 struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
48 struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
50 int ext4fs_init_journal(void)
54 struct ext_filesystem *fs = get_fs();
63 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
64 journal_ptr[i] = zalloc(sizeof(struct journal_log));
67 dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
68 if (!dirty_block_ptr[i])
70 journal_ptr[i]->buf = NULL;
71 journal_ptr[i]->blknr = -1;
73 dirty_block_ptr[i]->buf = NULL;
74 dirty_block_ptr[i]->blknr = -1;
77 if (fs->blksz == 4096) {
78 temp = zalloc(fs->blksz);
81 journal_ptr[gindex]->buf = zalloc(fs->blksz);
82 if (!journal_ptr[gindex]->buf)
84 ext4fs_devread(0, 0, fs->blksz, temp);
85 memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
86 memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
87 journal_ptr[gindex++]->blknr = 0;
90 journal_ptr[gindex]->buf = zalloc(fs->blksz);
91 if (!journal_ptr[gindex]->buf)
93 memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
94 journal_ptr[gindex++]->blknr = 1;
97 /* Check the file system state using journal super block */
98 if (ext4fs_check_journal_state(SCAN))
100 /* Check the file system state using journal super block */
101 if (ext4fs_check_journal_state(RECOVER))
109 void ext4fs_dump_metadata(void)
111 struct ext_filesystem *fs = get_fs();
113 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
114 if (dirty_block_ptr[i]->blknr == -1)
116 put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
117 (uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
122 void ext4fs_free_journal(void)
125 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
126 if (dirty_block_ptr[i]->blknr == -1)
128 if (dirty_block_ptr[i]->buf)
129 free(dirty_block_ptr[i]->buf);
132 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
133 if (journal_ptr[i]->blknr == -1)
135 if (journal_ptr[i]->buf)
136 free(journal_ptr[i]->buf);
139 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
141 free(journal_ptr[i]);
142 if (dirty_block_ptr[i])
143 free(dirty_block_ptr[i]);
150 int ext4fs_log_gdt(char *gd_table)
152 struct ext_filesystem *fs = get_fs();
154 long int var = fs->gdtable_blkno;
155 for (i = 0; i < fs->no_blk_pergdt; i++) {
156 journal_ptr[gindex]->buf = zalloc(fs->blksz);
157 if (!journal_ptr[gindex]->buf)
159 memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
160 gd_table += fs->blksz;
161 journal_ptr[gindex++]->blknr = var++;
168 * This function stores the backup copy of meta data in RAM
169 * journal_buffer -- Buffer containing meta data
170 * blknr -- Block number on disk of the meta data buffer
172 int ext4fs_log_journal(char *journal_buffer, long int blknr)
174 struct ext_filesystem *fs = get_fs();
177 if (!journal_buffer) {
178 printf("Invalid input arguments %s\n", __func__);
182 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
183 if (journal_ptr[i]->blknr == -1)
185 if (journal_ptr[i]->blknr == blknr)
189 journal_ptr[gindex]->buf = zalloc(fs->blksz);
190 if (!journal_ptr[gindex]->buf)
193 memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
194 journal_ptr[gindex++]->blknr = blknr;
200 * This function stores the modified meta data in RAM
201 * metadata_buffer -- Buffer containing meta data
202 * blknr -- Block number on disk of the meta data buffer
204 int ext4fs_put_metadata(char *metadata_buffer, long int blknr)
206 struct ext_filesystem *fs = get_fs();
207 if (!metadata_buffer) {
208 printf("Invalid input arguments %s\n", __func__);
211 dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
212 if (!dirty_block_ptr[gd_index]->buf)
214 memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
215 dirty_block_ptr[gd_index++]->blknr = blknr;
220 void print_revoke_blks(char *revk_blk)
225 struct journal_revoke_header_t *header;
227 if (revk_blk == NULL)
230 header = (struct journal_revoke_header_t *) revk_blk;
231 offset = sizeof(struct journal_revoke_header_t);
232 max = be32_to_cpu(header->r_count);
233 printf("total bytes %d\n", max);
235 while (offset < max) {
236 blocknr = be32_to_cpu(*((long int *)(revk_blk + offset)));
237 printf("revoke blknr is %ld\n", blocknr);
242 static struct revoke_blk_list *_get_node(void)
244 struct revoke_blk_list *tmp_node;
245 tmp_node = zalloc(sizeof(struct revoke_blk_list));
246 if (tmp_node == NULL)
248 tmp_node->content = NULL;
249 tmp_node->next = NULL;
254 void ext4fs_push_revoke_blk(char *buffer)
256 struct revoke_blk_list *node = NULL;
257 struct ext_filesystem *fs = get_fs();
258 if (buffer == NULL) {
259 printf("buffer ptr is NULL\n");
264 printf("_get_node: malloc failed\n");
268 node->content = zalloc(fs->blksz);
269 if (node->content == NULL)
271 memcpy(node->content, buffer, fs->blksz);
273 if (first_node == true) {
274 revk_blk_list = node;
278 prev_node->next = node;
283 void ext4fs_free_revoke_blks(void)
285 struct revoke_blk_list *tmp_node = revk_blk_list;
286 struct revoke_blk_list *next_node = NULL;
288 while (tmp_node != NULL) {
289 if (tmp_node->content)
290 free(tmp_node->content);
291 tmp_node = tmp_node->next;
294 tmp_node = revk_blk_list;
295 while (tmp_node != NULL) {
296 next_node = tmp_node->next;
298 tmp_node = next_node;
301 revk_blk_list = NULL;
306 int check_blknr_for_revoke(long int blknr, int sequence_no)
308 struct journal_revoke_header_t *header;
313 struct revoke_blk_list *tmp_revk_node = revk_blk_list;
314 while (tmp_revk_node != NULL) {
315 revk_blk = tmp_revk_node->content;
317 header = (struct journal_revoke_header_t *) revk_blk;
318 if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
319 offset = sizeof(struct journal_revoke_header_t);
320 max = be32_to_cpu(header->r_count);
322 while (offset < max) {
323 blocknr = be32_to_cpu(*((long int *)
324 (revk_blk + offset)));
325 if (blocknr == blknr)
330 tmp_revk_node = tmp_revk_node->next;
340 * This function parses the journal blocks and replays the
341 * suceessful transactions. A transaction is successfull
342 * if commit block is found for a descriptor block
343 * The tags in descriptor block contain the disk block
344 * numbers of the metadata to be replayed
346 void recover_transaction(int prev_desc_logical_no)
348 struct ext2_inode inode_journal;
349 struct ext_filesystem *fs = get_fs();
350 struct journal_header_t *jdb;
355 struct ext3_journal_block_tag *tag;
356 char *temp_buff = zalloc(fs->blksz);
357 char *metadata_buff = zalloc(fs->blksz);
358 if (!temp_buff || !metadata_buff)
360 i = prev_desc_logical_no;
361 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
362 (struct ext2_inode *)&inode_journal);
363 blknr = read_allocated_block((struct ext2_inode *)
365 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
366 p_jdb = (char *)temp_buff;
367 jdb = (struct journal_header_t *) temp_buff;
368 ofs = sizeof(struct journal_header_t);
371 tag = (struct ext3_journal_block_tag *)&p_jdb[ofs];
372 ofs += sizeof(struct ext3_journal_block_tag);
377 flags = be32_to_cpu(tag->flags);
378 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
382 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
383 if (revk_blk_list != NULL) {
384 if (check_blknr_for_revoke(be32_to_cpu(tag->block),
385 be32_to_cpu(jdb->h_sequence)) == 0)
388 blknr = read_allocated_block(&inode_journal, i);
389 ext4fs_devread(blknr * fs->sect_perblk, 0,
390 fs->blksz, metadata_buff);
391 put_ext4((uint64_t)(be32_to_cpu(tag->block) * fs->blksz),
392 metadata_buff, (uint32_t) fs->blksz);
393 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
399 void print_jrnl_status(int recovery_flag)
401 if (recovery_flag == RECOVER)
402 printf("Journal Recovery Completed\n");
404 printf("Journal Scan Completed\n");
407 int ext4fs_check_journal_state(int recovery_flag)
412 int transaction_state = TRANSACTION_COMPLETE;
413 int prev_desc_logical_no = 0;
414 int curr_desc_logical_no = 0;
416 struct ext2_inode inode_journal;
417 struct journal_superblock_t *jsb = NULL;
418 struct journal_header_t *jdb = NULL;
420 struct ext3_journal_block_tag *tag = NULL;
421 char *temp_buff = NULL;
422 char *temp_buff1 = NULL;
423 struct ext_filesystem *fs = get_fs();
425 temp_buff = zalloc(fs->blksz);
428 temp_buff1 = zalloc(fs->blksz);
434 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
435 blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
436 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
437 jsb = (struct journal_superblock_t *) temp_buff;
439 if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
440 if (recovery_flag == RECOVER)
441 printf("Recovery required\n");
443 if (recovery_flag == RECOVER)
444 printf("File System is consistent\n");
448 if (be32_to_cpu(jsb->s_start) == 0)
451 if (!(jsb->s_feature_compat &
452 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
453 jsb->s_feature_compat |=
454 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
456 i = be32_to_cpu(jsb->s_first);
458 blknr = read_allocated_block(&inode_journal, i);
459 memset(temp_buff1, '\0', fs->blksz);
460 ext4fs_devread(blknr * fs->sect_perblk,
461 0, fs->blksz, temp_buff1);
462 jdb = (struct journal_header_t *) temp_buff1;
464 if (be32_to_cpu(jdb->h_blocktype) ==
465 EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
466 if (be32_to_cpu(jdb->h_sequence) !=
467 be32_to_cpu(jsb->s_sequence)) {
468 print_jrnl_status(recovery_flag);
472 curr_desc_logical_no = i;
473 if (transaction_state == TRANSACTION_COMPLETE)
474 transaction_state = TRANSACTION_RUNNING;
477 p_jdb = (char *)temp_buff1;
478 ofs = sizeof(struct journal_header_t);
480 tag = (struct ext3_journal_block_tag *)
482 ofs += sizeof(struct ext3_journal_block_tag);
485 flags = be32_to_cpu(tag->flags);
486 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
489 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
490 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
493 } else if (be32_to_cpu(jdb->h_blocktype) ==
494 EXT3_JOURNAL_COMMIT_BLOCK) {
495 if (be32_to_cpu(jdb->h_sequence) !=
496 be32_to_cpu(jsb->s_sequence)) {
497 print_jrnl_status(recovery_flag);
501 if (transaction_state == TRANSACTION_RUNNING ||
503 transaction_state = TRANSACTION_COMPLETE;
506 cpu_to_be32(be32_to_cpu(
507 jsb->s_sequence) + 1);
509 prev_desc_logical_no = curr_desc_logical_no;
510 if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
511 recover_transaction(prev_desc_logical_no);
514 } else if (be32_to_cpu(jdb->h_blocktype) ==
515 EXT3_JOURNAL_REVOKE_BLOCK) {
516 if (be32_to_cpu(jdb->h_sequence) !=
517 be32_to_cpu(jsb->s_sequence)) {
518 print_jrnl_status(recovery_flag);
521 if (recovery_flag == SCAN)
522 ext4fs_push_revoke_blk((char *)jdb);
525 debug("Else Case\n");
526 if (be32_to_cpu(jdb->h_sequence) !=
527 be32_to_cpu(jsb->s_sequence)) {
528 print_jrnl_status(recovery_flag);
535 if (recovery_flag == RECOVER) {
536 jsb->s_start = cpu_to_be32(1);
537 jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
538 /* get the superblock */
539 ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
541 fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
543 /* Update the super block */
544 put_ext4((uint64_t) (SUPERBLOCK_SIZE),
545 (struct ext2_sblock *)fs->sb,
546 (uint32_t) SUPERBLOCK_SIZE);
547 ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
550 blknr = read_allocated_block(&inode_journal,
551 EXT2_JOURNAL_SUPERBLOCK);
552 put_ext4((uint64_t) (blknr * fs->blksz),
553 (struct journal_superblock_t *)temp_buff,
554 (uint32_t) fs->blksz);
555 ext4fs_free_revoke_blks();
563 static void update_descriptor_block(long int blknr)
567 struct journal_header_t jdb;
568 struct ext3_journal_block_tag tag;
569 struct ext2_inode inode_journal;
570 struct journal_superblock_t *jsb = NULL;
573 struct ext_filesystem *fs = get_fs();
574 char *temp_buff = zalloc(fs->blksz);
578 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
579 jsb_blknr = read_allocated_block(&inode_journal,
580 EXT2_JOURNAL_SUPERBLOCK);
581 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
582 jsb = (struct journal_superblock_t *) temp_buff;
584 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
585 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
586 jdb.h_sequence = jsb->s_sequence;
587 buf = zalloc(fs->blksz);
593 memcpy(buf, &jdb, sizeof(struct journal_header_t));
594 temp += sizeof(struct journal_header_t);
596 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
597 if (journal_ptr[i]->blknr == -1)
600 tag.block = cpu_to_be32(journal_ptr[i]->blknr);
601 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
602 memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
603 temp = temp + sizeof(struct ext3_journal_block_tag);
606 tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
607 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
608 memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
609 sizeof(struct ext3_journal_block_tag));
610 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
616 static void update_commit_block(long int blknr)
618 struct journal_header_t jdb;
619 struct ext_filesystem *fs = get_fs();
621 struct ext2_inode inode_journal;
622 struct journal_superblock_t *jsb;
624 char *temp_buff = zalloc(fs->blksz);
628 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
629 jsb_blknr = read_allocated_block(&inode_journal,
630 EXT2_JOURNAL_SUPERBLOCK);
631 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
632 jsb = (struct journal_superblock_t *) temp_buff;
634 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
635 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
636 jdb.h_sequence = jsb->s_sequence;
637 buf = zalloc(fs->blksz);
642 memcpy(buf, &jdb, sizeof(struct journal_header_t));
643 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
649 void ext4fs_update_journal(void)
651 struct ext2_inode inode_journal;
652 struct ext_filesystem *fs = get_fs();
655 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
656 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
657 update_descriptor_block(blknr);
658 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
659 if (journal_ptr[i]->blknr == -1)
661 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
662 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
663 journal_ptr[i]->buf, fs->blksz);
665 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
666 update_commit_block(blknr);
667 printf("update journal finished\n");