GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
config FS_EXT4
|
||||
bool "Enable ext4 filesystem support"
|
||||
help
|
||||
This provides support for reading images from the ext4 filesystem.
|
||||
ext4 is a widely used general-purpose filesystem for Linux.
|
||||
You can also enable CMD_EXT4 to get access to ext4 commands.
|
||||
|
||||
config EXT4_WRITE
|
||||
bool "Enable ext4 filesystem write support"
|
||||
depends on FS_EXT4
|
||||
help
|
||||
This provides support for creating and writing new files to an
|
||||
existing ext4 filesystem partition.
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2003
|
||||
# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
|
||||
#
|
||||
|
||||
obj-y := ext4fs.o ext4_common.o dev.o
|
||||
obj-$(CONFIG_EXT4_WRITE) += ext4_write.o ext4_journal.o crc16.o
|
||||
@@ -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
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (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>
|
||||
*
|
||||
* made from existing ext2/dev.c file of Uboot
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* based on code of fs/reiserfs/dev.c by
|
||||
*
|
||||
* (C) Copyright 2003 - 2004
|
||||
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog:
|
||||
* 0.1 - Newly created file for ext4fs support. Taken from
|
||||
* fs/ext2/dev.c file in uboot.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <blk.h>
|
||||
#include <config.h>
|
||||
#include <fs_internal.h>
|
||||
#include <ext4fs.h>
|
||||
#include <ext_common.h>
|
||||
#include "ext4_common.h"
|
||||
|
||||
lbaint_t part_offset;
|
||||
|
||||
static struct blk_desc *ext4fs_blk_desc;
|
||||
static disk_partition_t *part_info;
|
||||
|
||||
void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info)
|
||||
{
|
||||
assert(rbdd->blksz == (1 << rbdd->log2blksz));
|
||||
ext4fs_blk_desc = rbdd;
|
||||
get_fs()->dev_desc = rbdd;
|
||||
part_info = info;
|
||||
part_offset = info->start;
|
||||
get_fs()->total_sect = ((uint64_t)info->size * info->blksz) >>
|
||||
get_fs()->dev_desc->log2blksz;
|
||||
}
|
||||
|
||||
int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len,
|
||||
char *buffer)
|
||||
{
|
||||
return fs_devread(get_fs()->dev_desc, part_info, sector, byte_offset,
|
||||
byte_len, buffer);
|
||||
}
|
||||
|
||||
int ext4_read_superblock(char *buffer)
|
||||
{
|
||||
struct ext_filesystem *fs = get_fs();
|
||||
int sect = SUPERBLOCK_START >> fs->dev_desc->log2blksz;
|
||||
int off = SUPERBLOCK_START % fs->dev_desc->blksz;
|
||||
|
||||
return ext4fs_devread(sect, off, SUPERBLOCK_SIZE,
|
||||
buffer);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (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>
|
||||
*
|
||||
* ext4ls and ext4load : based on ext2 ls load support in Uboot.
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* based on code from grub2 fs/ext2.c and fs/fshelp.c by
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* ext4write : Based on generic ext4 protocol.
|
||||
*/
|
||||
|
||||
#ifndef __EXT4_COMMON__
|
||||
#define __EXT4_COMMON__
|
||||
#include <ext_common.h>
|
||||
#include <ext4fs.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/errno.h>
|
||||
#if defined(CONFIG_EXT4_WRITE)
|
||||
#include "ext4_journal.h"
|
||||
#include "crc16.h"
|
||||
#endif
|
||||
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
#define RECOVER 1
|
||||
#define SCAN 0
|
||||
|
||||
#define S_IFLNK 0120000 /* symbolic link */
|
||||
#define BLOCK_NO_ONE 1
|
||||
#define SUPERBLOCK_START (2 * 512)
|
||||
#define SUPERBLOCK_SIZE 1024
|
||||
#define F_FILE 1
|
||||
|
||||
static inline void *zalloc(size_t size)
|
||||
{
|
||||
void *p = memalign(ARCH_DMA_MINALIGN, size);
|
||||
memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
int ext4fs_read_inode(struct ext2_data *data, int ino,
|
||||
struct ext2_inode *inode);
|
||||
int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, loff_t len,
|
||||
char *buf, loff_t *actread);
|
||||
int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
|
||||
struct ext2fs_node **foundnode, int expecttype);
|
||||
int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
|
||||
struct ext2fs_node **fnode, int *ftype);
|
||||
|
||||
#if defined(CONFIG_EXT4_WRITE)
|
||||
uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
|
||||
uint16_t ext4fs_checksum_update(unsigned int i);
|
||||
int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags);
|
||||
int ext4fs_update_parent_dentry(char *filename, int file_type);
|
||||
uint32_t ext4fs_get_new_blk_no(void);
|
||||
int ext4fs_get_new_inode_no(void);
|
||||
void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer,
|
||||
int index);
|
||||
int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index);
|
||||
int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index);
|
||||
void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index);
|
||||
int ext4fs_iget(int inode_no, struct ext2_inode *inode);
|
||||
void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
|
||||
unsigned int total_remaining_blocks,
|
||||
unsigned int *total_no_of_block);
|
||||
void put_ext4(uint64_t off, const void *buf, uint32_t size);
|
||||
struct ext2_block_group *ext4fs_get_group_descriptor
|
||||
(const struct ext_filesystem *fs, uint32_t bg_idx);
|
||||
uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,
|
||||
const struct ext_filesystem *fs);
|
||||
uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg,
|
||||
const struct ext_filesystem *fs);
|
||||
uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg,
|
||||
const struct ext_filesystem *fs);
|
||||
uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb);
|
||||
void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks);
|
||||
uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg,
|
||||
const struct ext_filesystem *fs);
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,666 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (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
|
||||
*/
|
||||
|
||||
#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, uint32_t 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, uint32_t blknr)
|
||||
{
|
||||
struct ext_filesystem *fs = get_fs();
|
||||
if (!metadata_buffer) {
|
||||
printf("Invalid input arguments %s\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (dirty_block_ptr[gd_index]->buf)
|
||||
assert(dirty_block_ptr[gd_index]->blknr == blknr);
|
||||
else
|
||||
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(*((__be32 *)(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(*((__be32 *)
|
||||
(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, NULL);
|
||||
ext4fs_devread((lbaint_t)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, NULL);
|
||||
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
|
||||
fs->blksz, metadata_buff);
|
||||
put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)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;
|
||||
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,
|
||||
NULL);
|
||||
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
|
||||
temp_buff);
|
||||
jsb = (struct journal_superblock_t *) temp_buff;
|
||||
|
||||
if (le32_to_cpu(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) {
|
||||
blknr = read_allocated_block(&inode_journal, i, NULL);
|
||||
memset(temp_buff1, '\0', fs->blksz);
|
||||
ext4fs_devread((lbaint_t)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) {
|
||||
uint32_t new_feature_incompat;
|
||||
jsb->s_start = cpu_to_be32(1);
|
||||
jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
|
||||
/* get the superblock */
|
||||
ext4_read_superblock((char *)fs->sb);
|
||||
new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
|
||||
new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
|
||||
fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
|
||||
|
||||
/* Update the super block */
|
||||
put_ext4((uint64_t) (SUPERBLOCK_SIZE),
|
||||
(struct ext2_sblock *)fs->sb,
|
||||
(uint32_t) SUPERBLOCK_SIZE);
|
||||
ext4_read_superblock((char *)fs->sb);
|
||||
|
||||
blknr = read_allocated_block(&inode_journal,
|
||||
EXT2_JOURNAL_SUPERBLOCK, NULL);
|
||||
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)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, NULL);
|
||||
ext4fs_devread((lbaint_t)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) ((uint64_t)blknr * (uint64_t)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, NULL);
|
||||
ext4fs_devread((lbaint_t)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) ((uint64_t)blknr * (uint64_t)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;
|
||||
|
||||
if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
|
||||
return;
|
||||
|
||||
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
|
||||
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
|
||||
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++,
|
||||
NULL);
|
||||
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++, NULL);
|
||||
update_commit_block(blknr);
|
||||
printf("update journal finished\n");
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (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
|
||||
*/
|
||||
|
||||
#ifndef __EXT4_JRNL__
|
||||
#define __EXT4_JRNL__
|
||||
|
||||
#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
|
||||
|
||||
#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 {
|
||||
__be32 h_magic;
|
||||
__be32 h_blocktype;
|
||||
__be32 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 */
|
||||
__be32 s_blocksize; /* journal device blocksize */
|
||||
__be32 s_maxlen; /* total blocks in journal file */
|
||||
__be32 s_first; /* first block of log information */
|
||||
|
||||
/* Dynamic information describing the current state of the log */
|
||||
__be32 s_sequence; /* first commit ID expected in log */
|
||||
__be32 s_start; /* blocknr of start of log */
|
||||
|
||||
/* Error value, as set by journal_abort(). */
|
||||
__be32 s_errno;
|
||||
|
||||
/* Remaining fields are only valid in a version-2 superblock */
|
||||
__be32 s_feature_compat; /* compatible feature set */
|
||||
__be32 s_feature_incompat; /* incompatible feature set */
|
||||
__be32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||||
/* 0x0030 */
|
||||
__u8 s_uuid[16]; /* 128-bit uuid for journal */
|
||||
|
||||
/* 0x0040 */
|
||||
__be32 s_nr_users; /* Nr of filesystems sharing log */
|
||||
|
||||
__be32 s_dynsuper; /* Blocknr of dynamic superblock copy */
|
||||
|
||||
/* 0x0048 */
|
||||
__be32 s_max_transaction; /* Limit of journal blocks per trans. */
|
||||
__be32 s_max_trans_data; /* Limit of data blocks per trans. */
|
||||
|
||||
/* 0x0050 */
|
||||
__be32 s_padding[44];
|
||||
|
||||
/* 0x0100 */
|
||||
__u8 s_users[16 * 48]; /* ids of all fs'es sharing the log */
|
||||
/* 0x0400 */
|
||||
} ;
|
||||
|
||||
struct ext3_journal_block_tag {
|
||||
__be32 block;
|
||||
__be32 flags;
|
||||
};
|
||||
|
||||
struct journal_revoke_header_t {
|
||||
struct journal_header_t r_header;
|
||||
__be32 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, uint32_t blknr);
|
||||
int ext4fs_put_metadata(char *metadata_buffer, uint32_t 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,300 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (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>
|
||||
*
|
||||
* ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
|
||||
* Ext4 read optimization taken from Open-Moko
|
||||
* Qi bootloader
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* based on code from grub2 fs/ext2.c and fs/fshelp.c by
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* ext4write : Based on generic ext4 protocol.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ext_common.h>
|
||||
#include <ext4fs.h>
|
||||
#include "ext4_common.h"
|
||||
#include <div64.h>
|
||||
|
||||
int ext4fs_symlinknest;
|
||||
struct ext_filesystem ext_fs;
|
||||
|
||||
struct ext_filesystem *get_fs(void)
|
||||
{
|
||||
return &ext_fs;
|
||||
}
|
||||
|
||||
void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
|
||||
{
|
||||
if ((node != &ext4fs_root->diropen) && (node != currroot))
|
||||
free(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Taken from openmoko-kernel mailing list: By Andy green
|
||||
* Optimized read file API : collects and defers contiguous sector
|
||||
* reads into one potentially more efficient larger sequential read action
|
||||
*/
|
||||
int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
|
||||
loff_t len, char *buf, loff_t *actread)
|
||||
{
|
||||
struct ext_filesystem *fs = get_fs();
|
||||
int i;
|
||||
lbaint_t blockcnt;
|
||||
int log2blksz = fs->dev_desc->log2blksz;
|
||||
int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
|
||||
int blocksize = (1 << (log2_fs_blocksize + log2blksz));
|
||||
unsigned int filesize = le32_to_cpu(node->inode.size);
|
||||
lbaint_t previous_block_number = -1;
|
||||
lbaint_t delayed_start = 0;
|
||||
lbaint_t delayed_extent = 0;
|
||||
lbaint_t delayed_skipfirst = 0;
|
||||
lbaint_t delayed_next = 0;
|
||||
char *delayed_buf = NULL;
|
||||
char *start_buf = buf;
|
||||
short status;
|
||||
struct ext_block_cache cache;
|
||||
|
||||
ext_cache_init(&cache);
|
||||
|
||||
/* Adjust len so it we can't read past the end of the file. */
|
||||
if (len + pos > filesize)
|
||||
len = (filesize - pos);
|
||||
|
||||
if (blocksize <= 0 || len <= 0) {
|
||||
ext_cache_fini(&cache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
|
||||
|
||||
for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
|
||||
long int blknr;
|
||||
int blockoff = pos - (blocksize * i);
|
||||
int blockend = blocksize;
|
||||
int skipfirst = 0;
|
||||
blknr = read_allocated_block(&node->inode, i, &cache);
|
||||
if (blknr < 0) {
|
||||
ext_cache_fini(&cache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
blknr = blknr << log2_fs_blocksize;
|
||||
|
||||
/* Last block. */
|
||||
if (i == blockcnt - 1) {
|
||||
blockend = (len + pos) - (blocksize * i);
|
||||
|
||||
/* The last portion is exactly blocksize. */
|
||||
if (!blockend)
|
||||
blockend = blocksize;
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == lldiv(pos, blocksize)) {
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
}
|
||||
if (blknr) {
|
||||
int status;
|
||||
|
||||
if (previous_block_number != -1) {
|
||||
if (delayed_next == blknr) {
|
||||
delayed_extent += blockend;
|
||||
delayed_next += blockend >> log2blksz;
|
||||
} else { /* spill */
|
||||
status = ext4fs_devread(delayed_start,
|
||||
delayed_skipfirst,
|
||||
delayed_extent,
|
||||
delayed_buf);
|
||||
if (status == 0) {
|
||||
ext_cache_fini(&cache);
|
||||
return -1;
|
||||
}
|
||||
previous_block_number = blknr;
|
||||
delayed_start = blknr;
|
||||
delayed_extent = blockend;
|
||||
delayed_skipfirst = skipfirst;
|
||||
delayed_buf = buf;
|
||||
delayed_next = blknr +
|
||||
(blockend >> log2blksz);
|
||||
}
|
||||
} else {
|
||||
previous_block_number = blknr;
|
||||
delayed_start = blknr;
|
||||
delayed_extent = blockend;
|
||||
delayed_skipfirst = skipfirst;
|
||||
delayed_buf = buf;
|
||||
delayed_next = blknr +
|
||||
(blockend >> log2blksz);
|
||||
}
|
||||
} else {
|
||||
int n;
|
||||
int n_left;
|
||||
if (previous_block_number != -1) {
|
||||
/* spill */
|
||||
status = ext4fs_devread(delayed_start,
|
||||
delayed_skipfirst,
|
||||
delayed_extent,
|
||||
delayed_buf);
|
||||
if (status == 0) {
|
||||
ext_cache_fini(&cache);
|
||||
return -1;
|
||||
}
|
||||
previous_block_number = -1;
|
||||
}
|
||||
/* Zero no more than `len' bytes. */
|
||||
n = blocksize - skipfirst;
|
||||
n_left = len - ( buf - start_buf );
|
||||
if (n > n_left)
|
||||
n = n_left;
|
||||
memset(buf, 0, n);
|
||||
}
|
||||
buf += blocksize - skipfirst;
|
||||
}
|
||||
if (previous_block_number != -1) {
|
||||
/* spill */
|
||||
status = ext4fs_devread(delayed_start,
|
||||
delayed_skipfirst, delayed_extent,
|
||||
delayed_buf);
|
||||
if (status == 0) {
|
||||
ext_cache_fini(&cache);
|
||||
return -1;
|
||||
}
|
||||
previous_block_number = -1;
|
||||
}
|
||||
|
||||
*actread = len;
|
||||
ext_cache_fini(&cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext4fs_ls(const char *dirname)
|
||||
{
|
||||
struct ext2fs_node *dirnode = NULL;
|
||||
int status;
|
||||
|
||||
if (dirname == NULL)
|
||||
return 0;
|
||||
|
||||
status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
|
||||
FILETYPE_DIRECTORY);
|
||||
if (status != 1) {
|
||||
printf("** Can not find directory. **\n");
|
||||
if (dirnode)
|
||||
ext4fs_free_node(dirnode, &ext4fs_root->diropen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
|
||||
ext4fs_free_node(dirnode, &ext4fs_root->diropen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext4fs_exists(const char *filename)
|
||||
{
|
||||
loff_t file_len;
|
||||
int ret;
|
||||
|
||||
ret = ext4fs_open(filename, &file_len);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
int ext4fs_size(const char *filename, loff_t *size)
|
||||
{
|
||||
return ext4fs_open(filename, size);
|
||||
}
|
||||
|
||||
int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread)
|
||||
{
|
||||
if (ext4fs_root == NULL || ext4fs_file == NULL)
|
||||
return -1;
|
||||
|
||||
return ext4fs_read_file(ext4fs_file, offset, len, buf, actread);
|
||||
}
|
||||
|
||||
int ext4fs_probe(struct blk_desc *fs_dev_desc,
|
||||
disk_partition_t *fs_partition)
|
||||
{
|
||||
ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
|
||||
|
||||
if (!ext4fs_mount(fs_partition->size)) {
|
||||
ext4fs_close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
|
||||
loff_t *len_read)
|
||||
{
|
||||
loff_t file_len;
|
||||
int ret;
|
||||
|
||||
ret = ext4fs_open(filename, &file_len);
|
||||
if (ret < 0) {
|
||||
printf("** File not found %s **\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
len = file_len;
|
||||
|
||||
return ext4fs_read(buf, offset, len, len_read);
|
||||
}
|
||||
|
||||
int ext4fs_uuid(char *uuid_str)
|
||||
{
|
||||
if (ext4fs_root == NULL)
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_LIB_UUID
|
||||
uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id,
|
||||
uuid_str, UUID_STR_FORMAT_STD);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ext_cache_init(struct ext_block_cache *cache)
|
||||
{
|
||||
memset(cache, 0, sizeof(*cache));
|
||||
}
|
||||
|
||||
void ext_cache_fini(struct ext_block_cache *cache)
|
||||
{
|
||||
free(cache->buf);
|
||||
ext_cache_init(cache);
|
||||
}
|
||||
|
||||
int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
|
||||
{
|
||||
/* This could be more lenient, but this is simple and enough for now */
|
||||
if (cache->buf && cache->block == block && cache->size == size)
|
||||
return 1;
|
||||
ext_cache_fini(cache);
|
||||
cache->buf = malloc(size);
|
||||
if (!cache->buf)
|
||||
return 0;
|
||||
if (!ext4fs_devread(block, 0, size, cache->buf)) {
|
||||
ext_cache_fini(cache);
|
||||
return 0;
|
||||
}
|
||||
cache->block = block;
|
||||
cache->size = size;
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user