Signed-off-by: Uma Shankar <uma.shankar@samsung.com> Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com> Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com> Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>master
parent
a1596438a6
commit
ed34f34dba
@ -0,0 +1,46 @@ |
||||
This patch series adds support for ext4 ls,load and write features in uboot |
||||
Journaling is supported for write feature. |
||||
|
||||
To Enable ext2 ls and load commands, modify the board specific config file with |
||||
#define CONFIG_CMD_EXT2 |
||||
|
||||
To Enable ext4 ls and load commands, modify the board specific config file with |
||||
#define CONFIG_CMD_EXT4 |
||||
|
||||
To enable ext4 write command, modify the board specific config file with |
||||
#define CONFIG_CMD_EXT4 |
||||
#define CONFIG_CMD_EXT4_WRITE |
||||
|
||||
Steps to test: |
||||
|
||||
1. After applying the patch, ext4 specific commands can be seen |
||||
in the boot loader prompt using |
||||
UBOOT #help |
||||
|
||||
ext4load- load binary file from a Ext4 file system |
||||
ext4ls - list files in a directory (default /) |
||||
ext4write- create a file in ext4 formatted partition |
||||
|
||||
2. To list the files in ext4 formatted partition, execute |
||||
ext4ls <interface> <dev[:part]> [directory] |
||||
For example: |
||||
UBOOT #ext4ls mmc 0:5 /usr/lib |
||||
|
||||
3. To read and load a file from an ext4 formatted partition to RAM, execute |
||||
ext4load <interface> <dev[:part]> [addr] [filename] [bytes] |
||||
For example: |
||||
UBOOT #ext4load mmc 2:2 0x30007fc0 uImage |
||||
|
||||
4. To write a file to a ext4 formatted partition. |
||||
a) First load a file to RAM at a particular address for example 0x30007fc0. |
||||
Now execute ext4write command |
||||
ext4write <interface> <dev[:part]> [filename] [Address] [sizebytes] |
||||
For example: |
||||
UBOOT #ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120 |
||||
(here 6183120 is the size of the file to be written) |
||||
Note: Absolute path is required for the file to be written |
||||
|
||||
References : |
||||
-- ext4 implementation in Linux Kernel |
||||
-- Uboot existing ext2 load and ls implementation |
||||
-- Journaling block device JBD2 implementation in linux Kernel |
@ -0,0 +1,62 @@ |
||||
/*
|
||||
* crc16.c |
||||
* |
||||
* This source code is licensed under the GNU General Public License, |
||||
* Version 2. See the file COPYING for more details. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/byteorder.h> |
||||
#include <linux/stat.h> |
||||
#include "crc16.h" |
||||
|
||||
/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */ |
||||
static __u16 const crc16_table[256] = { |
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, |
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, |
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, |
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, |
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, |
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, |
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, |
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, |
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, |
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, |
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, |
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, |
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, |
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, |
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, |
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, |
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, |
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, |
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, |
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, |
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, |
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, |
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, |
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, |
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, |
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, |
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, |
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, |
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, |
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, |
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, |
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 |
||||
}; |
||||
|
||||
/**
|
||||
* Compute the CRC-16 for the data buffer |
||||
*/ |
||||
|
||||
unsigned int ext2fs_crc16(unsigned int crc, |
||||
const void *buffer, unsigned int len) |
||||
{ |
||||
const unsigned char *cp = buffer; |
||||
|
||||
while (len--) |
||||
crc = (((crc >> 8) & 0xffU) ^ |
||||
crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; |
||||
return crc; |
||||
} |
@ -0,0 +1,16 @@ |
||||
/*
|
||||
* crc16.h - CRC-16 routine |
||||
* Implements the standard CRC-16: |
||||
* Width 16 |
||||
* Poly 0x8005 (x16 + x15 + x2 + 1) |
||||
* Init 0 |
||||
* |
||||
* Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> |
||||
* This source code is licensed under the GNU General Public License, |
||||
* Version 2. See the file COPYING for more details. |
||||
*/ |
||||
#ifndef __CRC16_H |
||||
#define __CRC16_H |
||||
extern unsigned int ext2fs_crc16(unsigned int crc, |
||||
const void *buffer, unsigned int len); |
||||
#endif |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,667 @@ |
||||
/*
|
||||
* (C) Copyright 2011 - 2012 Samsung Electronics |
||||
* EXT4 filesystem implementation in Uboot by |
||||
* Uma Shankar <uma.shankar@samsung.com> |
||||
* Manjunatha C Achar <a.manjunatha@samsung.com> |
||||
* |
||||
* Journal data structures and headers for Journaling feature of ext4 |
||||
* have been referred from JBD2 (Journaling Block device 2) |
||||
* implementation in Linux Kernel. |
||||
* Written by Stephen C. Tweedie <sct@redhat.com> |
||||
* |
||||
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved |
||||
* This file is part of the Linux kernel and is made available under |
||||
* the terms of the GNU General Public License, version 2, or at your |
||||
* option, any later version, incorporated herein by reference. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <ext4fs.h> |
||||
#include <malloc.h> |
||||
#include <ext_common.h> |
||||
#include "ext4_common.h" |
||||
|
||||
static struct revoke_blk_list *revk_blk_list; |
||||
static struct revoke_blk_list *prev_node; |
||||
static int first_node = TRUE; |
||||
|
||||
int gindex; |
||||
int gd_index; |
||||
int jrnl_blk_idx; |
||||
struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES]; |
||||
struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES]; |
||||
|
||||
int ext4fs_init_journal(void) |
||||
{ |
||||
int i; |
||||
char *temp = NULL; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
|
||||
/* init globals */ |
||||
revk_blk_list = NULL; |
||||
prev_node = NULL; |
||||
gindex = 0; |
||||
gd_index = 0; |
||||
jrnl_blk_idx = 1; |
||||
|
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
journal_ptr[i] = zalloc(sizeof(struct journal_log)); |
||||
if (!journal_ptr[i]) |
||||
goto fail; |
||||
dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks)); |
||||
if (!dirty_block_ptr[i]) |
||||
goto fail; |
||||
journal_ptr[i]->buf = NULL; |
||||
journal_ptr[i]->blknr = -1; |
||||
|
||||
dirty_block_ptr[i]->buf = NULL; |
||||
dirty_block_ptr[i]->blknr = -1; |
||||
} |
||||
|
||||
if (fs->blksz == 4096) { |
||||
temp = zalloc(fs->blksz); |
||||
if (!temp) |
||||
goto fail; |
||||
journal_ptr[gindex]->buf = zalloc(fs->blksz); |
||||
if (!journal_ptr[gindex]->buf) |
||||
goto fail; |
||||
ext4fs_devread(0, 0, fs->blksz, temp); |
||||
memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE); |
||||
memcpy(journal_ptr[gindex]->buf, temp, fs->blksz); |
||||
journal_ptr[gindex++]->blknr = 0; |
||||
free(temp); |
||||
} else { |
||||
journal_ptr[gindex]->buf = zalloc(fs->blksz); |
||||
if (!journal_ptr[gindex]->buf) |
||||
goto fail; |
||||
memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE); |
||||
journal_ptr[gindex++]->blknr = 1; |
||||
} |
||||
|
||||
/* Check the file system state using journal super block */ |
||||
if (ext4fs_check_journal_state(SCAN)) |
||||
goto fail; |
||||
/* Check the file system state using journal super block */ |
||||
if (ext4fs_check_journal_state(RECOVER)) |
||||
goto fail; |
||||
|
||||
return 0; |
||||
fail: |
||||
return -1; |
||||
} |
||||
|
||||
void ext4fs_dump_metadata(void) |
||||
{ |
||||
struct ext_filesystem *fs = get_fs(); |
||||
int i; |
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (dirty_block_ptr[i]->blknr == -1) |
||||
break; |
||||
put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr * |
||||
(uint64_t)fs->blksz), dirty_block_ptr[i]->buf, |
||||
fs->blksz); |
||||
} |
||||
} |
||||
|
||||
void ext4fs_free_journal(void) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (dirty_block_ptr[i]->blknr == -1) |
||||
break; |
||||
if (dirty_block_ptr[i]->buf) |
||||
free(dirty_block_ptr[i]->buf); |
||||
} |
||||
|
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (journal_ptr[i]->blknr == -1) |
||||
break; |
||||
if (journal_ptr[i]->buf) |
||||
free(journal_ptr[i]->buf); |
||||
} |
||||
|
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (journal_ptr[i]) |
||||
free(journal_ptr[i]); |
||||
if (dirty_block_ptr[i]) |
||||
free(dirty_block_ptr[i]); |
||||
} |
||||
gindex = 0; |
||||
gd_index = 0; |
||||
jrnl_blk_idx = 1; |
||||
} |
||||
|
||||
int ext4fs_log_gdt(char *gd_table) |
||||
{ |
||||
struct ext_filesystem *fs = get_fs(); |
||||
short i; |
||||
long int var = fs->gdtable_blkno; |
||||
for (i = 0; i < fs->no_blk_pergdt; i++) { |
||||
journal_ptr[gindex]->buf = zalloc(fs->blksz); |
||||
if (!journal_ptr[gindex]->buf) |
||||
return -ENOMEM; |
||||
memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz); |
||||
gd_table += fs->blksz; |
||||
journal_ptr[gindex++]->blknr = var++; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* This function stores the backup copy of meta data in RAM |
||||
* journal_buffer -- Buffer containing meta data |
||||
* blknr -- Block number on disk of the meta data buffer |
||||
*/ |
||||
int ext4fs_log_journal(char *journal_buffer, long int blknr) |
||||
{ |
||||
struct ext_filesystem *fs = get_fs(); |
||||
short i; |
||||
|
||||
if (!journal_buffer) { |
||||
printf("Invalid input arguments %s\n", __func__); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (journal_ptr[i]->blknr == -1) |
||||
break; |
||||
if (journal_ptr[i]->blknr == blknr) |
||||
return 0; |
||||
} |
||||
|
||||
journal_ptr[gindex]->buf = zalloc(fs->blksz); |
||||
if (!journal_ptr[gindex]->buf) |
||||
return -ENOMEM; |
||||
|
||||
memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz); |
||||
journal_ptr[gindex++]->blknr = blknr; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* This function stores the modified meta data in RAM |
||||
* metadata_buffer -- Buffer containing meta data |
||||
* blknr -- Block number on disk of the meta data buffer |
||||
*/ |
||||
int ext4fs_put_metadata(char *metadata_buffer, long int blknr) |
||||
{ |
||||
struct ext_filesystem *fs = get_fs(); |
||||
if (!metadata_buffer) { |
||||
printf("Invalid input arguments %s\n", __func__); |
||||
return -EINVAL; |
||||
} |
||||
dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz); |
||||
if (!dirty_block_ptr[gd_index]->buf) |
||||
return -ENOMEM; |
||||
memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz); |
||||
dirty_block_ptr[gd_index++]->blknr = blknr; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void print_revoke_blks(char *revk_blk) |
||||
{ |
||||
int offset; |
||||
int max; |
||||
long int blocknr; |
||||
struct journal_revoke_header_t *header; |
||||
|
||||
if (revk_blk == NULL) |
||||
return; |
||||
|
||||
header = (struct journal_revoke_header_t *) revk_blk; |
||||
offset = sizeof(struct journal_revoke_header_t); |
||||
max = be32_to_cpu(header->r_count); |
||||
printf("total bytes %d\n", max); |
||||
|
||||
while (offset < max) { |
||||
blocknr = be32_to_cpu(*((long int *)(revk_blk + offset))); |
||||
printf("revoke blknr is %ld\n", blocknr); |
||||
offset += 4; |
||||
} |
||||
} |
||||
|
||||
static struct revoke_blk_list *_get_node(void) |
||||
{ |
||||
struct revoke_blk_list *tmp_node; |
||||
tmp_node = zalloc(sizeof(struct revoke_blk_list)); |
||||
if (tmp_node == NULL) |
||||
return NULL; |
||||
tmp_node->content = NULL; |
||||
tmp_node->next = NULL; |
||||
|
||||
return tmp_node; |
||||
} |
||||
|
||||
void ext4fs_push_revoke_blk(char *buffer) |
||||
{ |
||||
struct revoke_blk_list *node = NULL; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
if (buffer == NULL) { |
||||
printf("buffer ptr is NULL\n"); |
||||
return; |
||||
} |
||||
node = _get_node(); |
||||
if (!node) { |
||||
printf("_get_node: malloc failed\n"); |
||||
return; |
||||
} |
||||
|
||||
node->content = zalloc(fs->blksz); |
||||
if (node->content == NULL) |
||||
return; |
||||
memcpy(node->content, buffer, fs->blksz); |
||||
|
||||
if (first_node == TRUE) { |
||||
revk_blk_list = node; |
||||
prev_node = node; |
||||
first_node = FALSE; |
||||
} else { |
||||
prev_node->next = node; |
||||
prev_node = node; |
||||
} |
||||
} |
||||
|
||||
void ext4fs_free_revoke_blks(void) |
||||
{ |
||||
struct revoke_blk_list *tmp_node = revk_blk_list; |
||||
struct revoke_blk_list *next_node = NULL; |
||||
|
||||
while (tmp_node != NULL) { |
||||
if (tmp_node->content) |
||||
free(tmp_node->content); |
||||
tmp_node = tmp_node->next; |
||||
} |
||||
|
||||
tmp_node = revk_blk_list; |
||||
while (tmp_node != NULL) { |
||||
next_node = tmp_node->next; |
||||
free(tmp_node); |
||||
tmp_node = next_node; |
||||
} |
||||
|
||||
revk_blk_list = NULL; |
||||
prev_node = NULL; |
||||
first_node = TRUE; |
||||
} |
||||
|
||||
int check_blknr_for_revoke(long int blknr, int sequence_no) |
||||
{ |
||||
struct journal_revoke_header_t *header; |
||||
int offset; |
||||
int max; |
||||
long int blocknr; |
||||
char *revk_blk; |
||||
struct revoke_blk_list *tmp_revk_node = revk_blk_list; |
||||
while (tmp_revk_node != NULL) { |
||||
revk_blk = tmp_revk_node->content; |
||||
|
||||
header = (struct journal_revoke_header_t *) revk_blk; |
||||
if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) { |
||||
offset = sizeof(struct journal_revoke_header_t); |
||||
max = be32_to_cpu(header->r_count); |
||||
|
||||
while (offset < max) { |
||||
blocknr = be32_to_cpu(*((long int *) |
||||
(revk_blk + offset))); |
||||
if (blocknr == blknr) |
||||
goto found; |
||||
offset += 4; |
||||
} |
||||
} |
||||
tmp_revk_node = tmp_revk_node->next; |
||||
} |
||||
|
||||
return -1; |
||||
|
||||
found: |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* This function parses the journal blocks and replays the |
||||
* suceessful transactions. A transaction is successfull |
||||
* if commit block is found for a descriptor block |
||||
* The tags in descriptor block contain the disk block |
||||
* numbers of the metadata to be replayed |
||||
*/ |
||||
void recover_transaction(int prev_desc_logical_no) |
||||
{ |
||||
struct ext2_inode inode_journal; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
struct journal_header_t *jdb; |
||||
long int blknr; |
||||
char *p_jdb; |
||||
int ofs, flags; |
||||
int i; |
||||
struct ext3_journal_block_tag *tag; |
||||
char *temp_buff = zalloc(fs->blksz); |
||||
char *metadata_buff = zalloc(fs->blksz); |
||||
if (!temp_buff || !metadata_buff) |
||||
goto fail; |
||||
i = prev_desc_logical_no; |
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, |
||||
(struct ext2_inode *)&inode_journal); |
||||
blknr = read_allocated_block((struct ext2_inode *) |
||||
&inode_journal, i); |
||||
ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); |
||||
p_jdb = (char *)temp_buff; |
||||
jdb = (struct journal_header_t *) temp_buff; |
||||
ofs = sizeof(struct journal_header_t); |
||||
|
||||
do { |
||||
tag = (struct ext3_journal_block_tag *)&p_jdb[ofs]; |
||||
ofs += sizeof(struct ext3_journal_block_tag); |
||||
|
||||
if (ofs > fs->blksz) |
||||
break; |
||||
|
||||
flags = be32_to_cpu(tag->flags); |
||||
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) |
||||
ofs += 16; |
||||
|
||||
i++; |
||||
debug("\t\ttag %u\n", be32_to_cpu(tag->block)); |
||||
if (revk_blk_list != NULL) { |
||||
if (check_blknr_for_revoke(be32_to_cpu(tag->block), |
||||
be32_to_cpu(jdb->h_sequence)) == 0) |
||||
continue; |
||||
} |
||||
blknr = read_allocated_block(&inode_journal, i); |
||||
ext4fs_devread(blknr * fs->sect_perblk, 0, |
||||
fs->blksz, metadata_buff); |
||||
put_ext4((uint64_t)(be32_to_cpu(tag->block) * fs->blksz), |
||||
metadata_buff, (uint32_t) fs->blksz); |
||||
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); |
||||
fail: |
||||
free(temp_buff); |
||||
free(metadata_buff); |
||||
} |
||||
|
||||
void print_jrnl_status(int recovery_flag) |
||||
{ |
||||
if (recovery_flag == RECOVER) |
||||
printf("Journal Recovery Completed\n"); |
||||
else |
||||
printf("Journal Scan Completed\n"); |
||||
} |
||||
|
||||
int ext4fs_check_journal_state(int recovery_flag) |
||||
{ |
||||
int i; |
||||
int DB_FOUND = NO; |
||||
long int blknr; |
||||
int transaction_state = TRANSACTION_COMPLETE; |
||||
int prev_desc_logical_no = 0; |
||||
int curr_desc_logical_no = 0; |
||||
int ofs, flags, block; |
||||
struct ext2_inode inode_journal; |
||||
struct journal_superblock_t *jsb = NULL; |
||||
struct journal_header_t *jdb = NULL; |
||||
char *p_jdb = NULL; |
||||
struct ext3_journal_block_tag *tag = NULL; |
||||
char *temp_buff = NULL; |
||||
char *temp_buff1 = NULL; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
|
||||
temp_buff = zalloc(fs->blksz); |
||||
if (!temp_buff) |
||||
return -ENOMEM; |
||||
temp_buff1 = zalloc(fs->blksz); |
||||
if (!temp_buff1) { |
||||
free(temp_buff); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); |
||||
blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK); |
||||
ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); |
||||
jsb = (struct journal_superblock_t *) temp_buff; |
||||
|
||||
if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { |
||||
if (recovery_flag == RECOVER) |
||||
printf("Recovery required\n"); |
||||
} else { |
||||
if (recovery_flag == RECOVER) |
||||
printf("File System is consistent\n"); |
||||
goto end; |
||||
} |
||||
|
||||
if (be32_to_cpu(jsb->s_start) == 0) |
||||
goto end; |
||||
|
||||
if (!(jsb->s_feature_compat & |
||||
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM))) |
||||
jsb->s_feature_compat |= |
||||
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); |
||||
|
||||
i = be32_to_cpu(jsb->s_first); |
||||
while (1) { |
||||
block = be32_to_cpu(jsb->s_first); |
||||
blknr = read_allocated_block(&inode_journal, i); |
||||
memset(temp_buff1, '\0', fs->blksz); |
||||
ext4fs_devread(blknr * fs->sect_perblk, |
||||
0, fs->blksz, temp_buff1); |
||||
jdb = (struct journal_header_t *) temp_buff1; |
||||
|
||||
if (be32_to_cpu(jdb->h_blocktype) == |
||||
EXT3_JOURNAL_DESCRIPTOR_BLOCK) { |
||||
if (be32_to_cpu(jdb->h_sequence) != |
||||
be32_to_cpu(jsb->s_sequence)) { |
||||
print_jrnl_status(recovery_flag); |
||||
break; |
||||
} |
||||
|
||||
curr_desc_logical_no = i; |
||||
if (transaction_state == TRANSACTION_COMPLETE) |
||||
transaction_state = TRANSACTION_RUNNING; |
||||
else |
||||
return -1; |
||||
p_jdb = (char *)temp_buff1; |
||||
ofs = sizeof(struct journal_header_t); |
||||
do { |
||||
tag = (struct ext3_journal_block_tag *) |
||||
&p_jdb[ofs]; |
||||
ofs += sizeof(struct ext3_journal_block_tag); |
||||
if (ofs > fs->blksz) |
||||
break; |
||||
flags = be32_to_cpu(tag->flags); |
||||
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) |
||||
ofs += 16; |
||||
i++; |
||||
debug("\t\ttag %u\n", be32_to_cpu(tag->block)); |
||||
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); |
||||
i++; |
||||
DB_FOUND = YES; |
||||
} else if (be32_to_cpu(jdb->h_blocktype) == |
||||
EXT3_JOURNAL_COMMIT_BLOCK) { |
||||
if (be32_to_cpu(jdb->h_sequence) != |
||||
be32_to_cpu(jsb->s_sequence)) { |
||||
print_jrnl_status(recovery_flag); |
||||
break; |
||||
} |
||||
|
||||
if (transaction_state == TRANSACTION_RUNNING || |
||||
(DB_FOUND == NO)) { |
||||
transaction_state = TRANSACTION_COMPLETE; |
||||
i++; |
||||
jsb->s_sequence = |
||||
cpu_to_be32(be32_to_cpu( |
||||
jsb->s_sequence) + 1); |
||||
} |
||||
prev_desc_logical_no = curr_desc_logical_no; |
||||
if ((recovery_flag == RECOVER) && (DB_FOUND == YES)) |
||||
recover_transaction(prev_desc_logical_no); |
||||
|
||||
DB_FOUND = NO; |
||||
} else if (be32_to_cpu(jdb->h_blocktype) == |
||||
EXT3_JOURNAL_REVOKE_BLOCK) { |
||||
if (be32_to_cpu(jdb->h_sequence) != |
||||
be32_to_cpu(jsb->s_sequence)) { |
||||
print_jrnl_status(recovery_flag); |
||||
break; |
||||
} |
||||
if (recovery_flag == SCAN) |
||||
ext4fs_push_revoke_blk((char *)jdb); |
||||
i++; |
||||
} else { |
||||
debug("Else Case\n"); |
||||
if (be32_to_cpu(jdb->h_sequence) != |
||||
be32_to_cpu(jsb->s_sequence)) { |
||||
print_jrnl_status(recovery_flag); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
end: |
||||
if (recovery_flag == RECOVER) { |
||||
jsb->s_start = cpu_to_be32(1); |
||||
jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); |
||||
/* get the superblock */ |
||||
ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, |
||||
(char *)fs->sb); |
||||
fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; |
||||
|
||||
/* Update the super block */ |
||||
put_ext4((uint64_t) (SUPERBLOCK_SIZE), |
||||
(struct ext2_sblock *)fs->sb, |
||||
(uint32_t) SUPERBLOCK_SIZE); |
||||
ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, |
||||
(char *)fs->sb); |
||||
|
||||
blknr = read_allocated_block(&inode_journal, |
||||
EXT2_JOURNAL_SUPERBLOCK); |
||||
put_ext4((uint64_t) (blknr * fs->blksz), |
||||
(struct journal_superblock_t *)temp_buff, |
||||
(uint32_t) fs->blksz); |
||||
ext4fs_free_revoke_blks(); |
||||
} |
||||
free(temp_buff); |
||||
free(temp_buff1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void update_descriptor_block(long int blknr) |
||||
{ |
||||
int i; |
||||
long int jsb_blknr; |
||||
struct journal_header_t jdb; |
||||
struct ext3_journal_block_tag tag; |
||||
struct ext2_inode inode_journal; |
||||
struct journal_superblock_t *jsb = NULL; |
||||
char *buf = NULL; |
||||
char *temp = NULL; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
char *temp_buff = zalloc(fs->blksz); |
||||
if (!temp_buff) |
||||
return; |
||||
|
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); |
||||
jsb_blknr = read_allocated_block(&inode_journal, |
||||
EXT2_JOURNAL_SUPERBLOCK); |
||||
ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); |
||||
jsb = (struct journal_superblock_t *) temp_buff; |
||||
|
||||
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); |
||||
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); |
||||
jdb.h_sequence = jsb->s_sequence; |
||||
buf = zalloc(fs->blksz); |
||||
if (!buf) { |
||||
free(temp_buff); |
||||
return; |
||||
} |
||||
temp = buf; |
||||
memcpy(buf, &jdb, sizeof(struct journal_header_t)); |
||||
temp += sizeof(struct journal_header_t); |
||||
|
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (journal_ptr[i]->blknr == -1) |
||||
break; |
||||
|
||||
tag.block = cpu_to_be32(journal_ptr[i]->blknr); |
||||
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); |
||||
memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); |
||||
temp = temp + sizeof(struct ext3_journal_block_tag); |
||||
} |
||||
|
||||
tag.block = cpu_to_be32(journal_ptr[--i]->blknr); |
||||
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); |
||||
memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, |
||||
sizeof(struct ext3_journal_block_tag)); |
||||
put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); |
||||
|
||||
free(temp_buff); |
||||
free(buf); |
||||
} |
||||
|
||||
static void update_commit_block(long int blknr) |
||||
{ |
||||
struct journal_header_t jdb; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
char *buf = NULL; |
||||
struct ext2_inode inode_journal; |
||||
struct journal_superblock_t *jsb; |
||||
long int jsb_blknr; |
||||
char *temp_buff = zalloc(fs->blksz); |
||||
if (!temp_buff) |
||||
return; |
||||
|
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); |
||||
jsb_blknr = read_allocated_block(&inode_journal, |
||||
EXT2_JOURNAL_SUPERBLOCK); |
||||
ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); |
||||
jsb = (struct journal_superblock_t *) temp_buff; |
||||
|
||||
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); |
||||
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); |
||||
jdb.h_sequence = jsb->s_sequence; |
||||
buf = zalloc(fs->blksz); |
||||
if (!buf) { |
||||
free(temp_buff); |
||||
return; |
||||
} |
||||
memcpy(buf, &jdb, sizeof(struct journal_header_t)); |
||||
put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz); |
||||
|
||||
free(temp_buff); |
||||
free(buf); |
||||
} |
||||
|
||||
void ext4fs_update_journal(void) |
||||
{ |
||||
struct ext2_inode inode_journal; |
||||
struct ext_filesystem *fs = get_fs(); |
||||
long int blknr; |
||||
int i; |
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); |
||||
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); |
||||
update_descriptor_block(blknr); |
||||
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { |
||||
if (journal_ptr[i]->blknr == -1) |
||||
break; |
||||
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); |
||||
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), |
||||
journal_ptr[i]->buf, fs->blksz); |
||||
} |
||||
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); |
||||
update_commit_block(blknr); |
||||
printf("update journal finished\n"); |
||||
} |
@ -0,0 +1,141 @@ |
||||
/*
|
||||
* (C) Copyright 2011 - 2012 Samsung Electronics |
||||
* EXT4 filesystem implementation in Uboot by |
||||
* Uma Shankar <uma.shankar@samsung.com> |
||||
* Manjunatha C Achar <a.manjunatha@samsung.com> |
||||
* |
||||
* Journal data structures and headers for Journaling feature of ext4 |
||||
* have been referred from JBD2 (Journaling Block device 2) |
||||
* implementation in Linux Kernel. |
||||
* |
||||
* Written by Stephen C. Tweedie <sct@redhat.com> |
||||
* |
||||
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved |
||||
* This file is part of the Linux kernel and is made available under |
||||
* the terms of the GNU General Public License, version 2, or at your |
||||
* option, any later version, incorporated herein by reference. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
#ifndef __EXT4_JRNL__ |
||||
#define __EXT4_JRNL__ |
||||
|
||||
#define EXT2_JOURNAL_INO 8 /* Journal inode */ |
||||
#define EXT2_JOURNAL_SUPERBLOCK 0 /* Journal Superblock number */ |
||||
|
||||
#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001 |
||||
#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U |
||||
#define TRANSACTION_RUNNING 1 |
||||
#define TRANSACTION_COMPLETE 0 |
||||
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ |
||||
#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 |
||||
#define EXT3_JOURNAL_COMMIT_BLOCK 2 |
||||
#define EXT3_JOURNAL_SUPERBLOCK_V1 3 |
||||
#define EXT3_JOURNAL_SUPERBLOCK_V2 4 |
||||
#define EXT3_JOURNAL_REVOKE_BLOCK 5 |
||||
#define EXT3_JOURNAL_FLAG_ESCAPE 1 |
||||
#define EXT3_JOURNAL_FLAG_SAME_UUID 2 |
||||
#define EXT3_JOURNAL_FLAG_DELETED 4 |
||||
#define EXT3_JOURNAL_FLAG_LAST_TAG 8 |
||||
|
||||
/* Maximum entries in 1 journal transaction */ |
||||
#define MAX_JOURNAL_ENTRIES 100 |
||||
struct journal_log { |
||||
char *buf; |
||||
int blknr; |
||||
}; |
||||
|
||||
struct dirty_blocks { |
||||
char *buf; |
||||
int blknr; |
||||
}; |
||||
|
||||
/* Standard header for all descriptor blocks: */ |
||||
struct journal_header_t { |
||||
__u32 h_magic; |
||||
__u32 h_blocktype; |
||||
__u32 h_sequence; |
||||
}; |
||||
|
||||
/* The journal superblock. All fields are in big-endian byte order. */ |
||||
struct journal_superblock_t { |
||||
/* 0x0000 */ |
||||
struct journal_header_t s_header; |
||||
|
||||
/* Static information describing the journal */ |
||||
__u32 s_blocksize; /* journal device blocksize */ |
||||
__u32 s_maxlen; /* total blocks in journal file */ |
||||
__u32 s_first; /* first block of log information */ |
||||
|
||||
/* Dynamic information describing the current state of the log */ |
||||
__u32 s_sequence; /* first commit ID expected in log */ |
||||
__u32 s_start; /* blocknr of start of log */ |
||||
|
||||
/* Error value, as set by journal_abort(). */ |
||||
__s32 s_errno; |
||||
|
||||
/* Remaining fields are only valid in a version-2 superblock */ |
||||
__u32 s_feature_compat; /* compatible feature set */ |
||||
__u32 s_feature_incompat; /* incompatible feature set */ |
||||
__u32 s_feature_ro_compat; /* readonly-compatible feature set */ |
||||
/* 0x0030 */ |
||||
__u8 s_uuid[16]; /* 128-bit uuid for journal */ |
||||
|
||||
/* 0x0040 */ |
||||
__u32 s_nr_users; /* Nr of filesystems sharing log */ |
||||
|
||||
__u32 s_dynsuper; /* Blocknr of dynamic superblock copy */ |
||||
|
||||
/* 0x0048 */ |
||||
__u32 s_max_transaction; /* Limit of journal blocks per trans. */ |
||||
__u32 s_max_trans_data; /* Limit of data blocks per trans. */ |
||||
|
||||
/* 0x0050 */ |
||||
__u32 s_padding[44]; |
||||
|
||||
/* 0x0100 */ |
||||
__u8 s_users[16 * 48]; /* ids of all fs'es sharing the log */ |
||||
/* 0x0400 */ |
||||
} ; |
||||
|
||||
struct ext3_journal_block_tag { |
||||
uint32_t block; |
||||
uint32_t flags; |
||||
}; |
||||
|
||||
struct journal_revoke_header_t { |
||||
struct journal_header_t r_header; |
||||
int r_count; /* Count of bytes used in the block */ |
||||
}; |
||||
|
||||
struct revoke_blk_list { |
||||
char *content; /* revoke block itself */ |
||||
struct revoke_blk_list *next; |
||||
}; |
||||
|
||||
extern struct ext2_data *ext4fs_root; |
||||
|
||||
int ext4fs_init_journal(void); |
||||
int ext4fs_log_gdt(char *gd_table); |
||||
int ext4fs_check_journal_state(int recovery_flag); |
||||
int ext4fs_log_journal(char *journal_buffer, long int blknr); |
||||
int ext4fs_put_metadata(char *metadata_buffer, long int blknr); |
||||
void ext4fs_update_journal(void); |
||||
void ext4fs_dump_metadata(void); |
||||
void ext4fs_push_revoke_blk(char *buffer); |
||||
void ext4fs_free_journal(void); |
||||
void ext4fs_free_revoke_blks(void); |
||||
#endif |
Loading…
Reference in new issue