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 static struct revoke_blk_list *revk_blk_list;
39 static struct revoke_blk_list *prev_node;
40 static int first_node = true;
45 struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
46 struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
48 int ext4fs_init_journal(void)
52 struct ext_filesystem *fs = get_fs();
61 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
62 journal_ptr[i] = zalloc(sizeof(struct journal_log));
65 dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
66 if (!dirty_block_ptr[i])
68 journal_ptr[i]->buf = NULL;
69 journal_ptr[i]->blknr = -1;
71 dirty_block_ptr[i]->buf = NULL;
72 dirty_block_ptr[i]->blknr = -1;
75 if (fs->blksz == 4096) {
76 temp = zalloc(fs->blksz);
79 journal_ptr[gindex]->buf = zalloc(fs->blksz);
80 if (!journal_ptr[gindex]->buf)
82 ext4fs_devread(0, 0, fs->blksz, temp);
83 memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
84 memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
85 journal_ptr[gindex++]->blknr = 0;
88 journal_ptr[gindex]->buf = zalloc(fs->blksz);
89 if (!journal_ptr[gindex]->buf)
91 memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
92 journal_ptr[gindex++]->blknr = 1;
95 /* Check the file system state using journal super block */
96 if (ext4fs_check_journal_state(SCAN))
98 /* Check the file system state using journal super block */
99 if (ext4fs_check_journal_state(RECOVER))
107 void ext4fs_dump_metadata(void)
109 struct ext_filesystem *fs = get_fs();
111 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
112 if (dirty_block_ptr[i]->blknr == -1)
114 put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
115 (uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
120 void ext4fs_free_journal(void)
123 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
124 if (dirty_block_ptr[i]->blknr == -1)
126 if (dirty_block_ptr[i]->buf)
127 free(dirty_block_ptr[i]->buf);
130 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
131 if (journal_ptr[i]->blknr == -1)
133 if (journal_ptr[i]->buf)
134 free(journal_ptr[i]->buf);
137 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
139 free(journal_ptr[i]);
140 if (dirty_block_ptr[i])
141 free(dirty_block_ptr[i]);
148 int ext4fs_log_gdt(char *gd_table)
150 struct ext_filesystem *fs = get_fs();
152 long int var = fs->gdtable_blkno;
153 for (i = 0; i < fs->no_blk_pergdt; i++) {
154 journal_ptr[gindex]->buf = zalloc(fs->blksz);
155 if (!journal_ptr[gindex]->buf)
157 memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
158 gd_table += fs->blksz;
159 journal_ptr[gindex++]->blknr = var++;
166 * This function stores the backup copy of meta data in RAM
167 * journal_buffer -- Buffer containing meta data
168 * blknr -- Block number on disk of the meta data buffer
170 int ext4fs_log_journal(char *journal_buffer, long int blknr)
172 struct ext_filesystem *fs = get_fs();
175 if (!journal_buffer) {
176 printf("Invalid input arguments %s\n", __func__);
180 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
181 if (journal_ptr[i]->blknr == -1)
183 if (journal_ptr[i]->blknr == blknr)
187 journal_ptr[gindex]->buf = zalloc(fs->blksz);
188 if (!journal_ptr[gindex]->buf)
191 memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
192 journal_ptr[gindex++]->blknr = blknr;
198 * This function stores the modified meta data in RAM
199 * metadata_buffer -- Buffer containing meta data
200 * blknr -- Block number on disk of the meta data buffer
202 int ext4fs_put_metadata(char *metadata_buffer, long int blknr)
204 struct ext_filesystem *fs = get_fs();
205 if (!metadata_buffer) {
206 printf("Invalid input arguments %s\n", __func__);
209 dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
210 if (!dirty_block_ptr[gd_index]->buf)
212 memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
213 dirty_block_ptr[gd_index++]->blknr = blknr;
218 void print_revoke_blks(char *revk_blk)
223 struct journal_revoke_header_t *header;
225 if (revk_blk == NULL)
228 header = (struct journal_revoke_header_t *) revk_blk;
229 offset = sizeof(struct journal_revoke_header_t);
230 max = be32_to_cpu(header->r_count);
231 printf("total bytes %d\n", max);
233 while (offset < max) {
234 blocknr = be32_to_cpu(*((long int *)(revk_blk + offset)));
235 printf("revoke blknr is %ld\n", blocknr);
240 static struct revoke_blk_list *_get_node(void)
242 struct revoke_blk_list *tmp_node;
243 tmp_node = zalloc(sizeof(struct revoke_blk_list));
244 if (tmp_node == NULL)
246 tmp_node->content = NULL;
247 tmp_node->next = NULL;
252 void ext4fs_push_revoke_blk(char *buffer)
254 struct revoke_blk_list *node = NULL;
255 struct ext_filesystem *fs = get_fs();
256 if (buffer == NULL) {
257 printf("buffer ptr is NULL\n");
262 printf("_get_node: malloc failed\n");
266 node->content = zalloc(fs->blksz);
267 if (node->content == NULL)
269 memcpy(node->content, buffer, fs->blksz);
271 if (first_node == true) {
272 revk_blk_list = node;
276 prev_node->next = node;
281 void ext4fs_free_revoke_blks(void)
283 struct revoke_blk_list *tmp_node = revk_blk_list;
284 struct revoke_blk_list *next_node = NULL;
286 while (tmp_node != NULL) {
287 if (tmp_node->content)
288 free(tmp_node->content);
289 tmp_node = tmp_node->next;
292 tmp_node = revk_blk_list;
293 while (tmp_node != NULL) {
294 next_node = tmp_node->next;
296 tmp_node = next_node;
299 revk_blk_list = NULL;
304 int check_blknr_for_revoke(long int blknr, int sequence_no)
306 struct journal_revoke_header_t *header;
311 struct revoke_blk_list *tmp_revk_node = revk_blk_list;
312 while (tmp_revk_node != NULL) {
313 revk_blk = tmp_revk_node->content;
315 header = (struct journal_revoke_header_t *) revk_blk;
316 if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
317 offset = sizeof(struct journal_revoke_header_t);
318 max = be32_to_cpu(header->r_count);
320 while (offset < max) {
321 blocknr = be32_to_cpu(*((long int *)
322 (revk_blk + offset)));
323 if (blocknr == blknr)
328 tmp_revk_node = tmp_revk_node->next;
338 * This function parses the journal blocks and replays the
339 * suceessful transactions. A transaction is successfull
340 * if commit block is found for a descriptor block
341 * The tags in descriptor block contain the disk block
342 * numbers of the metadata to be replayed
344 void recover_transaction(int prev_desc_logical_no)
346 struct ext2_inode inode_journal;
347 struct ext_filesystem *fs = get_fs();
348 struct journal_header_t *jdb;
353 struct ext3_journal_block_tag *tag;
354 char *temp_buff = zalloc(fs->blksz);
355 char *metadata_buff = zalloc(fs->blksz);
356 if (!temp_buff || !metadata_buff)
358 i = prev_desc_logical_no;
359 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
360 (struct ext2_inode *)&inode_journal);
361 blknr = read_allocated_block((struct ext2_inode *)
363 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
364 p_jdb = (char *)temp_buff;
365 jdb = (struct journal_header_t *) temp_buff;
366 ofs = sizeof(struct journal_header_t);
369 tag = (struct ext3_journal_block_tag *)&p_jdb[ofs];
370 ofs += sizeof(struct ext3_journal_block_tag);
375 flags = be32_to_cpu(tag->flags);
376 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
380 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
381 if (revk_blk_list != NULL) {
382 if (check_blknr_for_revoke(be32_to_cpu(tag->block),
383 be32_to_cpu(jdb->h_sequence)) == 0)
386 blknr = read_allocated_block(&inode_journal, i);
387 ext4fs_devread(blknr * fs->sect_perblk, 0,
388 fs->blksz, metadata_buff);
389 put_ext4((uint64_t)(be32_to_cpu(tag->block) * fs->blksz),
390 metadata_buff, (uint32_t) fs->blksz);
391 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
397 void print_jrnl_status(int recovery_flag)
399 if (recovery_flag == RECOVER)
400 printf("Journal Recovery Completed\n");
402 printf("Journal Scan Completed\n");
405 int ext4fs_check_journal_state(int recovery_flag)
410 int transaction_state = TRANSACTION_COMPLETE;
411 int prev_desc_logical_no = 0;
412 int curr_desc_logical_no = 0;
414 struct ext2_inode inode_journal;
415 struct journal_superblock_t *jsb = NULL;
416 struct journal_header_t *jdb = NULL;
418 struct ext3_journal_block_tag *tag = NULL;
419 char *temp_buff = NULL;
420 char *temp_buff1 = NULL;
421 struct ext_filesystem *fs = get_fs();
423 temp_buff = zalloc(fs->blksz);
426 temp_buff1 = zalloc(fs->blksz);
432 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
433 blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
434 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
435 jsb = (struct journal_superblock_t *) temp_buff;
437 if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
438 if (recovery_flag == RECOVER)
439 printf("Recovery required\n");
441 if (recovery_flag == RECOVER)
442 printf("File System is consistent\n");
446 if (be32_to_cpu(jsb->s_start) == 0)
449 if (!(jsb->s_feature_compat &
450 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
451 jsb->s_feature_compat |=
452 cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
454 i = be32_to_cpu(jsb->s_first);
456 blknr = read_allocated_block(&inode_journal, i);
457 memset(temp_buff1, '\0', fs->blksz);
458 ext4fs_devread(blknr * fs->sect_perblk,
459 0, fs->blksz, temp_buff1);
460 jdb = (struct journal_header_t *) temp_buff1;
462 if (be32_to_cpu(jdb->h_blocktype) ==
463 EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
464 if (be32_to_cpu(jdb->h_sequence) !=
465 be32_to_cpu(jsb->s_sequence)) {
466 print_jrnl_status(recovery_flag);
470 curr_desc_logical_no = i;
471 if (transaction_state == TRANSACTION_COMPLETE)
472 transaction_state = TRANSACTION_RUNNING;
475 p_jdb = (char *)temp_buff1;
476 ofs = sizeof(struct journal_header_t);
478 tag = (struct ext3_journal_block_tag *)
480 ofs += sizeof(struct ext3_journal_block_tag);
483 flags = be32_to_cpu(tag->flags);
484 if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
487 debug("\t\ttag %u\n", be32_to_cpu(tag->block));
488 } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
491 } else if (be32_to_cpu(jdb->h_blocktype) ==
492 EXT3_JOURNAL_COMMIT_BLOCK) {
493 if (be32_to_cpu(jdb->h_sequence) !=
494 be32_to_cpu(jsb->s_sequence)) {
495 print_jrnl_status(recovery_flag);
499 if (transaction_state == TRANSACTION_RUNNING ||
501 transaction_state = TRANSACTION_COMPLETE;
504 cpu_to_be32(be32_to_cpu(
505 jsb->s_sequence) + 1);
507 prev_desc_logical_no = curr_desc_logical_no;
508 if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
509 recover_transaction(prev_desc_logical_no);
512 } else if (be32_to_cpu(jdb->h_blocktype) ==
513 EXT3_JOURNAL_REVOKE_BLOCK) {
514 if (be32_to_cpu(jdb->h_sequence) !=
515 be32_to_cpu(jsb->s_sequence)) {
516 print_jrnl_status(recovery_flag);
519 if (recovery_flag == SCAN)
520 ext4fs_push_revoke_blk((char *)jdb);
523 debug("Else Case\n");
524 if (be32_to_cpu(jdb->h_sequence) !=
525 be32_to_cpu(jsb->s_sequence)) {
526 print_jrnl_status(recovery_flag);
533 if (recovery_flag == RECOVER) {
534 jsb->s_start = cpu_to_be32(1);
535 jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
536 /* get the superblock */
537 ext4_read_superblock((char *)fs->sb);
538 fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
540 /* Update the super block */
541 put_ext4((uint64_t) (SUPERBLOCK_SIZE),
542 (struct ext2_sblock *)fs->sb,
543 (uint32_t) SUPERBLOCK_SIZE);
544 ext4_read_superblock((char *)fs->sb);
546 blknr = read_allocated_block(&inode_journal,
547 EXT2_JOURNAL_SUPERBLOCK);
548 put_ext4((uint64_t) (blknr * fs->blksz),
549 (struct journal_superblock_t *)temp_buff,
550 (uint32_t) fs->blksz);
551 ext4fs_free_revoke_blks();
559 static void update_descriptor_block(long int blknr)
563 struct journal_header_t jdb;
564 struct ext3_journal_block_tag tag;
565 struct ext2_inode inode_journal;
566 struct journal_superblock_t *jsb = NULL;
569 struct ext_filesystem *fs = get_fs();
570 char *temp_buff = zalloc(fs->blksz);
574 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
575 jsb_blknr = read_allocated_block(&inode_journal,
576 EXT2_JOURNAL_SUPERBLOCK);
577 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
578 jsb = (struct journal_superblock_t *) temp_buff;
580 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
581 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
582 jdb.h_sequence = jsb->s_sequence;
583 buf = zalloc(fs->blksz);
589 memcpy(buf, &jdb, sizeof(struct journal_header_t));
590 temp += sizeof(struct journal_header_t);
592 for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
593 if (journal_ptr[i]->blknr == -1)
596 tag.block = cpu_to_be32(journal_ptr[i]->blknr);
597 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
598 memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
599 temp = temp + sizeof(struct ext3_journal_block_tag);
602 tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
603 tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
604 memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
605 sizeof(struct ext3_journal_block_tag));
606 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
612 static void update_commit_block(long int blknr)
614 struct journal_header_t jdb;
615 struct ext_filesystem *fs = get_fs();
617 struct ext2_inode inode_journal;
618 struct journal_superblock_t *jsb;
620 char *temp_buff = zalloc(fs->blksz);
624 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
625 jsb_blknr = read_allocated_block(&inode_journal,
626 EXT2_JOURNAL_SUPERBLOCK);
627 ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
628 jsb = (struct journal_superblock_t *) temp_buff;
630 jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
631 jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
632 jdb.h_sequence = jsb->s_sequence;
633 buf = zalloc(fs->blksz);
638 memcpy(buf, &jdb, sizeof(struct journal_header_t));
639 put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
645 void ext4fs_update_journal(void)
647 struct ext2_inode inode_journal;
648 struct ext_filesystem *fs = get_fs();
651 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
652 blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
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++);
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++);
662 update_commit_block(blknr);
663 printf("update journal finished\n");